Clicking label makes Dirty property True

0

0 1

I am trying to add an undo button to my form. If the record is dirty,
I'd like the user to be prompted to confirm he wants to undo the
record. If it's not dirty, just ignore.

The problem is that simply clicking on the "Undo" label makes the
dirty property = True. (Same thing happens if I use a command button,
instead of a label.)

What's causing this? I do have some AfterUpdate and AfterInsert code,
but I wouldn't think that would be triggered by clicking on a label
(or command button).

Any ideas?
 
M

Marshall Barton

I am trying to add an undo button to my form. If the record is dirty,
I'd like the user to be prompted to confirm he wants to undo the
record. If it's not dirty, just ignore.

The problem is that simply clicking on the "Undo" label makes the
dirty property = True. (Same thing happens if I use a command button,
instead of a label.)

What's causing this? I do have some AfterUpdate and AfterInsert code,
but I wouldn't think that would be triggered by clicking on a label
(or command button).

Either your form is corrupted and logical processing went
south or you have some sode in the lable control's Click
event that dirties the record.

If the label is attached to a text box, then clicking on the
label gives the focus to the taxt box and it's GotFocus and
Enter event procedures will be executed. If that's what
you have, check those events for code that sets a bound
control's value.

OTOH, maybe you have not proved that the label click caused
the record to be dirty and something else, such as the
form's Current event, is what's doing it.
 
0

0 1

I think I narrowed it down to the call that opens the form, rather
than any code in the form itself. If I comment out a specific line,
Dirty stays false when I click on the label. Otherwise, any click
event on the form makes Dirty = True.

Below is the code that opens the form. It's behind a command button on
a continuous subform, fsubEvents. The problem is being caused by the
third to last line:

Forms(stDocName).Controls("PatientID").Value = Me.Parent!PatientID

Commenting it out fixes the issue. I just don't see why. The basic
user flow is: User clicks on a record in a continuous subform,
fsubEvents. The main form is frmPatients. The form that opens depends
on the form that's called (based on the record in fsubPatientEvents).

###

Private Sub cmdViewEvent_Click()

Dim stDocName As String
Dim stLinkCriteria As String
Dim stQuery As String
Dim rstTemp As New ADODB.Recordset

stQuery = "SELECT EventFrm, EventID "
stQuery = stQuery & "FROM PatientEvent INNER JOIN TypesEvent ON
PatientEvent.EventTypeID = TypesEvent.EventTypeID "
stQuery = stQuery & "Where PatientEvent.PEventID=" &
Me.PEventID
rstTemp.Open stQuery, CurrentProject.Connection, adOpenKeyset,
adLockOptimistic

stDocName = rstTemp("EventFrm")
stLinkCriteria = "[EventID]=" & rstTemp![EventID]

DoCmd.openForm stDocName, , , stLinkCriteria

' this line makes Dirty = True for all click events on the form
that opened
Forms(stDocName).Controls("PatientID").Value = Me.Parent!
PatientID
rstTemp.Close
Exit Sub

End Sub

###
 
D

David-W-Fenton

m:
' this line makes Dirty = True for all click events on the
form
that opened
Forms(stDocName).Controls("PatientID").Value = Me.Parent!
PatientID

Yes, of course it dirties the form whose name is stored in the
variable stDocName. Is it possible the recordset is looking up the
wrong record and assigning the wrong form name to that variable?

Looks like very strange code to me. I don't see why you couldn't
have a saved QueryDef that's the same as the recordset without a
WHERE clause, and then use a DLookup() to get the value you need.
Even if I were going to do it with a recordset, I'd never use ADO
for something like this -- it's simply completely unnecessary to use
anything other than DAO.
 
0

0 1

Yes, of course it dirties the form whose name is stored in the
variable stDocName.

I see why it would dirty it upon opening, but once the form is open,
this code is over isn't it? How does it permanently create a scenario
where any click even on the opened form dirties the record?
Is it possible the recordset is looking up the
wrong record and assigning the wrong form name to that variable?

The correct record and correct form seem to always be assigned.
Looks like very strange code to me. I don't see why you couldn't
have a saved QueryDef that's the same as the recordset without a
WHERE clause, and then use a DLookup() to get the value you need.
Even if I were going to do it with a recordset, I'd never use ADO
for something like this -- it's simply completely unnecessary to use
anything other than DAO.

I completely agree. I inherited much of this code, and because there
was so much of it I've tried to work with it rather than rewrite. But
so much of if seems unnecessarily complicated and, for lack of a
better word, long-winded.
 
B

Bob Quintal

m:
I see why it would dirty it upon opening, but once the form is
open, this code is over isn't it? How does it permanently create a
scenario where any click even on the opened form dirties the
record?

Changing the data in the table or query inside a form makes it dirty.

A form stays dirty until the record that is dirtying it is either saved
or cancelled.

In your example the form is dirtied by the calling code as soon as it
is opened. It will stay dirty until explicitly saved, implicitly saved
(by changing record or closing) or undone.

Access does not check that the form is dirty when it is opened, it only
checks when the form is touched by the user.
 
M

Marshall Barton

I see why it would dirty it upon opening, but once the form is open,
this code is over isn't it? How does it permanently create a scenario
where any click even on the opened form dirties the record?


The correct record and correct form seem to always be assigned.


I completely agree. I inherited much of this code, and because there
was so much of it I've tried to work with it rather than rewrite. But
so much of if seems unnecessarily complicated and, for lack of a
better word, long-winded.


Well, that explains it. Now the question is why di you have
that line of code? And, if a record already exists, doesn't
it already have its PatientID set?
I seems like you may want to set the PatientID for new
records (events?), but there is no reason to set it when the
form is opened.

To arrange for new records to have the PatientID set
automatically, get rid of the offending line of code and
change the open form code to use the OpanArgs arguments:

DoCmd.OpenForm stDocName, , , stLinkCriteria, _
OpenArgs:= Me.Parent!PatientID

And add code like this to all the event forms' Load event
procedure:
If Not IsNull(Me.OpenArgs) Then
Me.PatientID.DefaultValue = """" & Me.OpenArgs & """"
End If
 
D

David-W-Fenton

m:
I see why it would dirty it upon opening, but once the form is
open, this code is over isn't it? How does it permanently create a
scenario where any click even on the opened form dirties the
record?

Are there subforms involved?
 
M

Mike Painter

I missed most of this but is done after the form opens to "undirty" the
record?

The normal action of clicking on a label selects the entire field. Once
selected any action in that field would dity the form, so what happens after
that click?
 
0

0 1

I see why it would dirty it upon opening, but once the form is
Changing the data in the table or query inside a form makes it dirty.

A form stays dirty until the record that is dirtying it is either saved
or cancelled.

In your example the form is dirtied by the calling code as soon as it
is opened. It will stay dirty until explicitly saved, implicitly saved
(by changing record or closing) or undone.
Access does not check that the form is dirty when it is opened, it only
checks when the form is touched by the user.

I added to the OnLoad event of the form a line to set Dirty = False,
and using Debug.Print Me.Dirty (right after the Me.Dirty = False line)
confirmed that Dirty was indeed set to False after the form opened.
But then I clicked on a command button - a command button that didn't
even have any event or code associated with it, other then
"Debug.Print Me.Dirty" in the Click Event - and watched the Immediate
Window: Dirty turned True. This is what puzzled me. Clicking on a
command button with no "real" code behind doesn't change the data in
any way. I do have code that affects the recordset in the form's
Before Insert and After Insert events, but my understanding is these
only trigger when you insert a character into a record.

As for the resolution, see my reply to Marshall Barton's post about
the open args event, which solved the issue.
 
0

0 1

Well, that explains it.  Now the question is why di you have
that line of code?  And, if a record already exists, doesn't
it already have its PatientID set?
I seems like you may want to set the PatientID for new
records (events?), but there is no reason to set it when the
form is opened.

Very true. PatientID needs to be set for new records, but not for
existing ones (in which the PatientID is already there). Not sure why
the original programmer programmed it that way, but I suspect it had
something to do with the weird way he was populating two tables.
Imagine a many-to-many, but the junction table and one of the tables
on the one side weren't linked. This was the part of the database
model.

When the user opened the form (which was based on the table on the one
side of the m:m), and entered his first character, the AfterInsert
code would open a new ADOB.Recordset and populate the junction table
with the appropriate child fields for both sides of the m:m. Doing
this (I guess) created a value for the junction table's autonumber
(and PK) field. This value was then copied to the form's recordset
(Me.Recordset).
To arrange for new records to have the PatientID set
automatically, get rid of the offending line of code and
change the open form code to use the OpanArgs arguments:

    DoCmd.OpenForm stDocName, , , stLinkCriteria, _
                             OpenArgs:= Me.Parent!PatientID

And add code like this to all the event forms' Load event
procedure:
   If Not IsNull(Me.OpenArgs) Then
      Me.PatientID.DefaultValue = """" & Me.OpenArgs & """"
   End If

This did the trick, and the phenomenon of the Dirty becoming True
simply by clicking a command button (with no real code behind it) has
gone away. I guess I don't see how setting the PatientID via OpenArgs
is any different than setting it via a line like
Forms(stDocName).Controls("PatientID").Value = Me.Parent! (I don't
understand Open Args all that well.)

It seems the above code says:

If Open Args has a value (which it will every time, right? In this
case, it's always set to Me.Parent!PatientID), then make the default
value of PatientID = to the value of OpenArgs (which is always
Me.Parent!PatientID). How is this different than:

Forms(stDocName).Controls("PatientID").Value = Me.Parent!

It seems perhaps the outcome is the same, but the means of getting
there is different.

Thanks for your help.
 
D

David-W-Fenton

m:
I do have code that affects the recordset in the form's
Before Insert and After Insert events, but my understanding is
these only trigger when you insert a character into a record.

I would never edit the form's recordset. You should edit the data
loaded in the form's edit buffer directly, instead. I know you
resolved your problem elsewhere, but editing the recordset is
precisely the kind of thing that can cause confusing results, and
really should be avoided, as far as I'm concerned. It's a very
un-Access way of doing things.
 
D

David-W-Fenton

m:
If Open Args has a value (which it will every time, right? In this
case, it's always set to Me.Parent!PatientID), then make the
default value of PatientID = to the value of OpenArgs (which is
always Me.Parent!PatientID). How is this different than:

Forms(stDocName).Controls("PatientID").Value = Me.Parent!

It seems perhaps the outcome is the same, but the means of getting
there is different.

It's not the same at all. The default value of a control is only
relevant when a new record is inserted. Now, if the form is opened
in Data Entry mode (or its default is set to Data Entry), then just
opening the form is going to land you on a new blank record, so that
might be why it's getting dirtied. Maybe.

It all sounds like a really bad design to me, created by somebody
who really has no clue about the Access way of doing things
(subforms would be the normal way to do something like this).
 
M

Marshall Barton

Very true. PatientID needs to be set for new records, but not for
existing ones (in which the PatientID is already there). Not sure why
the original programmer programmed it that way, but I suspect it had
something to do with the weird way he was populating two tables.
Imagine a many-to-many, but the junction table and one of the tables
on the one side weren't linked. This was the part of the database
model.

When the user opened the form (which was based on the table on the one
side of the m:m), and entered his first character, the AfterInsert
code would open a new ADOB.Recordset and populate the junction table
with the appropriate child fields for both sides of the m:m. Doing
this (I guess) created a value for the junction table's autonumber
(and PK) field. This value was then copied to the form's recordset
(Me.Recordset).


This did the trick, and the phenomenon of the Dirty becoming True
simply by clicking a command button (with no real code behind it) has
gone away. I guess I don't see how setting the PatientID via OpenArgs
is any different than setting it via a line like
Forms(stDocName).Controls("PatientID").Value = Me.Parent! (I don't
understand Open Args all that well.)

It seems the above code says:

If Open Args has a value (which it will every time, right? In this
case, it's always set to Me.Parent!PatientID), then make the default
value of PatientID = to the value of OpenArgs (which is always
Me.Parent!PatientID). How is this different than:

Forms(stDocName).Controls("PatientID").Value = Me.Parent!

It seems perhaps the outcome is the same, but the means of getting
there is different.

The outcome is not the same in all but the one case where
you immediately create a new record. Setting the field's
Value will change the value in an existing record and dirty
the record.

The DefaultValue property just sits there waiting for a
character to be entered in a NEW record. At that time the
record becomes dirty and applying the DefaultValue to the
field does not change the dirty status because it was
already dirty.

Note that setting a field's value for a new record prior to
a user entering a character does dirty the new record and
the Esc key must be used to avoid (twice) to avoid saving
the record that the user decided not to create. OTOH, while
you can see the default value is a field, until a character
is entered, the record is not dirty and you can navigate to
some other record without saving or undoing anything.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top