30May
Dynamic Sencha Touch Forms : Part 3 : Adding form fields on the fly

Dynamic Sencha Touch Forms : Part 3 : Adding form fields on the fly

After a comment from Brandon looking for advice on adding form fields on the fly, I thought it would be worth a mini blog article to explain it.

 

What we want to do is add a button to our form that, when tapped, will add a new field to the form. By adding this functionality we can allow users to enter arbitrary amounts of data. This can be applied to situations such as, when entering ingredients for a recipe (we don’t want to restrict them to a set number, nor do we want to prepopulate the form with too many fields); adding qualifications to your CV (not everyone has the same number of qualifications so how do we allow them to enter the right number?).

 

So, you get the idea about why we might want this – but how do we make it?

As with all our tutorials there is a Tutorial Package that contains all the files you need to try the examples and follow the tutorial step by step. If you click on the Step’s header you can view the demo for that step.

Dynamic Sencha Touch Forms - Part 3 - Tutorial Package (1700)

Just drop into the Sencha Touch ‘examples’ directory

Step 1 – Create our Form

As in the previous parts we’re going to create a basic form to house our dynamic fields. This is a simple form (with no fields) with an Add button docked to the top and a Submit button docked to the bottom.

[javascript]

Ext.ns(‘DynamicForms’); // register our namespace
DynamicForms.MyForm = Ext.extend(Ext.form.FormPanel, {

initComponent: function(){

Ext.apply(this, {
floating: true,
width: 350,
height: 370,
centered: true,
modal: true,
hideOnMaskTap: false,
scroll: ‘vertical’,
dockedItems: [{
dock: 'top',
xtype: 'button',
text: 'Add Field',
handler: function(){
// handler to be completed in Step 2
},
scope: this
}, {
dock: 'bottom',
xtype: 'button',
text: 'Submit',
handler: function(){
// handler to be completed in Step 2
},
scope: this
}],
items: [] });

DynamicForms.MyForm.superclass.initComponent.call(this);
}

});

[/javascript]

We have left our buttons’ handlers empty just now, but we will add in that functionality in Step 2.

Step 2 – Make it Dynamic

Now we add the fun stuff. What we want to do is, when the Add button is tapped, create a new TextField and add it to the Form. This is remarkably simple and requires a whopping two lines of code. So we add this code to the Add button’s handler.

[javascript]

this.add({
xtype: ‘textfield’,
name: ‘MyField-’ + this.items.length
});

this.doLayout();

[/javascript]

We use the Form’s ‘add‘ method to create the new TextField and just pass it a configuration option that will create the field (I’ve only used a couple of config options to show the idea but you can add a full config object). We have dynamically added a number to the TextField’s name by appending the item count which is necessary due to a (in my opinion) bug with the ‘getValues‘ method which I’ll discuss later.

Finally we call a wee doLayout to force the Form to redraw itself with the new field in place.

Now if you open the Step 2 HTML page and tap the Add button a new TextField will be added. That’s it, done!

These dynamically added fields will be automatically included in the form submission and if you add the following code to the Submit button’s handler you will get a popup that shows the output of the ‘getValues‘ method.

[javascript]

var displayString = ”;
var formValues = this.getValues();

for(var fieldName in formValues){
displayString = displayString + fieldName + ‘: ‘ + formValues[fieldName] + ‘
‘;
}

Ext.Msg.alert(‘Output of this.getValues()’, displayString);

[/javascript]

The current implementation of the getValues method means that only Checkboxes can have the same name and consequently be sent to the server as an array on submission. The situations I’ve described previously are prime candidates to be sent as arrays which make it much easier to deal with on the server-side rather than having to parse field names with numbers suffixed. Therefore I think it’s a bug in the framework and should be changed to allow any field type to have the same name.

Comments