Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
Clear All
new posts

    DynamicForm Subclass

    I'm trying to create a DynamicForm subclass to implement custom handling of a "multiple=true" field in my datasource.

    application.ds.xml
    Code:
    <DataSource ...>
      <serverObject ... />
      <fields>
        <field name="vehicles" type="vehicle" multiple="true" />
      </fields>
    </DataSource>
    vehicle.ds.xml
    Code:
    <DataSource ...>
      <serverObject ... />
      <fields>
        <field name="year" type="integer" />
        <field name="make" type="text" />
        <field name="model" type="text" />
      </fields>
    </DataSource>
    Let me explain what I'm trying to accomplish.

    I want a form that has two buttons "Add Vehicle" and "Remove Vehicle" and when clicked will either show / hide the corresponding nested form of (year,make,model) [see attachment].

    This showing / hiding is not a problem and is working as expected.

    Validation is not a problem either - overriding DynamicForm.validate() and delegating to the nested forms works like a charm.

    The problem is aggregating the nested form values by override DynamicForm.getValues(). Using Firebug, the getValues() is not getting called as a part of the ValuesManager.saveData() - the validate() function does get called and aborts saving if a nested form is visible and invalid (i.e. incomplete).

    getValues() should be expecting a JS Object like...
    Code:
    {
      vehicles:[{
        year: x1,
        make: "y2",
        model: "z2"
      },{
        year: x2,
        make: "y2",
        model: "z2"
      }]
    }
    ...for correct unmarshalling on the server-side.

    Anyone have any ideas on what I'm doing wrong?

    Thanks,
    --mgbowman

    -----

    Here's the code for my two forms:

    VehiclesForm.js
    Code:
    isc.defineClass("VehiclesForm", "DynamicForm").addProperties({
    
    	count: 0,
    	max: 5,
    	
    	initWidget: function(config) {
    		this.numCols = 4;
    		this.fields = [{
    			name: "add",
    			title: "Add Vehicle",
    			type: "button",
    			click: this.getID() + ".addVehicle()",
    			endRow: false
    		},{
    			name: "remove",
    			title: "Remove Vehicle",
    			type: "button",
    			click: this.getID() + ".removeVehicle()",
    			startRow: false,
    			disabled: true
    		}];
    		this.vehicleForms = [];
    		for (var i = 0; i < this.max; i++) {
    			this.vehicleForms.add(isc.VehicleForm.create({
    				requiredIf: this.getID() + ".count > " + i
    			}));
    			this.fields.add({
    				name: "vehicles",
    				title: "Vehicle #" + (i + 1),
    				type: "nestedEditor",
    				editor: this.vehicleForms[i],
    				showIf: this.getID() + ".count > " + i,
    			});
    		}
    		this.Super("initWidget", arguments);
    	},
    	
    	validate: function(validateHiddenFields) {
    		var valid = true;
    		for (var i = 0; i < this.count; i++) {
    			valid &= this.vehicleForms[i].validate(validateHiddenFields);
    		}
    		return valid;
    	},
    	
    	getValues: function() {
    		var vehicles = [];
    		for (var i = 0; i < this.count; i++) {
    			vehicles.add(this.vehicleForms[i].getValues());
    		}
    		return { vehicles: vehicles }
    	},
    	
    	addVehicle: function() {
    		if (this.count < this.max) {
    			this.count++;
    			this.markForRedraw();
    		}
    		if (this.count == this.max) {
    			this.getField("add").disable();
    		}
    		this.getField("remove").enable();
    	},
    	
    	removeVehicle: function() {
    		if (this.count > 0) {
    			this.count--;
    			this.markForRedraw();
    		}
    		if (this.count == 0) {
    			this.getField("remove").disable();
    		}
    		this.getField("add").enable();
    	}
    
    });
    VehicleForm.js
    Code:
    isc.defineClass("VehicleForm", "DynamicForm").addProperties({
    	
    	initWidget: function(config) {
    		this.fields = [{
        		name: "year",
        		title: "Year",
        		editorType:"select",
        		optionDataSource:vehicleYears,
        		changed: function() {
        			var make = this.form.getField('make');
        			var model = this.form.getField('model');
        			make.clearValue();
        			model.clearValue();
        			make.enable();
        			model.disable();
        			make.fetchData();
        		},
        		validators: [{
        			type: "requiredIf",
        			expression: config.requiredIf
        		}]
        	}, {
            	name: "make",
            	title: "Make",
            	editorType: "select",
            	optionDataSource: vehicleMakes,
            	autoFetchData: false,
            	disabled: true,
            	changed: function() {
            		var model = this.form.getField('model');
            		model.clearValue();
            		model.fetchData();
            		model.enable();
            	},
            	getPickListFilterCriteria: function() {
            		var year = this.form.getValue("year");
            		return {year:year};
            	},
            	validators: [{
            		type: "requiredIf",
            		expression: config.requiredIf
            	}]
        	}, {
        		name: "model",
        		title: "Model",
        		editorType: "select",
        		optionDataSource: vehicleModels,
        		autoFetchData: false,
        		disabled: true,
        		getPickListFilterCriteria: function() {
        			var year = this.form.getValue("year");
        			var make = this.form.getValue("make");
        			return {year: year, make: make};
        		},
        		validators: [{
        			type: "requiredIf",
        			expression: config.requiredIf
        		}]
        	}];
    		this.Super("initWidget", arguments);
    	}
    	
    });
    Attached Files

    #2
    Looks like a ListGrid to me.

    Comment


      #3
      Not a big fan of ListGrid in this case. Either way, I managed to figure it out.

      I added a hidden 'vehicles' item to the parent VehiclesForm and changed the type of the nested forms from NestedEditorItem to CanvasItem (DynamicForm is a subclass of Canvas). This way, the ValuesManager knows nothing of the nested forms but expects a "vehicles" item from the parent form. My subclass implementation of getValues() returns the proper "multiple" data structure and all is well on the server-side.

      Thanks,
      --mgbowman

      Comment

      Working...
      X