Login Register

Refresh grid when underlying data on server changes

I have a grid like described in the tutorial ( simple grid) that grabs some data from the server and displays it in the grid.
Now I want to place a button on the same page that when clicked the data in the grid gets updated.
So if the the date on ther serverside is changed (e.g. the *.txt file) this is being visible in the grid somehow.
This seems to be a very simple problem but I couldn't manage to find out how it works.
Thanks.

here is what I did:

I had to build a new store, build a new model, and then call

grid.setModel(newmodel);
grid.update();

There are plenty of problems with doing it that way, but it works.

-Jon

Try QueryReadStore

dojo.data.ItemFileReadStore and dojo.data.ItemFileWriteStore don't have built-in functionality for refreshing their data from server - that's why you need to re-create them. You can choose to extend these to add that functionality or you can try a store implementation that's meant for loading data from server repeatedly - dojox.data.QueryReadStore. No need to create a new store or a model. To get started, have a look at this sample I wrote a week ago: Grid Server Side Sorting and Paging with DojoData and QueryReadStore

excellent

thanks for the pointer Maine!

I've got the queries happening, and the model store is changing as the server data changes, but the grid isn't updating it's rows to reflect the models changes. I think I'm missing a step here somewhere. I thought the notification api would handle that part?

Thanks for your help, it's gotten me much much closer with much less work...:)

[EDIT]

Found it! Instead of calling the model.store.fetch(), I'm calling model.requestRows(), when I want to update the grid, and it all works beautifully!

Thanks again for the pointer Maine!

-Jon

Full sample?

Any possibility of having an example of this (with enough source to help us newbies) posted?

Thanks in advance,

Shawn

Update the Full grid on the

Update the Full grid on the FLY:
retrieve the JSON data "value" from server and extract
var exValue = eval("(" + value + ")");

"model1" is the model you attached with ur grod
model1.setData(exValue);

model1.observer(modelObservers1); // "modelObservers1" is the observer attached to ur model, this is optional

"grid1" is the grid instance
grid1.setModel(model1);

thats all :-)

update the full grid on the fly; having problems

I'm trying your approach. In the original ItemFileReadStore, I reference a URL for a servlet. For example, I send back the following data.

{"timestamp":1193692111, "items":[{"login":"someLogin","lastName":"Robertson", "firstName":"David", "organization": "LBNL", "phone": "999-9999"}]}

When I want to do a refresh, I do an xhrPost, contact the same servlet and get back the same information for testing. In the load function, I have the following.

var userGrid = dijit.byId("userGrid");
var userModel = userGrid.model;
userModel.setData(responseObject.items);
userGrid.setModel(userModel);

When I do this, I still have the table, but now every cell has an "..." in it. I like the simplicity of your approach, and still being a Dojo newbie, would have to do some research to see how to recreate the store and model programmatically to replace the original ones. The functionality of ItemFileReadStore is fine except for being able to do an update, and I don't need the complexity of QueryReadStore.

Do you see anything obvious that I am doing wrong?

(EDIT) For this purpose, should I be sending something like [["someLogin", "Robertson", "David", "LBNL", "999-9999"]] instead? I noticed something like that usage in dojox/grid/tests/support/test_data.js, except it looks like there is something additional necessary by the additions to the array after the data initialization.
Like I said, I'm a newbie and am looking for something simple.

Updating store

So, you're using ItemFileReadStore? Do you get it working in the first place, i.e. when you're loading the data by passing the url? How does that data look like?

When you want to update the grid and you're using a store, it's the store you should update - not the model. The model and the grid update themselves automatically to reflect changes in the store. But (as the name indicates) you can't update ItemFileReadStore - try ItemFileWriteStore, for example. The correct data format for a store has an items array, as there is in your first snippet (but try adding an identifier property, see other forum discussions). The second data sample you're asking about is for a certain model that doesn't use a store.

no callback on setModel()

So, I am doing what you guys are doing above, with the grid.setModel(model) but there's no callback. The data fetching is async, so it works and gets the new data, however, if I want to put a default sort on the grid, or hide the progress icon and show the grid, or whatever, I don't have a callback in which to do that. I imagine that the grid.update() isn't necessary, because anything right after setModel() is run immediately, even before the data has returned.

model.store.fetch() has the onComplete callback, but I've found that it doesn't update the grid successfully in 1.0.2 release or in trunk as of a few days ago. setModel() is the only thing I've found to work.

:(

ideas?

Actually the approach you

Actually the approach you are trying is simple and correct. If you are getting "..." in your cells that means you need you do some correction in the data format you get from servlet.
Let me explain you somthing Grid is compatible for TWO Dimational or Tabular Data structure.
so if you have somthing like this in grid
111 Name1 Age1
222 Name2 Age2

In that case your JSON value from the server should be like this
[["111","Name1","Age1"],["222","Name2","Age2"],["333","Name3","Age3"]] Array contains Array

I am sure you wont forget to eplod JSON using "eval" methos, before setting data in model ie :
var exValue = eval("(" + value + ")");
model.setData(exValue);

It also has a Callback facility if you have set observer to your model.

Thanks
Manjul

wondering how model without a store works

Thank you for your help. Is there a store associated with this model in any way? I changed the way my data is formatted to what you suggested, but am now getting an error saying this.store.fetch is not a function when I do a setData on a refresh. I make a call to the same servlet referenced below when the tab is clicked on the first time, and the servlet is called the first time. At that point I don't get an error, but I only get the headings displayed.

The following is the code for the content pane.

<head>
<script type="text/javascript">
    var userView = {
      cells: [[
         {name: 'Login', field: "login", width: "15em"},
         {name: 'Last Name', field: "lastName", width: "11em"},
         {name: 'First Name', field: "firstName", width: "10em"},
         {name: 'Organization', field: "organization", width: "22em"},
         {name: 'Phone', field: "phone", width: "11em"}
      ]]
    };
    var userLayout = [ userView ];
</script>
</head>

<body class="tundra">

<form id="userListForm" method="POST">

Click on the user's last name to view detailed user information.

<table>
<tr>
  <td>User List</td>
  <td>
  <button dojoType="dijit.form.Button" id="userList">
     Refresh
     <script type="dojo/method" event="onClick">
        dojo.xhrPost({
          url: 'servlet/UserList',
          handleAs: "json-comment-filtered",
          load: oscars.Form.handleReply,
          error: oscars.Form.handleError,
          form: dojo.byId("userListForm")
        });
    </script>
  </button>

  </td>
</tr>
</table>

</form>

<div id="userModel" dojoType="dojox.grid.data.DojoData" jsId="userModel"
     rowsPerPage="20">

</div>
<div id="userGrid" dojoType="dojox.Grid" model="userModel"
    structure="userLayout">

</div>

</body>

EDIT2:  I tried removing the userModel creation in the content pane page and not setting the model for userGrid.  I then seem to get a default model for the grid.  After doing a setData, I get the correct number of rows with getRowCount, and refresh doesn't generate an error, but I see no data in the cells.  I can print out model.data, and correctly get a row with model.getRow(index).  The other thing I notice is that upon each refresh, the vertical area for the grid expands even though the row count remains the same, and the alternately colored rows remain the same in number.

<code>

how to recreate ItemFileReadStore and DojoData

I've given up temporarily on trying to use a model without a store, and recreating ItemFileReadStore and DojoData, as was suggested above. I want to do all sorting on the client without a trip to the server, and the list of data returned will be limited by other form parameters (so I don't want to use QueryReadStore, especially with the luck I'm having on trying simpler approaches).

I can get it to generate a get, but nothing displays. I'm not sure newModel.setData(newStore) is the right thing to do, but I couldn't set newStore with the "store" attribute of DojoData (always got null for the store from the model afterwards). Following is the code:

var userGrid = dijit.byId("userGrid");
        var newStore = new dojo.data.ItemFileReadStore(
                          {url: 'servlet/UserList'});
        var newModel = new dojox.grid.data.DojoData(
                          { rowsPerPage: "20",
                            query: "{ login: '*' }" });
        newModel.setData(newStore);
        userGrid.setModel(newModel);
        userGrid.update();

I couldn't tell if you

I couldn't tell if you didn't want to do it this way or not, but the below link seems to work for all:

http://dojotoolkit.org/forum/dojox-dojox/dojox-grid-support/update-grid-...

your update code works

Works for me too. Thanks!

This is working. But how we

This is working. But how we can destroy the newly created store and model?

newModel.destroy() is not working!

storeless model again

I was so pleased that the update fix for ItemFileReadStore worked for one of my forms that I forgot why I needed the storeless model. I have another form where the data returned depends on a number of form parameters, in which case the storeless model would be ideal. Since the storeless model works for the above poster, my only guess is that my use of the default model for the grid is causing problems. Declaring the model in the page as I do above gives a null store error when I try to do setData, however.

I haven't worked with a

I haven't worked with a "storeless" grid (does one exist?). Nor the QueryReadStore, but it sounds nice. But, for FilteringSelects, grids, etc., I've been successfully using the ItemFileXXXXStore (more recently for the Grid, AndOrWriteStore). One of the FilteringSelects needs to display a different set of choices based on which "category" is selected elsewhere. I use the ItemFileReadStore and replace FS's store. Works great and is fast. I just call xhrGet, IIRC, and pass the appropriate params to the servlet to get back the subset of data the user should see, then replace the FS's store.

For the Grid, I use the AndOrWriteStore (a complex query clone of ItemFileWriteStore). As the user requests rows be added/removed/changed, I xhrGet the servlet with the requested/affected values (which also makes the changes to the server's database), and then either delete the row from the grid, add the row to the grid, or update the values in the row, based on what came back from the server. For the Grid, I don't really replace the store, since, once the dataset is retrieved, the adds/changes/deletes are a small portion of the dataset. I do use, via user-selectable radio buttons, the Grid's query capability to filter the data displayed in the Grid, e.g., query="id:1* && dept:Sales && !title:VP".

Grid data sources

A "storeless" model sure does exist... The grid enables different abstraction levels:

  1. VirtualGrid: no model, no store — user implements get-method to feed data
  2. Grid with default model (table) (see data): model, no store — input two-dimensional arrays
  3. Grid with custom model: model, no store — input anything (tabular)
  4. Grid with DojoData model: model, store — model connects to a store that takes input depending on the store type (json, csv, xml)

Excellent! Thanks, Maine.

Excellent! Thanks, Maine. Frank.

AndOrWriteStore

I need to check out this AndOrWriteStore - sounds interesting. Google brought me to a Trac page about AndOrWriteStore. Have you been planning to write more about it?

I think it is scheduled for

I think it is scheduled for dojo 1.1, subject to jaredj making sure all is OK. The only change from ItemFileXXXXStore is the query section. I was holding off posting anything until it is a go/no-go. Do you think a forum post now is appropriate? Or wait a bit until jaredj looks at it? The first two files attached to the ticket just need to be dropped into the dojotoolkit/dojox/data directory with the other stores. Then just set your query (and reset as needed for filtering) using somewhat natural syntax, followed by grid.model.refresh().

Example queries supported:

Programmatic:
    query[:|=]"NOT id:23* AND (type:'test*' OR dept:'bob') && !filed:true"

  Widget markup (where json object may be required for query):
    query[:|=]{complexQuery:"NOT id:23* AND (type:'test*' OR dept:'bob') && !filed:true"}

Available logical operators (case insensitive):

, NOT AND OR ( ) ! && ||  Note: "," included for legacy queries (translated to AND).

Also, simple queries, as typically used with the other stores, are supported.

Store query interfaces

New Dojo features are definitely worth of discussing at the forums. In particular the different approaches that people are taking with the grid and the components related to it. However, I understand that you've held off from posting before an initial review. But how about opening a thread for suggestions concerning store query interfaces... Anyway, there will be also this another new interesting store query type introduced with jsonPathStore (see also: working with jsonPathStore and Tree).

Yes, Dustin did a great job

Yes, Dustin did a great job with jsonPathStore. I was going to have a syntax learning curve... :). I think it is probably more powerful query syntax than most.

There was another post back in the fall from someone who created a SQL-like query syntax, which looked good, also, but I don't think it was submitted for inclusion in dojo, not sure.

Override setData

Check out my post about improving DojoData model: Server Side Sorting and Paging with DojoData and QueryReadStore. You need to override setData method so that it doesn't reset your store.

found my problem with a storeless model

Well, I feel dumb, but am posting this in case someone else makes the same mistake. In the view, I left in the fields attribute of the cells from when I was using a store. I took those out, and things work fine. Apologies for the wasted bandwidth.

storeless data model in Grid 1.2

Is there a way anymore to populate a grid analogous to the following simple manner:

var resvGrid = dijit.byId("resvGrid");
var model = resvGrid.model;

// resvData is a list of lists from the server
oscars.Reservations.convertReservationTimes(responseObject.resvData);
// is there some way to get the data into the grid now that there is no model
model.setData(responseObject.resvData);
resvGrid.update();

My entire application is built on doing things this way. I've looked at the source, including _Grid.js, and the tests, and don't see the way to do it.

Use a datastore for your data structure

Yes, you can use your data structure for the list of items in a datastore. Instead of a list of lists, though, you should use a list of objects.

Check out any of the tests at http://download.dojotoolkit.org/current-stable/dojo-release-1.2.3/dojox/grid/tests/, in particular http://download.dojotoolkit.org/current-stable/dojo-release-1.2.3/dojox/grid/tests/support/test_data.js, which has the code for creating the data store from an array of items. Here's a snippet from that file, with your "resvData" inserted:

	// data object defines the identifier, label, and the list of items
	var data = {
		identifier: 'id',
		label: 'id',
		items: responseObject.resvData
	};

	var store = new dojo.data.ItemFileWriteStore({data: data});

	// resvGrid should be a dojox.grid.DataGrid
	resvGrid.setStore(store);

Cheers,
~Michael

Close and reload the datastore

I've seen this question all over the forums, so I'm posting this answer in a few different places. I had this same question and couldn't find an easy solution right away. After playing with it for a bit, I finally remembered the dojo.data api call for the "close()" method.

Using a Dojo 1.2 DataGrid widget that is loaded via a URL with ItemFile****Store (Read/Write), the Grid can be refreshed (using the same URL) with a few simple commands, without having to replace the datastore.

First, create the Datastore with the "clearOnClose" parameter set to true:

	var myDatastore = new dojo.data.ItemFileReadStore( { url: "myUrl.json", clearOnClose: true  } );

Then, create your DataGrid (e.g. "myGrid") with whatever setup you need. When you want to reload the data, have your button (or whatever) execute the following:

	// Close the datastore and tell the DataGrid to refresh.
	myGrid.store.close();
	myGrid.sort();

The sort function internally forces a refresh, and that's what will cause the grid to fetch the data from the datastore again. Since the datastore has been closed (and cleared because of the "clearOnClose" property), the data will be requested from the URL again.

This isn't a complete example. The details of creating the DataGrid widget are left out, since there are many ways to do it, depending on the situation.

Cheers,
~Michael

I just stumbled on this

I just stumbled on this yesterday, and have a similar solution, but I'm not keen on using _functions.
In my case, I want to change the underlying url for the store, then refresh the grid and have the
store fetch the new data. I also set the clearOnClose flag, but then:

myDatastore._jsonFileUrl = "myNewUrl.json";
  myDatastore.close();
  myGrid._refresh();

This works with the 1.2.3 DataGrid, and the ItemFileWriteStore. But it seems to me, there ought
to be public methods for changing the url on the store, and for refreshing the grid. (IIRC, there was a
public refresh() method for a previous grid.)

Bob Goldstein

_refresh() vs. sort()

Yeah, I was looking for a public refresh function, also. That's when I came across sort(), which calls _refresh() internally.

But if you're changing the URL for the ItemFile****Store (Read/Write), then I think your only options at this point are to either modify _jsonFileUrl directlly (which may not work in future releases, since it's not a public API property), or just construct a new datastore. Constructing a new datastore isn't really any extra expense, since you're not reusing any of the resources that the original datastore had. In fact, from a theoretical point of view, one could argue that data coming from different URLs really are meant to be separate datastores.

Cheers,
~Michael.

1.2 Grid _refresh() without "Loading..."

Has anyone found a best practice/method for updating/refreshing a grid without getting the "Loading..." screen? I'm currently polling a cgi script that outputs changing JSON data every 2seconds (I eventually want to migrate to a comet type solution). What I'm trying to get is the look and feel as when I delete a row with: store.deleteItem(selectedItem); where the row is immediately deleted. Is there a practice to get the grid to update instantly, much like on an item deletion?

I'm sorry if this has already been asked, but I've been searching documents and forums for the last couple mornings. Thank you.

QueryReadStore and refreshing the data.

To help others who might come across these issues, here's what I've found about forcing a QueryReadStore to re-request the data from the store. This is with version 1.3.0. QueryReadStore, keeps a copy of the last request it has sent to the server. It compares the new request to the old request to determine if it can use a cached copy of the data. This is great if you want caching. However if your application is aware that data on the server has changed, there are only two choices that I've found to work for forcing a refresh.

1. create a complete new QueryReadStore object and tell your grid, tree, etc. to use it.

I think this is considered the preferred way. However, if you are creating your store in markup as many examples show, you need to change over to creating it programmatically.

2. set storename._lastServerRequest to null.

_lastServerRequest has the a copy of the request parameters as a json object. It is a private member, is likely to change and therefore shouldn't be counted on. However if you are creating your store from markup it works.

QueryReadStore's implementation of close is a no-op. I think that is wrong. If it's not going to do anything I think it should throw an unimplemented exception, rather than just silently doing nothing.

What I've done is to override the close method and make it set _lastServerRequest to null.

Once this is done a call to gridname.sort() will cause a fetch and a grid refesh.

Hope this helps someone,
--Rob