jqGrid toolbar search with autocomplete using json data - json

I found the very nice demo by Oleg (http://www.ok-soft-gmbh.com/jqGrid/FillToolbarSearchFilter.htm) which shows a "jqGrid toolbar search with autocomplete using local data" but have trouble to get this to work for json via ajax. Is there a good reason why the autocomplete feature won't work - even if I force the grid to be local after loading?
$(document).ready(function() {
var mygrid = $("#mylist"),
mygetUniqueNames = function(columnName) {
var texts = mygrid.jqGrid('getCol',columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i=0;i<textsLength;i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
return uniqueTexts;
};
mygrid.jqGrid({
url:'autocompleteTest.php',
datatype: "json",
colNames:['name', 'City','stateCd'],
colModel:[
{name:'name',index:'name',width:225, search: true},
{name:'City',index:'City',width:125},
{name:'stateCd',index:'stateCd',width:75},
],
rowNum: 100,
loadonce : true,
sortname: 'name',
sortorder: 'desc',
sortable: true,
viewrecords: true,
rownumbers: true,
sortorder: "desc",
ignoreCase: true,
pager: '#mypager',
height: "auto",
caption: "How to use filterToolbar better with data from server"
}).jqGrid('navGrid','#mypager',
{edit:false, add:false, del:false, search:false, refresh:false});
mygrid.jqGrid('setColProp', 'name',
{
searchoptions: {
sopt:['bw'],
dataInit: function(elem) {
$(elem).autocomplete({
source:mygetUniqueNames('name'),
delay:0,
minLength:0
});
}
}
});
mygrid.jqGrid('filterToolbar',
{stringResult:true, searchOnEnter:true, defaultSearch:"bw"});
});

It is difficult to provide an example in case of the usage of remote source parameter of jQuery UI Autocomplete. The main problem is that your question is about jqGrid which is pure JavaScript solution. If we would discuss the server part of tha solution we would have too options. Many users uses different languages: Java, C#, VB, PHP and so on. For example I personally prefer C#. Then we would have to choose the technology which we use: ASP.NET MVC, WCF, ASPX web service and so on. For example I would choose WCF. Then we should define the database access technology, for example, Entity Framework, LINQ to SQL, SqlDataReader, SqlDataAdapter and so on. Let us I would choose Entity Framework and would provide you the corresponding code example, but it would help you not really if you use for example PHP and MySQL.
So I just describe which interface should have the server for the remote source parameter of jQuery UI Autocomplete without any code.
You should replace in my example the source parameter to your server url like following:
dataInit: function(elem) {
$(elem).autocomplete({
source:'yourSearchUrl.php',
minLength:2
});
}
If the user types two characters (the value can be changed by minLength option), for example 'ab' then the autocomplete will make HTTP GET request with the parameter term=ab:
yourSearchUrl.php?term=ab
your server should answer with the JSON data in the same format as for the local source. I used the string array format in my previous example. Another supported format is array of objects with label/value/both properties like
[
{
"id": "Dromas ardeola",
"label": "Crab-Plover",
"value": "Crab-Plover"
},
{
"id": "Larus sabini",
"label": "Sabine`s Gull",
"value": "Sabine`s Gull"
},
{
"id": "Vanellus gregarius",
"label": "Sociable Lapwing",
"value": "Sociable Lapwing"
},
{
"id": "Oenanthe isabellina",
"label": "Isabelline Wheatear",
"value": "Isabelline Wheatear"
}
]
read the documentation for more information.
If you need to implement more complex scenario and send some additional data to the server or convert the server response in any way you can use custom source callback function. In the case you should use source: function(request, response) {/*your implementation*/}, where the request would be an object having term property (request.term). Inside of your implementation your should make ajax request to the server manually. The response would be callback function which you should call after your custom ajax request will be finished (inside of success event handler). The response function should be called with the parameter which should be array in the same format as mygetUniqueNames returns. I recommend you to examine the source code from the jQuery Autocomplete demo.
To de able to provide unique data from one column of tabele you should just use SELECT DISTINCT SQL statement which are supported in the most databases.
I hope that my description would help you.
UPDATED: If you have the local source the solution you could find in my old answer which you already use. What you just need to do is to call the filterToolbar after the source array are filled. Because you load the data from the server your should move the call of filterToolbar inside of loadComplete. You use loadonce:true jqGrid option which switch the datatype from 'json' to 'local' after the first data loading. So you can include in the loadComplete event handler of your grid the code like the following:
var grid = $('#list');
grid({
url:'autocompleteTest.php',
datatype: 'json',
loadonce: true,
// ... other parameters
loadComplete: function(data) {
if (grid.getGridParam('datatype') === 'json') {
// build the set 'source' parameter of the autocomplete
grid.jqGrid('setColProp', 'name', {
searchoptions: {
sopt:['bw'],
dataInit: function(elem) {
$(elem).autocomplete({
source:mygetUniqueNames('name'),
delay:0,
minLength:0
});
}
}
});
mygrid.jqGrid('filterToolbar',
{stringResult:true,searchOnEnter:true,
defaultSearch:"bw"});
}
}
});
If you will need to reload the data from the server (change the datatype to 'json' and call grid.trigger('reloadGrid')) you will have to change the code above so that you first destroy the autocomplete widget with $('#gs_name').autocomplete('destroy') and then create it one more time with the same code like inside of dataInit.

Related

Sending complex JSON with fetch, save, and delete on a model or collection

We have an internal API that was specifically built to be used with a new piece of software I'm building that runs on Backbone. The API has a single URL and takes JSON as input to determine what it needs to return. It essentially allows me to build custom queries with JSON that return exactly what I'm looking for.
Thing is this JSON can get pretty verbose and is often 3–4 levels deep, but sometimes may just be a few lines and just 1 level deep.
First question first: How do I send a string of JSON along with the ID when I do a fetch()? Do I have to set these parameters as the model or collection's defaults?
Here is an example of a really simple string to get a specific user's info
{
"which" : "object",
"object" : {
"type" : "customer",
"place" : "store",
"customerID" : "14"
}
}
As others have suggested it will likely be challenging to work with SOAP, but it shouldn't be impossible. Backbone models and collections communicate with the server through the sync operation; you should be able to customize that. I think something along these lines might get the ball rolling (for models):
Backbone.SoapyModel = Backbone.Model.extend({
sync: function(method, model, options) {
// force POST for all SOAP calls
method = 'create';
options = _.extend(options, {
// Setting the data property will send the model's state
// to the server. Add whatever complexity is needed here:
data: JSON.stringify({
"which" : "object",
"object" : model.toJSON()
}),
// Set the request's content type
contentType: 'application/json'
});
// Defer the rest to Backbone
return Backbone.sync.apply(this, [method, model, options]);
}
});
var SoapyModelImpl = Backbone.SoapyModel.extend({
url: '/test'
});
var soapTest = new SoapyModelImpl({
id: 42,
name: 'bob',
address: '12345 W Street Dr',
phone: '867 5304'
});
soapTest.fetch();

Have jqGrid display raw json in a column

I have a use case where I would like to have jqGrid display some raw JSON for a particular column. I have the following JSON being sent from the server:
{"items":[
{
"code":"ABC123",
"description":"",
"custom_data":{"items":[
{"prop1":"val1","prop2":"val2"},
{"prop1":"val3","prop2":"val4"}
]}
},
{"code":"ABC124","description":"","custom_data":[]},
...,
]}
and a jqGrid configuration like so:
{
url:'/api/somewhere',
datatype: "json",
jsonReader : {
root:"items",
repeatitems: false,
id: "code"
},
colNames:['Code',
'Description',
'Data',],
colModel:[
{
name:'code', index:'code', width:100, hidden:false,
edittype:'text',
editable: true,
editrules:{required:true, edithidden:true},
editoptions: {readonly:false}
},
{
name:'description',
index:'description',
width:250,
editable:true,
edittype:'text',
editrules:{required:true}
},
{
name:'custom_data',
index:'custom_data',
width:100,
hidden:true,
sortable:false,
editable:true,
edittype:'text',
editrules:{required:false, edithidden:true}
},
],
...,
The grid displays OK, but the custom_data column is displayed as [object Object]. What I need is for it to display the raw JSON string I have tried calling JSON.stringify on the custom_data object for each row object using the loadComplete event, but that didn't work. I need to do some data manipulation after the GET anyway, as I want to delete null values from the custom_data object.
My users are comfortable reading and editing raw JSON, so I also need the add/edit form to accept raw JSON which will then get POSTed.
I'm not sure if I'm simply using the wrong event to convert the object back to a string, or if there is something else going on.
What you can do is usage of custom formatter for "custom_data" column
formatter: function (cellValue, options, rawData) {
return cellValue.items ? JSON.stringify(cellValue.items) : "";
}
I changed in the demo hidden property for "custom_data" column to true to see the data
Additionally you can consider to use userdata instead of hidden column to save additional custom data. I recommend you to read the answer additionally which shows not only how to use userdata, but additionally how to show additional data in form subgrid.

Solr live search using ExtJs4

i'm using solr+haystack(django plugin) on the backend and the search is working fine;
While Django(and Haystack) with its templates is doing everything for me(I mean its pretty simple to configure and use), ExtJS4 is a little more complex;
The question is how to use Solr using ExtJS4?
An example is very much appreciated;
Thanks for any help and sorry for my English;
As ExtJS4 is a MVC framework, the solution is done like MVC;
The controller/Search.js
Ext.define('yourapp.controller.Search',{
extend:'Ext.app.Controller',
stores:[
'Searches'
],
views:[
'search.Search',
'search.SearchList'
],
models:[
'Search'
],
init:function(){
this.control({
"search":{
'keyup':this.search,
},
});
},
search:function(inputedTxt, e, eOpts){
this.getSearchesStore().load({
//When sending a request, q will rely to request.POST['q'] on server-side;
//inputedTxt.getValue() -- a value, entered in textfield (or whatever)
params:{
q:inputedTxt.getValue()
},
callback:function(result){
if(result[0]){
//do something with the result
//i'd been creating a window with a grid inside. "Grid"'s view is written below.
}
}
}
});
The models/Search.js
Ext.define('yourapp.model.Search',{
extend:'Ext.data.Model',
fields:[
{name:'name', type:'string'}
]
});
The store/Searches.js
Ext.define('yourapp.store.Searches',{
extend:'Ext.data.Store',
storeId: "searchStore",
model:'yourapp.model.Search',
autoLoad: false,
proxy:{
type:'ajax',
// server-side url
url: '/searchlist/',
actionMethods:{create: "POST", read: "POST", update: "POST", destroy: "POST"},
reader:{
type:'json',
root:'searches'
}
}
});
The view/search/Search.js
//a Text field to input text;
Ext.define('yourapp.view.search.Search',{
extend:'Ext.form.field.Text',
alias: 'widget.search',
id: "searchView",
enableKeyEvents: true,
initComponent:function(){
this.callParent(arguments);
}
});
The view/search/SearchList.js
//a view for a result
Ext.define('yourapp.view.search.SearchList',{
extend: 'Ext.grid.Panel',
alias:'widget.searchlist',
title: 'search result',
store: 'Searches',
columns:[
{
header:'Name',
dataIndex:'name',
flex:1
}
]
});
Somewhere in the view/Viewport.js xtype: 'search', should be inserted for a text field to be displayed.
That's all for a ExtJS4 part.
On server-side -- Django:
'haystack' and Solr should be installed and configured (by 'configured' i mean: search should already work on the server-side);
In someapp/view.py
def searchlist(request):
from haystack.query import SearchQuerySet
# POST["q"] should be receivedt from our client-side
searchText = request.POST["q"]
sqs = SearchQuerySet().filter(name=searchText)
data = []
for result in sqs:
data.append({"name": result.object.name})
return HttpResponse('{ success:true, searches:'+simplejson.dumps(data)+'}', mimetype = 'application/json')
Finally in your urls.py you should add:
(r'^searchlist/','someapp.views.searchlist'),
That was for it. Best wishes.
P.S.
I know this is not the greatest answer and there's lack of explanation, but as for me, I rather prefer a code example than verbal explanation.
SOLR has JSON output from its queries using wt=json param and can readily be consumed by ExtJS.
http://wiki.apache.org/solr/SolJSON?action=fullsearch&context=180&value=jsonp&titlesearch=Titles#JSON_Response_Writer
if you need to use jsonp you can specify a callback function via this param json.wrf=callback

EXTJS JsonStore not loading proeprly

I have a JSONStore like :
OrdersStore = Ext.extend(Ext.data.JsonStore, {
constructor: function(cfg) {
cfg = cfg || {};
OrdersStore.superclass.constructor.call(this, Ext.apply({
storeId: 'ordersStore',
url: '/ajaxSupport.action',
root: 'rows',
baseParams: {
action: 'getorderlegsearchgrid'
},
fields: [
{
name: 'orderId'
}
]
},
cfg));
}
});
new OrdersStore();
This store is attached to a grid : 'pendingOrdersGrid'.
When I do:
alert(Ext.util.JSON.encode(this.pendingOrdersGrid.getStore().getAt(0)));
I hope to get the first record. But I get 'null'
I can't give you a complete answer from this information but some hints:
don't extend a store with a fixed storeId, url or fields! That's really bad design
if possible use browser that supports a console (Firefox with firebug or IE with developer toolbar [or FF4/IE9]) and debug the content of your store in the console.
to read the content of a record try something like this.pendingOrdersGrid.getStore().getAt(0).data.orderId

Sencha Touch - Accessing Associated-Model Store JSON via Nested Looping

I've been lurking on Stack Overflow for quite some time now, and have found quite a number of very helpful answers. Many thanks to the community! I hope to be able to contribute my own helpful answers before too long.
In the meantime, I have another issue I can't figure out. I am using Sencha Touch to create a Web-based phone app and I'm having trouble using a nested loop to iterate through some JSON. I can grab the first level of data, but not the items nested within that first level. There is a somewhat related ExtJS thread, but I decided to create my own since ExtJS and Touch diverge in subtle yet important ways. Anyway, here is some code to show where I am:
JSON (truncated - the JSON is PHP/MYSQL-generated, and there are currently actually three sub levels with "title", all of which I can access. It's the sub level "items" through which I can't iterate):
{
"lists": [
{
"title": "Groceries",
"id": "1",
"items": [
{
"text": "contact solution - COUPON",
"listId": "1",
"id": "4",
"leaf": "true"
},
{
"text": "Falafel (bulk)",
"listId": "1",
"id": "161",
"leaf": "true"
},
{
"text": "brita filters",
"listId": "1",
"id": "166",
"leaf": "true"
}
]
}
]
}
Store:
var storeItms = new Ext.data.Store({
model: 'Lists',
proxy: {
type: 'ajax',
method: 'post',
url : LIST_SRC,
extraParams: {action: 'gtLstItms'},
reader: {
type: 'json',
root: 'lists'
}
}
});
Working Loop:
storeItms.on('load', function(){
var lstArr = new Array();
storeItms.each(function(i) {
var title = i.data.title;
lstArr.push(i.data.title);
});
console.log(lstArr);
});
Non-working Nested Loop:
storeItms.on('load', function(){
var lstArr = new Array();
storeItms.each(function(i) {
var title = i.data.title;
var id = i.data.id;
title.items.each(function(l) {
lstArr.push(l.data.text);
});
});
console.log(lstArr);
});
The non-working nested loop gives me the error "Cannot call method 'each' of undefined", in reference to 'title.items.each...'
I suspect this is because I've not set title to be a key to set up a key:value pair, so it just sees a list of strings...but I'm kind of at a loss.
I should mention that the store is populated via two Models that have been associated with one another. I know that the Store can access everything because I am able to do nested iterating via an XTemplate.
Any help will be much appreciated and hopefully returned to the community in kind before too long!'
-Eric
Eric, why the loop?
If your models are associated in the same way that the JSON is nested, then you should just be able to set autoLoad:true on the store, sit back and enjoy.
Anyway, on the assumption that you are needing these arrays for some other unrelated reason, the problem is that you are trying .each on
i.data.title.items
Surely you should be iterating through
i.data.items
Also, if the object is a model, you can use .get() instead of the data object:
var title = i.get('title);
Using new sencha touch 2 framework, you can create associations within the models exactly the same way how your json is returned.
Check Sencha Touch 2 Model Document which tells you the various config options on Model.
You may refer to this example of ST2 Nested List .
Hope this helps.
"title" is not a enumerable object, its a string. To iterate a string you'll need to split it to convert it into an array.
Also, instead of using Ext.each try a simple for (var x in obj) {} or for (var xc in obj.prop) {} If that works then the ext.each method should work as well but if ext cannot iterate the object it will just quietly fail.