I have a jqGrid with the following pager
.navGrid('#pager-mm',{add:false,edit:false,del:false,search:true,view:true},
{},{},{},
{multipleSearch:true,multipleGroup:true,showQuery: true},
{})
When I build a complex query having nested AND and OR groupings, jqGrid builds the correct query as a string on the client-side. Rather than rebuilding the same query on my server writing extra code, I would like to send the correctly built client-side query as a string to the server. However,
beforeSumbit:function()
is not being triggered when I search. How can I send this custom string to my server?
I don't full understand what you really want. By default the filters will be send to the server as filters parameter. Nevertheless you can use onSearch callback for example to access to the searching filter. You can use
var filters = $(this).jqGrid("getGridParam", "postData").filters;
to get filters property of the postData.
UPDATED: I would never ever trust the fragment of SQL statement created on the client side. If you use the SQL fragment which sent from the client in the server code you allow in the way automatically SQL Injection. If security play some role in your application you should not use SQL statement created by jqGrid.
Nevertheless if your question have pure theoretical nature you can get the SQL statement displayed in the searching dialog using toSQLString method of the searching filter. The corresponding code could look like the following
grid.jqGrid('navGrid', '#pager', {edit: false, add: false, del: false}, {}, {}, {}, {
multipleSearch: true,
multipleGroup: true,
showQuery: true,
recreateFilter: true,
onSearch: function () {
var $filter = $("#" + $.jgrid.jqID("fbox_" + this.id)),
sql = $filter.jqFilter('toSQLString');
alert(sql);
}
});
The corresponding demo you will find here. By the way you don't need to use showQuery: true to be able to use toSQLString method.
Related
I'm calling this dataset:
http://data.edinburghopendata.info/api/action/datastore_search?resource_id=4cfb5177-d3db-4efc-ac6f-351af75f9f92
with an AJAX call :
var data = {
resource_id: '4cfb5177-d3db-4efc-ac6f-351af75f9f92',
filters: '{"BankTypeNa": "Packaging", "BankTypeNa": "Compost Bins"}',
limit : 4757
};
$.ajax({
url: 'http://data.edinburghopendata.info/api/action/datastore_search',
data: data,
dataType: 'jsonp',
success: function(data) {
markers = data.result.records;
showMarkers();
}
});
which is giving results only for the second filter.
http://data.edinburghopendata.info/api/action/datastore_search?resource_id=4cfb5177-d3db-4efc-ac6f-351af75f9f92&filters={%22BankTypeNa%22:%20%22Packaging%22,%20%22BankTypeNa%22:%20%22Compost%20Bins%22}
Is there a way, or another parameter I could use to get both "Packaging" and "Compost Bins" in my search results?
Would be nice if somebody can prove me wrong, but its not possible. In theory you would just put the two values in an array as the value for the BankTypeNa key, e.g.
filters: '{"BankTypeNa": ["Packaging", "Compost Bins"]}'
But this doesn't work for text columns (an SQL error results). It does work for numeric ones [1]. It would be good to submit an issue on that at github.com/ckan/ckan.
I would use the datastore_search_sql endpoint instead, i.e.
var data = {
"resource_id": "4cfb5177-d3db-4efc-ac6f-351af75f9f92",
"sql": "SELECT * FROM \"4cfb5177-d3db-4efc-ac6f-351af75f9f92\" WHERE \"BankTypeNa\" LIKE 'Packaging' OR \"BankTypeNa\" LIKE 'Compost Bins'",
"limit": 4757
};
[1] CKAN: delete a list of records within the DataStore in a single query
Our application handles and manages records changes on the client side. We use ExtJS5 Data Session mechanism.
A session tracks records that need to be updated, created or destroyed
on the server. It can also order these operations to ensure that newly
created records properly reference other newly created records by
their new, server-assigned id.
Let me introduce short use case.
User opens and fills a form. Behind the scene fields are binded to entity object which is tracked by session. When user clicks Submit then session is synchronized, i.e. Ext sends requests to the server and parse response. Here I've encountered a problem.
Server returns following object but Ext does not recognize it:
[{"success": false, errorMessage: "error"}]
Ext prints warning:
[W] Ignoring server record: {"success":false}
or
[W] Ignoring server record: {"success":true}
My question is how should look server response in order to indicate that record is not accepted/saved by backend?
The source code where above warning is printed: http://docs-origin.sencha.com/extjs/5.0/apidocs/source/Operation.html (in function doProcess)
Below I put snippet how I'm starting a batch operation (sync session):
var session = this.getViewModel().getSession(),
saveBatch = session.getSaveBatch();
saveBatch.on('complete', function (batch, operation, eOpts) {
// whole batch processing has been completed
/*...*/
});
saveBatch.on('exception', function (batch, operation, eOpts) {
// exception has been occurred (possible for each operation) (such as HTTP 500)
/*...*/
});
saveBatch.on('operationcomplete', function (batch, operation, eOpts) {
// single operation has been completed
// now, every operation is marked as successful
/*...*/
});
saveBatch.start();
update 26.09.2014
Sencha developer has suggested including an id of object in the response. so I've modified server response to:
[{"id": 10, "success": false}]
but this does not solve the problem.
I spend some time on debugging Ext.data.operation.Operation.doProcess method and I analyzed a sample code from sencha support. Ultimately I've found the solution.
There is my proxy config:
proxy: {
type: 'rest',
// ...
reader: {
type: 'json',
rootProperty: 'data',
totalProperty: 'totalCount',
successProperty: 'success',
messageProperty: 'errorMessage'
}
}
Server response when some error occured:
{
"success": false,
"errorMessage": "<error message>"
}
Server response when data was successfully saved:
The minimal form for delete or update record without changing data:
{
"success": true,
}
The extended form for creating or updating record with changing record data:
{
"success": true,
"data": [{
clientId: 5, // clientIdProperty
id: 5,
// [optional] fields to change, e.g.:
name: 'new name'
}]
}
I modified a demo which I have from sencha support:
https://fiddle.sencha.com/#fiddle/bem
in proxy config use data2.json for error and data3.json for success response.
i need to implement the multisort in grid that populate from a Ajax Store, but i have also a problem with the simple sorting of column.
This is my store:
dsUser = Ext.create('Ext.data.Store', {
model: 'user',
pageSize: defPagSize,
totalProperty: 'totalCount',
autoLoad: {start: 0, limit: defPagSize},
remoteSort: true,
proxy: {
type: 'ajax',
enablePaging:true,
url: '<c:url value="/queryForList.action?query=User.getUsers"/>',
reader: {
type: 'json',
root: 'list',
totalProperty:'totalCount'
}
}
});
Anytype of help is usefull.
Thanks.
EDIT:
Now i re-write the old logic of sorting in my application..At this moment i find anyone can help me to post and modify grid for posting an array of (property:'', direction:'') and mantain the icon on the grid to select. (sorry for my english)
The proxy is merely sending through the sortParam and value in a structure that is usable in JS...e.g., a JSON-encoded array of objects ([{"property":"email","direction":"DESC"}]).
When you receive this request server-side, you'll absolutely need top parse apart the sort order object and convert it to a string that your DB can understand. Using the raw value from the query string in your DB will not work, nor was it intended to work like that.
When I do this, it's typically like this:
Receive request
Search for sort order param in query string
Decode the JSON string into an object in my server-side app's language
Iterate over the array of sorters and build a "sort" string
Send parsed sort string along to the DB query
I have seen questions slightly related to this, but none that answer my problem. I have set up an Ext.Ajax.request as follows:
var paramsStringVar = 'param1=1¶m2=two¶m3=something¶m4=etc';
Ext.Ajax.request({
url: '/cgi-bin/url.pl',
method:'POST',
params:paramsStringVar,
timeout:120000,
success: function(response, opts){
var objhtml = response.responseText; //content returned from server side
console.log(objhtml);
}
});
This request retrieves the appropriate content from the backend. One parameter is outputType, which can take values {html, excel, csv}. When returning html to display I am able to handle and display it correctly. Now on to the problem...
When I set the outputType parameter to csv or excel, I get back the appropriate content as csv or tsv(excel) as requested. BUT, I don't want the content, I want a prompt to download the file(csv or excel). How can I have the browser auto prompt the user to download the file instead of just retrieving the text content within extjs?
Version 4.07 so I can't use any 4.1 only features
There seems to be no bulletproof solution but there are several approaches I would try:
1) Use an iframe instead of real XHR to POST data to the server, e.g. <form action="/something" target="myiframe"> where myiframe is the name of your hidden iframe. That way your form would use the iframe (not your main window) to submit data to the configured URL. Your server should set response header as application/octet-stream (or some ither MIME type for binary data) so the browser triggers download. Otherwise (if html returned in your case) you can just retrieve iframe's body innerHTML and display it to the user in UI. While using an iframe (or a new window) instead of XHR doesn't sound like the best idea, this solution seems to be the most reliable so far (and with best browser support).
Here is a slightly modified example from Ext.form.Basic docs page:
Ext.create('Ext.form.Panel', {
title: 'Basic Form',
renderTo: Ext.getBody(),
width: 350,
// Any configuration items here will be automatically passed along to
// the Ext.form.Basic instance when it gets created.
// *THIS* makes the form use a standard submit mechanism, not XHR
/**/standardSubmit: true,
// URL to submit to
url: 'save-form.php',
items: [{
fieldLabel: 'Field',
xtype: 'textfield',
name: 'theField'
}],
buttons: [{
text: 'Submit',
handler: function() {
// The getForm() method returns the Ext.form.Basic instance:
var form = this.up('form').getForm();
if (form.isValid()) {
// Submit the Ajax request and handle the response
form.submit({
success: function(form, action) {
Ext.Msg.alert('Success', action.result.msg);
},
failure: function(form, action) {
Ext.Msg.alert('Failed', action.result.msg);
},
// You can put the name of your iframe here instead of _blank
// this parameter makes its way to Ext.form.Basic.doAction()
// and further leads to creation of StandardSubmit action instance
/**/ target: '_blank'
});
}
}
}]
});
There are two key parameters here (lines marked with /**/):
standardSubmit: true config that you pass to your form will make it do a standard submit instead of XHR.
Passing a target parameter to the form's submit action. This feature is not documented but you can see it being used in Ext.form.action.Submit source code (all options that you pass to Ext.form.Basic.submit() method end up as parameters of Ext.form.action.* instance.
In the example code I put target: '_blank' to demonstrate that it works right away (will create a new browser window). You can replace it with the name of your iframe later but I suggest that you first test how your form submits data to a regular new window and then develop logic that creates and processes an iframe. You will have to process the result inside iframe yourself, thought. It's not that difficult, see Ext.data.Connection.upload() implementation as an example of iframe processing.
ExtJS actually already uses the iframe technique for file uploads. See Ext.data.Connection and Ext.form.field.Field.isFileUpload() for an idea of how it can work.
2) Suggested here: Using HTML5/Javascript to generate and save a file.
If you don't want to go the iframe way, you can try generate data URI from response data and navigate to that URI triggering download:
content = "Hello world!";
uriContent = "data:application/octet-stream," + encodeURIComponent(content);
window.location.href = uriContent;
Again, mimetype is essential here. This worked for me, you should note, however, that browsers impose a size limit to data URIs (256Kb is a safe bet).
3) Another answer in the mentioned thread links to FileSaver.js library the implements the (abandoned?) w3 spec. Usage and demo here. It uses [BlobBuilder] to generate a blob of binary data that is further used to initialize downloads using one of several methods. While this solution seems to work, it uses deprecated APIs and may not be future-proof.
Below is my solution. This is how I have it currently working. The response generates a download/open prompt, based on a response type of text/csv. Note that no iFrame or reference to an iframe are needed. I spent a lot of time hung up on the need for an iFrame, which actually broke my solution. An iFrame is not needed to generate a download prompt. What is needed is a request(submittal) similar to this one, along with a backend generating the appropriate csv with text/csv response header.
var hiddenForm = Ext.create('Ext.form.Panel', {
title:'hiddenForm',
standardSubmit: true,
url: /cgi-bin/url.pl
timeout: 120000,
height:0,
width: 0,
hidden:true,
items:[
{xtype:'hiddenField', name:'field1', value:'field1Value'},
// additional fields
]
})
hiddenForm.getForm().submit()
The standardSubmit line is vital
You don't need to create a form panel and make it hidden in your extjs file. We can add a html form and on click of button in extjs file we can submit the form using the url. This will work both in IE as well as chrome browsers. Below is my code i tried and its working fine,
<form action="<%=fullURL%>/DownloadServlet.do" method="get" id="downloadForm" name="downloadForm" target="_self">
</form>
click:
{
fn: function()
{
document.getElementById('downloadForm').submit();
}
}
To get it working on ExtJS 3.4:
var hiddenForm = new Ext.FormPanel({
id:'hiddenForm',
region: 'south',
method: 'POST',
url: "/cgi/test.wsgi",
height: 0,
standardSubmit: true,
hidden:true,
items:[
{xtype:'hidden', name:'p', value:p},
{xtype:'hidden', name:'g', value:g},
// ...
],
});
linkThis = new Ext.Button({
text: 'Download this CSV',
handler: function() {
hiddenForm.getForm().submit();
},
maxHeight: 30,
});
Remember that in order to make it working, you should put the hiddenForm in any container (i.e. in the same Ext.Window of the button), for example:
risultatiWindow = new Ext.Window({
title: 'CSV Export',
height: 400,
width: 500,
....
items: [...., hiddenForm]
});
Ok, I am semi-new to ExtJS, and I am building a program that has "inputs" that are listed in a grid, and in my DB these inputs can be linked to "symptoms".
I am trying to create a function that will take in the id of the input and grab all of the symptoms from the database that are linked to that symptom, and list them in a field set.
It works fine when I click on an input that is only linked to one symptom, but if the input is linked to more than one symptom, then the error says.. "invalid property id"
This is what I have for my function.
function listSymptoms(inputID){
Ext.Ajax.request({
url: "../../inc/project4.php?list=symptoms",
reader: new (Ext.data.JsonReader)({
root: "symptoms",
inputid: "id"
}),
params: {
inputid: inputID
},
method: "POST",
success: function (f, a){
var jsonData = Ext.util.JSON.decode(f.responseText);
symptomsFieldSet.body.update(jsonData.data.name);
},
failure: function (f,a){
Ext.Msg.alert('There was a problem opening your message.');
}
});
}
I have the inputID for the function being passed in when the user clicks on one of the inputs that are held inside the grid.
I believe that my problem has something to do with this line..
symptomsFieldSet.body.update(jsonData.data.name);
I am just stumped on how to handle this. Do I need to create a data store like I have for grids? Or is there an easier way to do this?
ANY help is appreciated! thanks in advance.
I think you need to rethink the structure of your JSON response object. You can send this in your JSON response to your request. If you are using Ext.util.Ajax calls instad of a form, you'll need to decode this JSON response string using the util method Ext.util.JSON.decode(). Check out the API Documentation
{
success: true,
msg: {text: 'this can be used for error message handling' },
data : [
{id:1,
chiefComplaint: 'head hurts',
symptoms: [
{symptomID: '740.1', text: 'Headache'},
{symptomID: '12352135'. text: 'and so on'}
}
]
]
}