Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    ListGrid invalidateCache() not working for DataSource with no identifier

    SmartGWT 2.3 pro
    GWT 2.0.3
    Firefox 3.6
    IDE: SpringSource Tool Suite 2.5.0.M3

    I've got a strange problem with a ListGrid and a dataSource with objects with no unique identifier.

    The use-case is as follows: before a form is submitted, I need to check for warnings on the form data. These aren't strictly validation errors, instead they're warnings that the user needs to review manually. If the warnings aren't an issue, he can submit the form anyway.

    Long story short - I have a number of datasources that create ValidationWarning objects. These validationWarnings contain information about the warning and are show in a number of listgrids (one per type). However, the validation warnings do not have a unique ID (since they aren't persistent objects; they're temporary objects that are generated on demand when the form is submitted).

    The first time the form is submitted, everything works fine - the warnings are generated correctly and displayed in their respective listgrids. However, lets say a user decides that the warnings are valid and he modifies the form before resubmitting the data. At this point, I need to check for warnings again.

    I'm calling listGrid.invalidateCaches() (to ensure that the listGrid will ask the server for new results). However despite this call, listGrid.willFetchData() returns false; which means I have no way of forcing an update from the server. I've used listGrid.invalidateCaches() before and I never had issues with it in the past; but all those times I was working with persistent objects which had valid unique identifiers, so I suspect that this is the source of the problem. Do I need to somehow generate a unique ID for my temporary warning objects to get around this?

    Example of data source file:

    Code:
    <DataSource
    	ID="didAccountValidation"
    	serverType="generic">
    	<fields>
    		<field name="did" type="text" title="DID"/>
    		<field name="message" type="text" title="Message"/>
    		<field name="assignedDate" type="datetime" title="Assigned Date"/>
    		<field name="previousAccount" type="text" title="Previous Account"/>
    	</fields>
    	 <serverObject lookupStyle="spring" bean="didAccountValidationDS"/>
    	 
    </DataSource>
    As you can see, there's no unique identifier.

    Relevant client code:

    Code:
    public void checkWarnings(Integer[] didIds, Integer accountId, Integer csaId, WarningsCheckedCallback callback)
    		{
    			Log.debug(this.getClass().getName() + " checking for warnings");
    			reset();
    			callerCallback = callback;
    			
    			Criteria accountCriteria = new Criteria();
    			accountCriteria.addCriteria(DIDField.DID_ID_LIST.getName(), didIds);
    			accountCriteria.addCriteria(DIDField.ACCOUNT.getName(), accountId);
    			
    			Criteria csaCriteria = new Criteria();
    			csaCriteria.addCriteria(DIDField.DID_ID_LIST.getName(), didIds);
    			csaCriteria.addCriteria(DIDField.CSA.getName(), csaId);
    			
    			Log.debug(this.getClass().getName() + " starting RPC queue");
    			RPCManager.startQueue();
    				accountWarningGrid.invalidateCache();
    				if(accountWarningGrid.willFetchData(accountCriteria)){
    					
    					Log.debug(accountWarningGrid.getClass().getName() + " will fetch server data.");
    					
    				}
    				else
    				{
    					Log.debug(accountWarningGrid.getClass().getName() + " will not fetch server data.");
    				}
    				accountWarningGrid.fetchData(accountCriteria, new DSCallback()
    				{
    					@Override
    					public void execute(DSResponse response, Object rawData,
    							DSRequest request) {
    						accountRet=true;
    						Record[] results = response.getData();
    						if(results.length > 0)
    						{
    							Log.debug(this.getClass().getName() + " found " + results.length + " account warnings.");
    							foundWarnings=true;
    							accountLayout.setVisibility(Visibility.INHERIT);
    							
    						}
    						else
    						{
    							Log.debug(this.getClass().getName() + " found no account warnings.");
    						}
    						checkProceed();
    					}
    						
    				});
    				
    				csaWarningGrid.invalidateCache();
    				csaWarningGrid.fetchData(csaCriteria,new DSCallback()
    				{
    					@Override
    					public void execute(DSResponse response, Object rawData,
    							DSRequest request) {
    						csaRet=true;
    						Record[] results = response.getData();
    						if(results.length > 0)
    						{
    							Log.debug(this.getClass().getName() + " found " + results.length + " csa warnings.");
    							foundWarnings=true;
    							csaLayout.setVisibility(Visibility.INHERIT);
    							
    						}
    						else
    						{
    							Log.debug(this.getClass().getName() + " found no csa warnings.");
    						}
    						checkProceed();
    					}
    						
    				});
    			RPCManager.sendQueue();
    			Log.debug(this.getClass().getName() + " rpc queue sent.");
    		}

    #2
    Forgot to mention one more important aspect:

    on subsequent data fetches, I can see the listGrid does actually contact the server and the datasource returns data, but for some reason the callback never executes. Very weird.

    Comment


      #3
      Little unclear on your overall use case and whether the DataSource shown is supposed to be the main data or the warnings, but:

      1) invalidateCache() will automatically initiate the same fetch that fetches the current data, *without* the need to call fetchData() yourself - that's why you can get willFetchData() false in this circumstance

      2) to wipe out current data and initiate your own manual fetch (if you for some reason need to), using setData() to set the data to an empty array, then call fetchData() yourself.

      Comment


        #4
        Aah, I didn't realize invalidateCache() triggered a fetch. That totally makes sense, I see now why it wasn't working; thanks!

        In terms of the use case... I basically have a form; and the data in the form can trigger both validation errors and validation warnings.

        Validation errors are "blocking errors", i.e. you cannot submit the form unless you fix these errors. I'm handling this through the normal SmartGWT mechanisms; i.e. setting validation rules in the .ds.xml file, and on the server side using dsRequest.getDataSource().valdate() and setting the ErrorReport on the dsResponse.

        Validation warnings are "non-blocking" errors, i.e. they need to be reviewed by the user, but the user can chose to still go ahead and submit the form if he decides the warnings can be ignored.

        I experimented with having the dataSource check for validation warnings and pass these back to the client as a property on the response (dsResponse.setProperty("warningReport", warningReport)) but it caused all kinds of problems - I would have to set the status of the response to something other than "STATUS_SUCCESS", the client would expect the errorReport to be there as well (even though there might not be any errors per so) and it was just a huge mess.

        Instead, what I ended up implementing was this... the form submit is a two-step process now. Prior to submitting, I first check for warnings (basically by doing a fetch on a warningDataSource). If there are no warnings, or the user decides the warnings can be ignored, I then submit the form (which may have errors in which case the user would get notified of the blocking errors).

        Only unfortunate aspect with this is that if a form has both warnings and errors, they are not shown together; instead you see them sequentially; but I can live with that for now.

        Comment


          #5
          It does make sense to send informational messages separately for now. But note that there's a future enhancement planned (no ETA) to allow you to flag a message as informational and therefore not blocking for a save.

          Comment

          Working...
          X