Login Register

dojox.data.QueryReadStore (1.0)

New in 1.0, QueryReadStore is very similar to ItemReadStore. They both use JSON as their exchange format. The difference is in the way they query data. ItemReadStore makes one fetch from the server, and handles all sorting and filtering in the client. That's fine for hundreds of records, even thousands. But for hundreds of thousands of records or slow Internet connections, that's less feasible.

QueryReadStore makes a request to the server for each sorting or query. This makes it ideal for large datasets with small windows of data, as in dijit.FilteringSelect.

Query Translation

A dojo.data request follows a specific JSON format. As an example, suppose we have a FilteringSelect which looks up states. When the user presses "A", the dojo.data request is:

{
   query: {name: "A*"},
   queryOptions: {ignoreCase: true},
   sort: [{attribute:"name", descending:false}],
   start: 0,
   count: 10
}

Now we want to hand this off to the server. Odds are, your server doesn't recognize incoming JSON, and asking it to do so is too restrictive. Instead, most server queries follow a REST pattern like this:

states.php?q=A*

Fortunately, it's easy to translate between the two. You simply subclass QueryReadStore like this:

dojo.provide("custom.ComboBoxReadStore");

dojo.require("dojox.data.QueryReadStore");

dojo.declare("custom.ComboBoxReadStore", dojox.data.QueryReadStore, {
    fetch:function(request) {
	request.serverQuery = {q:request.query.name};
        // Call superclasses' fetch
	return this.inherited("fetch", arguments);
    }
});

We can place this file into a folder "custom" at the same level as the dojo, dijit and dojox directories of the distribution. (See Creating Your Own Modules for a discussion and alternatives.

You can download QueryReadStore.php below (it's also in /dojox/data/tests/stores/QueryReadStore.php) to run this example on a PHP server. The server portion hands over a portion of the states that fits the query.

Here a full client program. In order for it to work:

  1. Place the following HTML in a file (call it qrs.html) on a web server that has PHP 5.2 or greater.
  2. Create a folder called "custom" in the same directory as qrs.html
  3. Create a ComboBoxReadStore.js file inside the "custom" folder and place the custom.ComboBoxReadStore contents listed previously in this page in that file.
  4. Save the QueryReadStore.php_.txt file linked below the following HTML code as QueryReadStore.php and save it in the same directory as qrs.html

The directory structure should look like this when you are done:

--qrs.html
--QueryReadStore.php
--custom
----ComboBoxReadStore.js
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
            "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>QueryReadStore Demo</title>
    <style type="text/css">
        @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
        @import "http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.css"
    </style>
    <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js"
            djConfig="baseUrl: './', modulePaths: {custom: 'custom'}, parseOnLoad: true">
</script>
    <script type="text/javascript">
       dojo.require("dojo.parser");
       dojo.require("dojox.data.QueryReadStore");
       dojo.require("dijit.form.FilteringSelect");
       dojo.require("custom.ComboBoxReadStore");
    </script>
</head>
<body class="tundra">
    <div dojoType="custom.ComboBoxReadStore" jsId="store"
         url="QueryReadStore.php"
         requestMethod="get">

    </div>
    State: <input id="fs" dojoType="dijit.form.FilteringSelect" store="store" pageSize="5" />
</body></html>
AttachmentSize
QueryReadStore.php_.txt5.18 KB

help

I was not able to run the example....
I checked the example the list is not populating...
what should i do? I tried with 1.0 and 1.0.1 both QueryReadStore.html example..... page is dispalying but not showing data?

Example broken plus check your PHP version

First of all, the example seems to be broken as "custom.ComboBoxReadStore" doesn't exist in content delivery network. However, it's easy to fix because the definition can be grabbed from a test page, where ComboBox uses a customized QueryReadStore. Just drop this fixed version on the same directory as that test page on your box:

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>QueryReadStore Demo</title>
        <style type="text/css">
            @import "../../../dojo/resources/dojo.css";
            @import "../../../dijit/themes/tundra/tundra.css";
        </style>
        <script type="text/javascript" src="../../../dojo/dojo.js" djConfig="isDebug: true, parseOnLoad: true"></script>
        <script type="text/javascript">
            dojo.require("dijit.form.ComboBox");
            dojo.require("dijit.form.FilteringSelect");
            dojo.require("dojox.data.QueryReadStore");

            dojo.provide("ComboBoxReadStore");
            dojo.declare(
                "ComboBoxReadStore",
                dojox.data.QueryReadStore,
                {
                    fetch:function(request) {
                        request.serverQuery = {q:request.query.name};
                        return this.inherited("fetch", arguments);
                    }
                }
            );
        </script>
    </head>
    <body class="tundra">
        <div dojoType="ComboBoxReadStore" jsId="store"
             url="stores/QueryReadStore.php"
             requestMethod="get">

        </div>
        State: <input id="fs" dojoType="dijit.form.FilteringSelect" store="store" pageSize="5" />
    </body>
</html>

Example won't work with old PHP versions, so you might also want to check you PHP version. PHP page uses json_encode function that has been in PHP only for a year - since version 5.2.0. Simple way to check PHP version is with a PHP page that contains only phpinfo function:

<?
    phpinfo();
?>

I just fixed the example,

I just fixed the example, and provided more information on how to set it up.

thanks

I was using PHP 4.0... i got it working now... :D

Does someone have a jsp example

I am trying to use Dojo for a new project at work, and PHP is a non-starter, since we are using jsp for the rest of the product.

Can someone point to working examples of Dojo 1.x.x with a jsp back end?

I would love to see a working dojox.data.QueryReadStore jsp example.

how about this as a java example of QueryReadStore...

Didn't do the pagination and there's likely some libaries you could import to do the json but this will work. Just save this as QueryReadStore.jsp, and then go into QueryReadStore.html and change the extension from php to .jsp.

<%@page import="java.util.*" %>
<%
HashMap qrs = new HashMap();

HashMap Alabama = new HashMap();
qrs.put("Alabama", Alabama);
Alabama.put("name", "Alabama");
Alabama.put("label", "Alabama");
Alabama.put("abbreviation", "AL");

HashMap Alaska = new HashMap();
qrs.put("Alaska", Alaska);
Alaska.put("name", "Alaska");
Alaska.put("label", "Alaska");
Alaska.put("abbreviation", "AK");

String q = request.getParameter("q"); ;
System.out.println("q=" + q);

if (q != null && q.endsWith("*")) {
	q = q.substring(0,q.lastIndexOf("*"));
	System.out.println("q=" + q);
}

ArrayList ret = new ArrayList();		

Set qrsKeys = qrs.keySet();
Iterator Iter = qrsKeys.iterator();
while (q != null && Iter.hasNext()) {
        String key = (String)(Iter.next());
        System.out.println("KEY=" + key + " - " + qrs.get(key));
        if (0 == key.indexOf(q)){
        	ret.add(qrs.get(key));
        }
}
/*
		 Handle paging, if given.
		if (array_key_exists("start", $_REQUEST)) {
			$ret = array_slice($ret, $_REQUEST['start']);
		}
		if (array_key_exists("count", $_REQUEST)) {
			$ret = array_slice($ret, 0, $_REQUEST['count']);
		}
 */
%>
{
"items":
[
<%
int size = ret.size();
Iter = ret.iterator();
while (Iter.hasNext()) {
	HashMap item = (HashMap)Iter.next();
	int index = ret.indexOf(item);
	String comma = null;
	if (size > 1 && ((size-1) !=index)) {comma=",";} else {comma="";}
%>
 { identifier:"<%=item.get("name")%>", name:"<%=item.get("name")%>", label:"<%=item.get("label")%>", abbreviation:"<%=item.get("abbreviation")%>"}<%=comma%>
<% } %>
]
}

QueryReadStore with form data

Is there a easy way to parse form-data into the query?
I have a searchformular with more than one searchparameter.
How can I get a datasore?
Thanks for help!

xhr-Request in QueryReadStore

The xhr-Request in the QueryReadStore is done with
var xhrHandler = xhrFunc({url:this.url, handleAs:"json-comment-optional", content:serverQuery});

I have some problems with the "json-comment-optional" ... wouldn't it be possible to define the handleAs - Parameter when I define the store??

Thanks!

i also have a problem with the xhr-Request...

because i need to define sync:true

actually, it's even necessary for this PHP example, because as result of each server request the text in the FilteringSelect is being replaced, and if the user types too fast (actually while the server request is on the go), it messes up the text in the FilteringSelect. i would call this a bug.
my solution is to make the xhr calls synchronized (and not asynchronized).

regards,
ewilde.

Dojo bug tracking and forums

@zet4080, ewilde: Please, file bug reports and enhancement ideas to Dojo Trac (Log in: guest/guest).

@martin.eller, pcarmichael: Support questions to Dojox forums.

QueryReadStore not fit for Tree widget

See recent Trac issue and the discussion: QueryReadStore can't be used to provide data for a Tree widget.

Example using paging?

Does anyone have an example like the one above supporting paging on the server side?

The PHP script of the example above does interpret the request parameters "start" and "count", but these parameters not sent by the client. I tried to extend the example above:
- added the "pageSize"-attribute to the FilteringSelect
- modified the fetch-function by adding request.start and request.count to the server query

When I try to load the second page of a list of returned values, the PHP script replies these items but they are not displayed in the FilteringSelect. Instead, the drop down window is being closed and the "invalid value" message is being displayed.

What else has to be done?

Best regards,
Ralph

QueryReadStore & TypeMap?

Hello,

I'm trying to switch from an itemFileReadStore to a queryReadStore to feed an editable grid. I have a date-field, which I want to edit with the DateTextBox-editor. With the itemFileReadStore I used the typeMap to convert the date to a date-object. The typeMap does not seem to work with the queryReadStore. Is there any way to accomplish this? Any workarounds or alternatives I can use?

About paging in Grid controls using this QueryReadStore

I think someone should fix the docs to reflect the fact that if one wishes to use paging in Grid controls using QueryReadStore the "numRows" field must be present in the result the server sends in, e.g.:

{ "identifier" : "id", "numRows" : 30, "items" : [ { "id" : 10, "login" : "user", "email" : "user@..." }, ... ] }

Otherwise the grid model will think that the portion of the data it requested (which is usually one page of data) is all the data the servers has for the query and so no automatic data fetching will be done with virtual scrolling.

Spent more that 4 hours trying to figure that out. :( Applies at least to Dojo 1.2.

See QueryReadStore Grid demo illustrates changes for details.

It is incomprehensible that

It is incomprehensible that this would not be (better?) documented. I also pissed away hours of my life before finding this comment - thank you! This was also necessary for the Dojo 1.2.3+ DataGrid (as opposed to deprecated Grid). Setting the "rowsPerPage" property on the grid itself did not do the trick (although it really seems like it is supposed to).

Documentation Nightmare Continues

You can use the "get" method on QueryReadStore to flatten out the request parameters. There's no need to convert the JSON sting. Moreover, if the odds of a server accepting the JSON string are so low, and it's too restrictive to ask for that, why was it done? Finally, why not just document ALL of the attributes of that JSON string (I have zero problem dealing with it, provided it's documented) or should we simply rely on some casual comments in an example? Again, the documentation is utterly pathetic.