/** * @class Ext.form.action.Submit * @extends Ext.form.action.Action * <p>A class which handles submission of data from {@link Ext.form.Basic Form}s * and processes the returned response.</p> * <p>Instances of this class are only created by a {@link Ext.form.Basic Form} when * {@link Ext.form.Basic#submit submit}ting.</p> * <p><u><b>Response Packet Criteria</b></u></p> * <p>A response packet may contain: * <div class="mdetail-params"><ul> * <li><b><code>success</code></b> property : Boolean * <div class="sub-desc">The <code>success</code> property is required.</div></li> * <li><b><code>errors</code></b> property : Object * <div class="sub-desc"><div class="sub-desc">The <code>errors</code> property, * which is optional, contains error messages for invalid fields.</div></li> * </ul></div> * <p><u><b>JSON Packets</b></u></p> * <p>By default, response packets are assumed to be JSON, so a typical response * packet may look like this:</p><pre><code> { success: false, errors: { clientCode: "Client not found", portOfLoading: "This field must not be null" } }</code></pre> * <p>Other data may be placed into the response for processing by the {@link Ext.form.Basic}'s callback * or event handler methods. The object decoded from this JSON is available in the * {@link Ext.form.action.Action#result result} property.</p> * <p>Alternatively, if an {@link Ext.form.Basic#errorReader errorReader} is specified as an {@link Ext.data.reader.Xml XmlReader}:</p><pre><code> errorReader: new Ext.data.reader.Xml({ record : 'field', success: '@success' }, [ 'id', 'msg' ] ) </code></pre> * <p>then the results may be sent back in XML format:</p><pre><code> <?xml version="1.0" encoding="UTF-8"?> <message success="false"> <errors> <field> <id>clientCode</id> <msg><![CDATA[Code not found. <br /><i>This is a test validation message from the server </i>]]></msg> </field> <field> <id>portOfLoading</id> <msg><![CDATA[Port not found. <br /><i>This is a test validation message from the server </i>]]></msg> </field> </errors> </message> </code></pre> * <p>Other elements may be placed into the response XML for processing by the {@link Ext.form.Basic}'s callback * or event handler methods. The XML document is available in the {@link Ext.form.Basic#errorReader errorReader}'s * {@link Ext.data.reader.Xml#xmlData xmlData} property.</p> */ Ext.define('Ext.form.action.Submit', { extend:'Ext.form.action.Action', alternateClassName: 'Ext.form.Action.Submit', alias: 'formaction.submit', type: 'submit', /** * @cfg {Boolean} clientValidation Determines whether a Form's fields are validated * in a final call to {@link Ext.form.Basic#isValid isValid} prior to submission. * Pass <tt>false</tt> in the Form's submit options to prevent this. Defaults to true. */ // inherit docs run : function(){ var form = this.form; if (this.clientValidation === false || form.isValid()) { this.doSubmit(); } else { // client validation failed this.failureType = Ext.form.action.Action.CLIENT_INVALID; form.afterAction(this, false); } }, /** * @private * Perform the submit of the form data. */ doSubmit: function() { var formEl, ajaxOptions = Ext.apply(this.createCallback(), { url: this.getUrl(), method: this.getMethod(), headers: this.headers }); // For uploads we need to create an actual form that contains the file upload fields, // and pass that to the ajax call so it can do its iframe-based submit method. if (this.form.hasUpload()) { formEl = ajaxOptions.form = this.buildForm(); ajaxOptions.isUpload = true; } else { ajaxOptions.params = this.getParams(); } Ext.Ajax.request(ajaxOptions); if (formEl) { Ext.removeNode(formEl); } }, /** * @private * Build the full set of parameters from the field values plus any additional configured params. */ getParams: function() { var nope = false, configParams = this.callParent(), fieldParams = this.form.getValues(nope, nope, this.submitEmptyText !== nope); return Ext.apply({}, fieldParams, configParams); }, /** * @private * Build a form element containing fields corresponding to all the parameters to be * submitted (everything returned by {@link #getParams}. * NOTE: the form element is automatically added to the DOM, so any code that uses * it must remove it from the DOM after finishing with it. * @return HTMLFormElement */ buildForm: function() { var fieldsSpec = [], formSpec, formEl, basicForm = this.form, params = this.getParams(), uploadFields = []; basicForm.getFields().each(function(field) { if (field.isFileUpload()) { uploadFields.push(field); } }); function addField(name, val) { fieldsSpec.push({ tag: 'input', type: 'hidden', name: name, value: Ext.String.htmlEncode(val) }); } // Add the form field values Ext.iterate(params, function(key, val) { if (Ext.isArray(val)) { Ext.each(val, function(v) { addField(key, v); }); } else { addField(key, val); } }); formSpec = { tag: 'form', action: this.getUrl(), method: this.getMethod(), target: this.target || '_self', style: 'display:none', cn: fieldsSpec }; // Set the proper encoding for file uploads if (uploadFields.length) { formSpec.encoding = formSpec.enctype = 'multipart/form-data'; } // Create the form formEl = Ext.DomHelper.append(Ext.getBody(), formSpec); // Special handling for file upload fields: since browser security measures prevent setting // their values programatically, and prevent carrying their selected values over when cloning, // we have to move the actual field instances out of their components and into the form. Ext.Array.each(uploadFields, function(field) { if (field.rendered) { // can only have a selected file value after being rendered formEl.appendChild(field.extractFileInput()); } }); return formEl; }, /** * @private */ onSuccess: function(response) { var form = this.form, success = true, result = this.processResponse(response); if (result !== true && !result.success) { if (result.errors) { form.markInvalid(result.errors); } this.failureType = Ext.form.action.Action.SERVER_INVALID; success = false; } form.afterAction(this, success); }, /** * @private */ handleResponse: function(response) { var form = this.form, errorReader = form.errorReader, rs, errors, i, len, records; if (errorReader) { rs = errorReader.read(response); records = rs.records; errors = []; if (records) { for(i = 0, len = records.length; i < len; i++) { errors[i] = records[i].data; } } if (errors.length < 1) { errors = null; } return { success : rs.success, errors : errors }; } return Ext.decode(response.responseText); } });