Announcement

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

    Double fetchData callback on RestDataSource with setCacheData

    Using 25 March 2011 SC8 Power Nightly, executing the following code results in the fetchData callback being called twice. Each time it has the correct data, but the transactionNumbers are sequential.

    Subsequent calls of goFetch() only fire the callback once, as I'd expect.

    I thought at first it might have been my sub-classing and over-writing of transformRequest and transformResponse (even though I was still calling the Super(...) versions). However, I boiled it down to this test case and I hope that the fix will fix my more complex usage.

    The same thing seems to happen if criteria is null, although it is correctly filtering the data.

    Code:
    isc.RestDataSource.create({
    	ID:"testDS",
    	dataFormat:"json",
    	dataURL:"/rest",    // Real, although irrelevant to this example
    	fields:[
    		{
    			name:"id",
    			type:"integer",
    			primaryKey:true
    		},
    		{
    			name:"name"
    		}
    	]
    });
    
    testDS.setCacheAllData(true);
    testDS.setCacheData([{id:1,name:"first"},{id:2,name:"second"}]);
    
    function goFetch() {
    	var criteria = {id:1};
    	testDS.fetchData(criteria,function(dsResponse,data){
    		console.warn("fetchData transactionNum:" + dsResponse.transactionNum + " length:" + data.length);
    	});
    }
    
    goFetch();

    #2
    It's your cacheAllData setting, which always causes an initial fetch of all data into ds.cacheData - your actual fetch request is deferred until after the automatic cacheAllData fetch executes, then it and all subsequent fetches are made against cacheData.

    You can see this by just switching cacheAllData off.

    Comment


      #3
      Thanks for the reply. I was rather hoping that the intended behaviour of setCacheData would automatically make that initial fetch, leading to a more consistent paradigm of the fetchData callback only ever getting called once.

      I guess either I can make that initial call manually:

      Code:
      testDS.setCacheAllData(true);
      testDS.setCacheData([{id:1,name:"first"},{id:2,name:"second"}]);
      testDS.fetchData();
      
      ...
      Or do what I've been doing and use a flag:

      Code:
      function goFetch() {
      	var doneFetchBehaviour = false;
      	var criteria = {id:1};
      	testDS.fetchData(criteria,function(dsResponse,data){
      		if (doneFetchBehaviour) return;
      		doneFetchBehaviour = true;
      		console.warn("fetchData transactionNum:" + dsResponse.transactionNum + " length:" + data.length);
      	});
      }
      
      goFetch();

      Comment


        #4
        It's not clear why you would be interested in both setting cacheAllData: true *and* providing cacheData.

        If the DS has cacheData because it's a test and there's no real back-end, switch off cacheAllData - if the back-end exists, get rid of cacheData, it will be filled automatically.

        Comment


          #5
          Understandable. I didn't state that this was a simplified example of what I was playing around with.

          ***
          At the end of the day, all I'm really trying to achieve is an elegant way to send deltas from my server to my client DataSources and maintain SmartClient's automatic updating of DataBound components.
          ***

          My environment runs without a SmartClient server. It has both REST interfaces that can be explicitly connected to, as well as RPC calls that are made that can return deltas.

          Across multiple DataSources, sometimes I wanted to update just part of the cache and sometimes I wanted to wipe the cache and replace it all.

          I have been playing around with updateCaches to address the former and trying to sequentially call setCacheAllData(false) then setCacheAllData(true) to address the latter case.

          I'm trying to stay as close to the SmartClient DataSource paradigm as possible.

          I have been trying to extend the RestDataSource so that in non-caching mode it can query from the REST interface and in caching mode it can be updated by the deltas from the RPC calls.

          I achieved a working POC having a layered approach with a RestDataSource underneath a ResultSet underneath a CustomDataSource. The RPC updates could be done by modifying the ResultSet whilst in non-cached mode the CustomDataSource would pass the requests straight on to the RestDataSource. But it would be neater if I could use updateCaches, setCacheAllData and setCacheData to acheive the same effect on a single DataSource.

          The multiple firing of the fetchData callback was one of the headaches I encountered.

          The other headache that I haven't yet boiled down to a standalone testcase seems to be that when the RestDataSource goes into cacheAllData it seems to replace transformRequest with custom code. I see that the original transformRequest function is stored, but when you manually take the DataSource out of cacheAllData mode, the transformRequest seemingly doesn't get restored.

          This means that in my case, where transformRequest was adding parameters to the request necessary for correct data retrieval, those parameters are not being added, so I have to take the DataSource out of cache mode and then restore the original transformRequest function manually.

          Comment


            #6
            Just a quick update to let you know we believe the double-callback issue should now be resolved. Please try the latest nightly build and let us know if you continue to see it.

            Comment


              #7
              Thank you, that has solved the problem with a few code tweaks:

              I had overwritten transformRepsonse (dsResponse, dsRequest, data) on RestDataSource and it referenced data.response.data. I am now finding that I am getting instances where data.response is null. If you'd like me to delve deeper, I will, otherwise I shall just check data.response !== undefined before doing the rest of my code.

              It has introduced a bug...whenever I context click on a ListGrid (not a row, but in the listgrid_body) I get the following error three times:

              CXT4:WARN:ListGrid:isc_ListGrid_0:getCellRecord called with bad rowNum: null

              The CXTx number varies with each click but is the same for each set of three errors.

              Code:
              isc.Menu.create({
              ID:'cm',
              data:[{title:"test",click:""}]
              })
              
              isc.ListGrid.create({
              autoDraw:true,
              contextMenu:cm
              })

              Comment


                #8
                A second follow-up based on the code before:

                Code:
                testDS.setCacheAllData(true);
                testDS.setCacheData([{id:1,name:"first"},{id:2,name:"second"}]);
                
                // BUG?
                testDS.hasAllData(); // reports false
                hasAllData does not report true having setCacheData. I would expect that to report true?

                Comment


                  #9
                  Finally, FYI, I've also been using testDS.cacheResultSet in order to synchronously retrieve objects when I know that whole set is loaded.

                  Calling setCacheData doesn't now seem to generate that cacheResultSet, but sequently calling .invalidateCache and then .fetchData does make cacheResultSet reappear.

                  I know it's not documented usage, if you have an alternative proposal I'm all ears.

                  Comment

                  Working...
                  X