I'm using ExtJS 4 and have an Ext.data.Store with an ajax proxy and api:
var gridStore = Ext.create('Ext.data.Store', {
autoSync: true,
proxy: {
type: 'ajax',
api: {
read: 'myurl',
create: 'myurl',
update: 'myurl',
destroy: 'myurl'
},
reader: {
type: 'json',
successProperty: 'success',
root: 'data',
messageProperty: 'message'
},
writer: {
type: 'json',
writeAllFields: false,
root: 'data'
},
listeners: {
exception: function(proxy, response, operation){
Ext.MessageBox.show({
title: 'Server error',
msg: operation.getError(),
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
}
}
...
When I use the update function and my server returns a json object with success:false (because he entered something wrong) the field in my associated grid is still marked as changed and the user has the option to change his wrong value.
That works fine.
But when I remove a record from the store...
var store = Ext.StoreManager.lookup('gridStore');
store.remove(store.getById(id));
...then ExtJS removes this record from the store first and call the ajax api afterwards. So when the destroy api returns success:false the message is shown as exception like in the update api, thats fine, but my record has been removed from the store! As example the exception from the server says that you cannot remove this record because of whatever but it's already removed in the store.
How to cancel the store removement after the server sync? I want the record to stay in the store if the server returns success:false.
Any idea? Maybe a bug?
UPDATE SOLUTION
Based on Ryan's anwer, I modified the exception listener as following, which works very well:
listeners: {
exception: function(proxy, response, operation){
Ext.MessageBox.show(...);
// get the removed records and insert them where they have been
var removedRecords = gridStore.getRemovedRecords();
for(var i=0; i<removedRecords.length; i++){
var record = removedRecords[i];
gridStore.insert(record.index, record);
}
}
}
The insert technique didn't work for me, the removed record stays marked for removal on the next sync operation. I am using Ext.data.Store.rejectChanges() for this purpose.
Just extending the code you gave, specifically the listeners area:
listeners: {
exception: function(proxy, response, operation){
Ext.MessageBox.show({
title: 'Server error',
msg: operation.getError(),
icon: Ext.MessageBox.ERROR,
buttons: Ext.Msg.OK
});
gridStore.add(gridStore.getRemovedRecords());
}
}
I am useing callback functions 'success','failure' or 'callback' when sync.
I hope this method can help you.
store.remove(records);
store.sync({
success: function (proxy, operations) {
// pop success message
}, failure: function (proxy, operations) {
// resume records
store.rejectChanges();
}
});
I am using model.destroy, this is what i use for deleting singular entries from grid:
text : 'Delete',
itemId : 'delete',
scope : this,
handler : function() {
var selection = grid.getView().getSelectionModel().getSelection()[0];
if(selection) {
selection.destroy({
failure : function() {
console.log('Record could not be deleted.');
},
success : function() {
store.remove(selection);
console.log('Record successfuly removed.');
},
});
}
}
Related
I have a problem here, here is the code.
function addProduct () {
var prod_form = Ext.getCmp('productForm');
if(!prod_form.getForm().isValid()) {
Ext.Msg.show({
title:'Warning',
msg: 'Please verify the field(s) marked in <font color="red">red</font>',
icon: Ext.Msg.WARNING,
buttons: Ext.Msg.OK
})
return;
}
prod_form.getForm().submit({
url: 'save',
success: function(prod_form,action) {
console.log('SUCCESS');
Ext.Msg.show({
title: 'Adding the Product Successful',
msg: 'Data has been saved!'
})
},
failure : function(prod_form,action) {
console.log('FAILURE');
Ext.Msg.show({
title: 'Error',
msg: 'Failure in adding the Product',
buttons: Ext.Msg.OK
})
}
})
}
i have a function add product in extjs and it handles the button Add Product whenever it is clicked. then it will load the modal which has the form inside.
it do work but the problem is in the success and failure function.
It returns the failure function, but it does write the data in the database.
Why is this?
thanks!!
Make sure your back end returns success: true in the response payload otherwise all calls to form.submit() will "fail" even though it may have worked.
If you can't change the back end to return the success variable, you could use errorReader property of the form.
So for symfony 2 users, what you need to do is to create a json response,
success: true
I want to receive a personalized error message when trying to load a store and my connection times out or the DB it's not accessible ... when I do an Ajax Request is very easy because I get "response" as a parameter either in success or failure ...
Ext.Ajax.request({
url: 'ajax_demo/sample.json',
success: function(response, opts) {
var obj = Ext.decode(response.responseText);
console.dir(obj);
},
failure: function(response, opts) {
console.log('server-side failure with status code ' + response.status);
}
});
But I'm facing problems to do the same when trying to load a store, I've defined a callback function but I only receive records, operation and success.
store.load({
callback : function(records, options, success) {
if (!success) {
// what can I do here to show personalized error sent from server
}
}
});
So, what is the proper way to handle a response like this to show it to the user?
{"success": false, "msg": "SomeExceptionFromServer"}
Best regards
When success is false operation never gets a response property instead it gets a getError method, but you should define a messageProperty in the proxyReader in order to work.
Example:
Ext.define("SC.store.SegurosCancelacionStore", {
extend: "Ext.data.Store",
model: "SC.model.PersonaSeguro",
proxy: {
timeout: 90000,
actionMethods: {
read : 'POST'
},
type: "ajax",
url: "../SegurosFinsolCancelacionServlet",
reader: {
type: "json",
root: "seguros",
messageProperty : 'msjError' //without this, it doesn't work
}
},
autoLoad: false
});
Implementation:
storeSegurosCancelacion.load({
params: {
'sucursal':sucursal,
'persona': persona
},
callback:function(records, operation, success){
msg.hide();
if(success == true){
if(records.length == 0){
Ext.Msg.alert('Resultado', 'No se ha encontrado informaciĆ³n');
}
}
if(success == false){
try{
Ext.Msg.alert('Error', operation.getError()); // way more elegant than ussing rawData etc ...
}catch(e){
Ext.Msg.alert('Error', 'Error inesperado en el servidor.');
}
}
}
});
Best regards
store.load({
callback : function(records, operation, success) {
console.log(operation.getResponse().msg);//this does the trick
}
});
If there is an error that you want to send, why not pass an empty data property along with the error message? So there are no records to load, but you get the message.
{
"success": false,
"msg": "SomeExceptionFromServer",
"data": {}
}
You might have to change data to your data property name.
I am calling rest web service from sencha extjs 4.2.1 in model .My model is
Ext.define('AM.model.User', {
extend: 'Ext.data.Model',
fields: [
{name: 'subCategoryName', type: 'string'},
],
proxy:{
type : 'jsonp',
callbackKey: 'callback',
url: 'http://192.168.1.10:8080/CredoCustomerConnect/subcategory/getsubcategorylist/1/1/0',
headers: {
'Accept': 'application/json'
},
callback: function( data ) {
console.log("callback" + data);
},
listeners: {
load: function() {
console.log("in load");
}
},
reader: {
type: 'json',
rootProperty:'subcategory'
}
}
});
When I call the url 'http://192.168.1.10:8080/CredoCustomerConnect/subcategory/getsubcategorylist/1/1/0',
in the browser , I am getting the result like
callback({"listException":"false","listSize":"5","nextPage":"false","pageNumber":"0","subcategory":[{"isException":"false","categoryId":"1","categoryName":"Solutions","productSize":"4","subCategoryDescription":"Oracle Consulting","subCategoryId":"1","subCategoryName":"Oracle Consulting"},],"totalRecords":"5"})
But I am not seeing any data in grid view.
Rest Web service method is
#GET
#Path("getsubcategorylist/{categoryId}/{userId}/{pageNumber}")
#Consumes("application/x-www-form-urlencoded")
//#Produces({MediaType.APPLICATION_JSON})
#Produces({"application/javascript"})
public JSONWithPadding getSubCategorylist(#PathParam("categoryId") int categoryId,#PathParam("userId")int userId,#PathParam("pageNumber") int pageNumber, #QueryParam("callback") String callback)
{
SubCategoryList subCategory = new SubCategoryList();
SubCategoryEntityHandler handler = new SubCategoryEntityHandler();
try {
subCategory = handler.getSubCategoriesList(categoryId,pageNumber);
return new JSONWithPadding(
new GenericEntity<SubCategoryList>(subCategory) {
},callback);
} catch (Exception e) {
e.printStackTrace();
subCategory.setListException(true);
subCategory.setListMessage(e.getMessage());
return new JSONWithPadding(
new GenericEntity<SubCategoryList>(subCategory) {
}, "callback");
}
}
My store is
Ext.define('AM.store.Users', {
extend: 'Ext.data.Store',
config: {
model: 'AM.model.User',
}
});
My view is
Ext.define('AM.view.user.List' ,{
extend: 'Ext.grid.Panel',
alias: 'widget.userlist',
title: 'All Users',
store: 'Users',
initComponent: function() {
this.columns = [
{header: 'Subject', dataIndex: 'subCategoryName', flex: 1},
];
this.callParent(arguments);
}
});
There is no error in console. But I am not seeing any data in grid.
How to resolve this?
Your server should not return simply:
callback({...})
Instead, it must read the value of the request GET param you've configured as callbackKey (in your case, that's 'callback'), and use this value as the name of the callback in the response. See section "Implementing on the server side" in the JsonP proxy doc.
For example, for its first request, the proxy will use an URL like this:
http://192.168.1.10:8080/CredoCustomerConnect/subcategory/getsubcategorylist/1/1/0?callback=Ext.data.JsonP.callback1
So the server response must be:
Ext.data.JsonP.callback1({ ... })
The second request URL would be something like:
http://192.168.1.10:8080/CredoCustomerConnect/subcategory/getsubcategorylist/1/1/0?callback=Ext.data.JsonP.callback2
Etc, etc.
From Extjs docs:
JsonP proxy creates a temporary callback function, waits for it to be
called and then puts the data into the Proxy making it look just like
you loaded it through a normal AjaxProxy.
This code worked for me after a bit of tweaking around
Ext.define('My.Model', {
extend: 'Ext.data.Model',
fields: [
'id', 'name'
],
proxy:{
type : 'jsonp',
url: 'http://127.0.0.1:8080',
reader : {
type : 'json',
root : 'data'
}
}
My.Model.load(1, {
callback: function(data) {
console.log(data);
}
});
Server side:
// Retrieve the callback parameter
cb = parms.get("callback");
// Build response string
msg = cb + "({ \"data\": [{\"id\": 1, \"name\": \"" + "username" + "\"}] });";
//Return msg with status 200 OK and "text/javascript" header
I am trying to save the changes from the grid to the store but I am not really sure if I'm doing it the right way.
STORE:
store_jvhdr = new Ext.data.JsonStore({
model: 'model_jvhdr',
proxy: {
type: 'ajax',
api: {
read: './journalservlet?batNbr='+batNbr+'&operation=GET_RECORD',
update: './journalservlet',
create: './journalservlet'
},
reader: {
type: 'json',
root: 'data'
}
},
autoLoad: true,
listeners: {
load: function(store, records, successful){
...
}
}
});
This are the listeners attached to the grid
listeners: {
itemdblclick: function(dv, record, item, index, e){
...
},
edit: function(editor, e){
console.log('test');
store_jvdtl.commitChanges();
store_jvdtl.sync();
}
}
Am I missing something?
Using store_jvdtl.sync(); is correct but I don't think you want to call commitChanges() the reason for this is that commitChanges() marks the records in the store as 'clean' or rather, removes their dirty state.
As a result, when you call sync() the store doesn't think it has any changes to send, so I'd have thought you wouldn't get the ajax requests made to your proxy api urls.
I am using extjs in a monorail application. I am using a JsonStore to persist data back to my controller. I have read, update and delete working properly. But I cannot seem to figure out how to format my response back on creates. Currently, Firebug gives me the following error:
uncaught exception:
Ext.data.DataReader: #realize was
called with invalid remote-data.
Please see the docs for
DataReader#realize and review your
DataReader configuration.
I am flummoxed about WTF this error means. Anyone have pointers? Relevant bits of code below:
var proxy = new Ext.data.HttpProxy({
api: {
read: '../foo/bar.rnr',
create: '../foo/CreateBar.rnr',
update: '../foo/UpdateBar.rnr',
destroy: '../foo/DeleteBar.rnr'
}
});
var writer = new Ext.data.JsonWriter({
encode: true,
writeAllFields: true,
listful: true,
destroyRecord: function(rec) {
return this.toHash(rec);
}
});
var store = new Ext.data.JsonStore({
autoLoad: true,
autoSave: false,
url: '../foo/bar.rnr',
method: 'get',
baseParams: { Id: pageParameters.Id },
proxy: proxy,
writer: writer,
id: 'Id',
fields: [
{ name: 'Id', type: 'int' },
{ name: 'Name', type: 'string' },
{ name: 'Note', type: 'string', defaultValue: null }
]
});
My current response looks like this, but this is after a lot of trial and error, so it is prolly hosed.
{"success":true,"message":"OK!","undefined":[]}
You'll need to return records in the returning json object.
Go to the following example from My book, Ext JS in Action, that shows how to use data writer for crud actions.
http://extjsinaction.com/examples/chapter08/usingWriterWithHttpProxy.html
Right click to insert a new record. Observe the Ajax req's from firebug and you'll see it in action.