Ronaldo
15 Aug 2007, 11:27 AM
Hi all,
I decided to have a look at the pros and cons to go JSON all the way. That means not only loading data using JSON, but also submitting forms using JSON (No gets but posts).
I guess I might just as well share the results, as it shows how well written this stuff is.
(As a matter of fact, to write all this took more time than to figure out how it worked)
I know the form.submit method can take extra parameters which are posted as a separate field, but I'd like to use JSON only in a field called 'data', and get rid of the 'regular' form fields. That way, I could get rid of all the specific Struts forms, and process a form submission in a more general manner using a single string field containing all data. Again, it's just an experience, so I welcome all thoughts and comments.
Note that I intend to add more complex data (Say from modified grids on the same page) to be posted in the same request.
I also intended to keep using the form.submit method because it has error handling attached, so if there are errors, they will be automagically displayed in the form fields. If I'd use my own Ajax request, I'd have to wire that too.
So I dived into the form.submit method and discovered that the actual ajax request is executed in a separate class called Ext.form.Action.Submit.
Ext.form.Action.Submit = function(form, options){
Ext.form.Action.Submit.superclass.constructor.call(this, form, options);
};
Ext.extend(Ext.form.Action.Submit, Ext.form.Action, {
type : 'submit',
run : function(){
var o = this.options;
var method = this.getMethod();
var isPost = method == 'POST';
if(o.clientValidation === false || this.form.isValid()){
Ext.Ajax.request(Ext.apply(this.createCallback(), {
form:this.form.el.dom,
url:this.getUrl(!isPost),
method: method,
params:isPost ? this.getParams() : null,
isUpload: this.form.fileUpload
}));
}else if (o.clientValidation !== false){ this.failureType = Ext.form.Action.CLIENT_INVALID;
this.form.afterAction(this, false);
}
},
success : function(response){
... handle success code
},
handleResponse : function(response){
... handle response
}
});
This action is called from the BasicForm.submit method:
Ext.extend(Ext.form.BasicForm, Ext.util.Observable, {
.......
doAction : function(action, options){
if(typeof action == 'string'){
action = new Ext.form.Action.ACTION_TYPES[action](this, options);
}
if(this.fireEvent('beforeaction', this, action) !== false){
this.beforeAction(action);
action.run.defer(100, action);
}
return this;
},
submit : function(options){
this.doAction('submit', options);
return this;
},
.......
}
And the action called is mapped with the string 'submit' somewhere else:
Ext.form.Action.ACTION_TYPES = {
'load' : Ext.form.Action.Load,
'submit' : Ext.form.Action.Submit
};Now the only line I needed to remove is
form:this.form.el.dom,in the Ext.Ajax.request. But the success and handleResponse methods were just fine for handling the JSON response from the server.
And here's how that works:
I created a new JSONSubmit class, which inherits everything from the original Ext.form.Action.Submit class.
Ext.form.Action.JSONSubmit = function(form, options){
Ext.form.Action.JSONSubmit.superclass.constructor.call(this, form, options);
};
Ext.extend(Ext.form.Action.JSONSubmit, Ext.form.Action.Submit, {
type : 'submit',
run : function(){
var o = this.options;
var method = this.getMethod();
var isPost = method == 'POST';
if(o.clientValidation === false || this.form.isValid()){
Ext.Ajax.request(Ext.apply(this.createCallback(), {
//form:this.form.el.dom,
url:this.getUrl(!isPost),
method: method,
params:isPost ? this.getParams() : null,
isUpload: this.form.fileUpload
}));
}else if (o.clientValidation !== false){
this.failureType = Ext.form.Action.CLIENT_INVALID;
this.form.afterAction(this, false);
}
}
});And below that, you need to 'register' the new class, replacing the old one:
Ext.form.Action.ACTION_TYPES = {
'load' : Ext.form.Action.Load,
'submit' : Ext.form.Action.JSONSubmit
};Just to make sure, I also removed the event from every new form created:
var form = new Ext.form.Form({...});
form.un('submit', form.submit, form);So now the form.submit works and the submit is configured as follows:
form.submit({
url: anUrl ,
method: 'POST', //ok already default, could be omitted
params : { data: data },
waitMsg:'Saving...',
reset: false,
failure: function(form, action) {
.. do something usefull with the errors
},
success: function(form, action) {
.. do something usefull too
}
});
I decided to have a look at the pros and cons to go JSON all the way. That means not only loading data using JSON, but also submitting forms using JSON (No gets but posts).
I guess I might just as well share the results, as it shows how well written this stuff is.
(As a matter of fact, to write all this took more time than to figure out how it worked)
I know the form.submit method can take extra parameters which are posted as a separate field, but I'd like to use JSON only in a field called 'data', and get rid of the 'regular' form fields. That way, I could get rid of all the specific Struts forms, and process a form submission in a more general manner using a single string field containing all data. Again, it's just an experience, so I welcome all thoughts and comments.
Note that I intend to add more complex data (Say from modified grids on the same page) to be posted in the same request.
I also intended to keep using the form.submit method because it has error handling attached, so if there are errors, they will be automagically displayed in the form fields. If I'd use my own Ajax request, I'd have to wire that too.
So I dived into the form.submit method and discovered that the actual ajax request is executed in a separate class called Ext.form.Action.Submit.
Ext.form.Action.Submit = function(form, options){
Ext.form.Action.Submit.superclass.constructor.call(this, form, options);
};
Ext.extend(Ext.form.Action.Submit, Ext.form.Action, {
type : 'submit',
run : function(){
var o = this.options;
var method = this.getMethod();
var isPost = method == 'POST';
if(o.clientValidation === false || this.form.isValid()){
Ext.Ajax.request(Ext.apply(this.createCallback(), {
form:this.form.el.dom,
url:this.getUrl(!isPost),
method: method,
params:isPost ? this.getParams() : null,
isUpload: this.form.fileUpload
}));
}else if (o.clientValidation !== false){ this.failureType = Ext.form.Action.CLIENT_INVALID;
this.form.afterAction(this, false);
}
},
success : function(response){
... handle success code
},
handleResponse : function(response){
... handle response
}
});
This action is called from the BasicForm.submit method:
Ext.extend(Ext.form.BasicForm, Ext.util.Observable, {
.......
doAction : function(action, options){
if(typeof action == 'string'){
action = new Ext.form.Action.ACTION_TYPES[action](this, options);
}
if(this.fireEvent('beforeaction', this, action) !== false){
this.beforeAction(action);
action.run.defer(100, action);
}
return this;
},
submit : function(options){
this.doAction('submit', options);
return this;
},
.......
}
And the action called is mapped with the string 'submit' somewhere else:
Ext.form.Action.ACTION_TYPES = {
'load' : Ext.form.Action.Load,
'submit' : Ext.form.Action.Submit
};Now the only line I needed to remove is
form:this.form.el.dom,in the Ext.Ajax.request. But the success and handleResponse methods were just fine for handling the JSON response from the server.
And here's how that works:
I created a new JSONSubmit class, which inherits everything from the original Ext.form.Action.Submit class.
Ext.form.Action.JSONSubmit = function(form, options){
Ext.form.Action.JSONSubmit.superclass.constructor.call(this, form, options);
};
Ext.extend(Ext.form.Action.JSONSubmit, Ext.form.Action.Submit, {
type : 'submit',
run : function(){
var o = this.options;
var method = this.getMethod();
var isPost = method == 'POST';
if(o.clientValidation === false || this.form.isValid()){
Ext.Ajax.request(Ext.apply(this.createCallback(), {
//form:this.form.el.dom,
url:this.getUrl(!isPost),
method: method,
params:isPost ? this.getParams() : null,
isUpload: this.form.fileUpload
}));
}else if (o.clientValidation !== false){
this.failureType = Ext.form.Action.CLIENT_INVALID;
this.form.afterAction(this, false);
}
}
});And below that, you need to 'register' the new class, replacing the old one:
Ext.form.Action.ACTION_TYPES = {
'load' : Ext.form.Action.Load,
'submit' : Ext.form.Action.JSONSubmit
};Just to make sure, I also removed the event from every new form created:
var form = new Ext.form.Form({...});
form.un('submit', form.submit, form);So now the form.submit works and the submit is configured as follows:
form.submit({
url: anUrl ,
method: 'POST', //ok already default, could be omitted
params : { data: data },
waitMsg:'Saving...',
reset: false,
failure: function(form, action) {
.. do something usefull with the errors
},
success: function(form, action) {
.. do something usefull too
}
});