Checking for updated fields

Checking for updated fields

Postby PeterHarmes » Thu Jun 18, 2009 1:39 pm

Hi,

I'm looking to put a message in my app to check if the user has updated any fields in a dialog (these can be gets/radio/checkboxes etc) and then if the user tries to quit, display a message saying "Data not saved, are you sure you wish to quit?"

Is there a global setting that i can put into my dialog that can get updated if any updates occur, or do i have to put an ON CHANGE onto each of my controls?

Any ideas will be appreciated

Pete
PeterHarmes
 
Posts: 363
Joined: Wed Feb 15, 2006 2:06 pm
Location: Oxford, England

Re: Checking for updated fields

Postby Rick Lipkin » Thu Jun 18, 2009 1:54 pm

Peter

I don't have a direct answer for you .. but consider a couple options ..

1) In a network environment you could have issues with two people having buffered up the same record .. very typical in a small office situation .. if one person saves the record and the other saves on top of that same record .. you now have a delima. In this case I use a 'signature' numeric field that gets incremented once each time the record is saved. If workstation A saves a record the signature field in the table gets incremented .. the trick is before workstation B saves the same record .. you go out once again to the table and verify the signature field buffered on workstation B is the same as what the table says .. if not .. then workstation A has slipped behind workstation B and changed the information and workstation B should not be allowed to save if the signature field is not the same.

2) It may seem redundant .. but many times I will thru up a MsgYesNo() and even if nothing has changed and ask the user to Save or Cancel during the end of an Edit session .. let the user confirm if they have changed a record.

Just my 2 cents..

Rick Lipkin
User avatar
Rick Lipkin
 
Posts: 2658
Joined: Fri Oct 07, 2005 1:50 pm
Location: Columbia, South Carolina USA

Re: Checking for updated fields

Postby PeterHarmes » Thu Jun 18, 2009 2:03 pm

Thanks for your reply - i've always said to our customers that i could change my app to work as you suggested in point 2, so i'm probably going to go with that. Just wondered if there was an "hidden" automated procedure somewhere :wink:

Regards,

Pete
PeterHarmes
 
Posts: 363
Joined: Wed Feb 15, 2006 2:06 pm
Location: Oxford, England

Re: Checking for updated fields

Postby Gale FORd » Thu Jun 18, 2009 4:58 pm

This bit of code might point you in the right direction. This code would run after the ON INIT for the dialog. It does not take into account if you already have bChange block already assigned. You might have to add other types of controls also. It also does not do folder within folder.

Code: Select all  Expand view

   FOR nI := 1 TO LEN( oDlg:aControls )
       IF oDlg:aControls[ nI ]:ClassName() = "TGET" .or. oDlg:aControls[ nI ]:ClassName() = "TCHECKBOX"
         if oDlg:aControls[ nI ]:bChange == nil
           // Here is where you can assign variable or use function to turn on save checking.
           // There is another place further down.
           oDlg:aControls[ nI ]:bChange = { || ::togglesaveon() }
         endif
       ENDIF
       IF oDlg:aControls[ nI ]:ClassName() = "TFOLDER"
         FOR nIFold := 1 TO LEN( oDlg:aControls[ nI ]:aDialogs )
            FOR nFoldI := 1 TO LEN( oDlg:aControls[ nI ]:aDialogs[ nIFold ]:aControls )
               IF oDlg:aControls[ nI ]:aDialogs[ nIFold ]:aControls[ nFoldI ]:ClassName() = "TGET" .or. ;
                     oDlg:aControls[ nI ]:aDialogs[ nIFold ]:aControls[ nFoldI ]:ClassName() = "TCHECKBOX"
                 if oDlg:aControls[ nI ]:aDialogs[ nIFold ]:aControls[ nFoldI ]:bChange == nil
                   // Here is where you can assign variable or use function to turn on save checking.
                   oDlg:aControls[ nI ]:aDialogs[ nIFold ]:aControls[ nFoldI ]:bChange = { || ::togglesaveon() }
                 endif
               ENDIF
            NEXT
         NEXT
      ENDIF
   NEXT
 
Gale FORd
 
Posts: 663
Joined: Mon Dec 05, 2005 11:22 pm
Location: Houston

Re: Checking for updated fields

Postby James Bott » Thu Jun 18, 2009 5:05 pm

Pete,

Personally, I am against such a design. The software should assume that the user wants to do what they said they did. I hate confirmations! Consider that 99 times out of a hundred, the answer will be the same. The user will be so used to getting rid of the annoying message by answering in a certain matter that it will be so automatic, that the one time in a hundred that they really needed to answer it differently, it will be too late. The confirmation message will have already been dismissed by the user in the usual way.

So confirmations don't work and they just create more work for the user.

If you really wish to do this, however, there is a modified() method of the TDatabase class that will tell you if the data has been changed. The database class holds the data in an array, the user can then edit it and the modified() method will check the array against the original record. Of course, you must change your code to use a database object in order to use the modified() method.

Regards,
James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Checking for updated fields

Postby Otto » Thu Jun 18, 2009 6:59 pm

Hello James,
would you be so kind to explain the modified() method a bit.
Is modified asking if you want save.
It would also be a good step to have a undo build in.
Thanks in advance.
Best regards,
Otto
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
User avatar
Otto
 
Posts: 6272
Joined: Fri Oct 07, 2005 7:07 pm

Re: Checking for updated fields

Postby James Bott » Thu Jun 18, 2009 9:27 pm

Otto,

>would you be so kind to explain the modified() method a bit.
>Is modified asking if you want save.

No, calling Modified() simply checks the buffer agianst the record and returns .t. if they are different.

>It would also be a good step to have a undo build in.

Yes, Undo is much better than a confirmation. In order to create a undo you will have to save the previous data somewhere, then provide an Undo button or menu choice.

James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Re: Checking for updated fields

Postby nageswaragunupudi » Fri Jun 19, 2009 5:20 am

I fully agree with Mr. James on user psychology.

About checking whether any data is modified by a dialog, in a network environment, we need to consider two kinds of changes.

1) If our user has modified the data by editing the dialog.
2) If any other user changed the data, after our user read the data.

I normally use a class derived from TDataBase. I maintain two buffers, aOriginal and aBuffer. Comparing aOriginal and aBuffer tells me if our user has changed the data. If changed it needs to be saved. This comparison does not require a diskread, which is costly in network environments. ( This has another advantage. User might have edited a few Gets and again re-edited to the original values. In such a case we need not save the record ). Also maintaining two buffers aOriginal and aBuffer enables 'UNDO' without another diskread.

By comparing aOriginal with data in the table ( similar to modified method of TDataBase ) we know if some other user changed the data already. ( Comparing Version fields if maintained may appear to be faster, but our normal RDDs anyway read the entire record ).

Mr James' TData class stood the test of time. I do not know how TData class helps the programmer in this regard. Would Mr James or any user of TData like to enlighten us on this aspect of TData ?

It may be noted that ADO recordset also maintains these values to enable the programmer to do these kinds of comparisons. Every field has OriginalValue, UnderlyingValue and Value. Comparing Value with OriginalValue tells us if our user has modified data. Resync method to update only underlyingvalues reads the current data into this value. Comparing Value with UnderlyingValues tells is if other user modified the data. ( Using Version fields is faster while dealing with RDMSs )

In case, I am not using any classes, I normally have all the values in an array at the outset and compare with edited values in the dialog.

Incidentally I would like to share my views on oGet:Changed. This such a handy feature that we are tempted to use this value to determine if our user has changed the data. But this can be dangerously misleading. Every time a Get gets focus, the oGet;Changed is reset to .f. The user might have edited the data once and might have gone back to the same get and did not modify this time. oGet:changed shows .f.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10482
Joined: Sun Nov 19, 2006 5:22 am
Location: India

Re: Checking for updated fields

Postby Otto » Fri Jun 19, 2009 5:37 am

Hello Mr. NagesWaraRao,

would you please show how you compare to arrays.
I always use a FOR-NEXT statement. Is there a better way?
Thanks in advance
And best regards,
Otto
********************************************************************
mod harbour - Vamos a la conquista de la Web
modharbour.org
https://www.facebook.com/groups/modharbour.club
********************************************************************
User avatar
Otto
 
Posts: 6272
Joined: Fri Oct 07, 2005 7:07 pm

Re: Checking for updated fields

Postby driessen » Fri Jun 19, 2009 12:43 pm

I have solved this problem many years ago, even already in my Clipper times.

I always use this kind of code :

Code: Select all  Expand view
LOCAL cField1,cField2,cField2
LOCAL cUpdate := .F.
.................
cFIELD1 := DBF1->FIELD1
cFIELD2 := DBF1->FIELD2
cFIELD3 := DBF1->FIELD3
.................
DEFINE DIALOG ........
REDEFINE GET cFIELD1 ID 101 OF oDlg
REDEFINE GET cFIELD2 ID 102 OF oDlg
REDEFINE GET cFIELD3 ID 103 OF oDlg
ACTIVATE DIALOG ........
.................
IF !(cFIELD1 = DBF1->FIELD1 .AND. ;
     cFIELD2 = DBF1->FIELD2 .AND. ;
     cFIELD3 = DBF1->FIELD3)
    cUPDATED := .T.
ENDIF

IF cUPDATED
   DBF1->FIELD1 := cFIELD1
   DBF1->FIELD2 := cFIELD2
   DBF1->FIELD3 := cFIELD3
ENDIF


You could make a cUPDATED for each field if you want to know which fields are updated.

Good luck.
Regards,

Michel D.
Genk (Belgium)
_____________________________________________________________________________________________
I use : FiveWin for (x)Harbour v. 24.07 - Harbour 3.2.0 (February 2024) - xHarbour Builder (January 2020) - Bcc773
User avatar
driessen
 
Posts: 1422
Joined: Mon Oct 10, 2005 11:26 am
Location: Genk, Belgium

Re: Checking for updated fields

Postby nageswaragunupudi » Fri Jun 19, 2009 4:17 pm

Mr Otto

>
I always use a FOR-NEXT statement. Is there a better way?
>

I also do the same thing. I think this is the best way I can think of.
Regards

G. N. Rao.
Hyderabad, India
User avatar
nageswaragunupudi
 
Posts: 10482
Joined: Sun Nov 19, 2006 5:22 am
Location: India


Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: Google [Bot] and 35 guests