Fork me on GitHub

The grid system

The grid system of jquery.gridform aligns all elements in a table of rows and cells starting with the count of 1 at the upper left corner. So a grid system with four fields starting with 1_1 (first row, first cell) to 3_1 (third row, first cell) and a fourth field at 3_2 (third row, second cell) would be rendered like this:

This is rendered with the optional argument "showCellNames"

And then the same form with content:

For this to work, you just need to create a new gridform and pass some settings to it. At least a unique name and fields.

var t1 = $().gridform({
    /* unique name of the form */
    'name': 'form1', 
    /* fields of the form */
    'fields': {
        '1_1' : {
        	'id'        : 'login',
        	'label'     : 'Login',
        	'type'      : 'string',
        	'width'     : '150px'
        },
        '2_1' : {
        	'id'        : 'pwd',
        	'label'     : 'Password',
        	'type'      : 'string',
        	'pwd'       : true,
        	'width'     : '150px',
        	'maxLength' : 10,
        },
        '3_1' : {
        	'id'        : 'pwdRepeat',
        	'label'     : 'Password repeat',
        	'type'      : 'string',
        	'pwd'       : true,
        	'width'     : '150px',
        	'maxLength' : 10
        },
        '3_2' : {
        	'id'        : 'new',
        	'label'     : 'New user',
        	'type'      : 'boolean',
        	'width'     : '150px'
        },
    }
});
/* Render the form */
t1.render();
/* or (if you want to access it directly) */
gridform.forms['form1'].render();
 

Take more space: colspan and rowspan

Consider you need to build a more complex grid for a form. There you have a text field which should get more space (with rowspan), a headline (with cellspan) and a url string field (with cellspan) to cover the whole grid.

This is done by using the properties "colspan" and "rowspan" in the field definition (see the code example).


// Addes objects in the fields section of the settings
'1_1' : {
    'id'          : 'caption',
    'label'       : 'Caption',
    'type'        : 'headline',
    'colspan'     : 2   // span over 2 cells
},
'2_2' : {
    'id'          : 'new',
    'label'       : 'Description',
    'type'        : 'text',
    'width'       : '100%',
    'rowspan'     : 3, //span over 3 rows
    'placeholder' : 'has a rowspan of 3'
},
'5_1' : {
    'id'          : 'url',
    'label'       : 'Url',
    'type'        : 'string',
    'width'       : '100%',
    'colspan'     : 2, //span over 2 cells
    'placeholder' : 'has a colspan of 2'
},
...

Define size of content and labels

In the example above the available space of the table is split into equal parts for each cell. But maybe you want more space for the second cell (the textarea). Therefore you can use the property "dimension" of the settings. There you have the opportunity to control both the lenght of label and content of a cell.

...
'dimensions' : {
    'col_1' : {
        'labelWidth'   : '120px',
        'contentWidth' : "200px"
    },
    'col_2' : {
        'labelWidth'   : '80px'
    }
}
...

Field types

The filed types contained in the basic version of gridform are limited. There are now date or time fields, no colour pickers, etc. Due to the fact, that there are so many different excellent libs out there for doing that, I decided to let the user extend the fields very easily by themself. So these field types are built in:

...
// minimal definition of the field types
'1_1' : {
	'id' : 'string',
	'label' : 'string',
	'type' : 'string',
	'width' : '250px'
},
'2_1' : {
	'id' : 'pwd',
	'label' : 'pwd',
	'type' : 'string',
	'pwd' : true,
	'width' : '250px'
},
'3_1' : {
	'id' : 'text',
	'label' : 'text',
	'type' : 'text',
	'width' : '250px',
},
'4_1' : {
	'id' : 'select',
	'label' : 'select',
	'type' : 'select',
	'width' : '250px',
	'selection' : [{key : 1,value : 'first option'}, {key : 2,value : 'second option'}]
},
'5_1' : {
	'id' : 'checkbox',
	'label' : 'checkbox',
	'type' : 'checkbox',
	'selection' : [{key : 1,value : 'first option'}, { key : 2, value : 'second option'}]
},
'6_1' : {
	'id' : 'radio',
	'label' : 'radio',
	'type' : 'radio',
	'selection' : [{key : 1,value : 'first option'}, {key : 2,value : 'second option'}]
},
'7_1' : {
	'id' : 'boolean',
	'label' : 'boolean',
	'type' : 'boolean'
},
'8_1' : {
	'id' : 'headline',
	'label' : 'headline',
	'type' : 'headline'
},
'9_1' : {
	'id' : 'separator',
	'type' : 'separator'
},
...

Async load of choices for select

Selection fields, checboxes and radio buttons all need an attribute "selection" configured in their field definition. That's the list of choices for the element, as seen in the code above (e.g. the field 4_1). The select field is special here: instead of a fixed json object, you can define a function that return the list of choices. This can be used for compute the list at runtime or call a backend via async ajax call. The field knows if a function is called and will present a "loading-state" information to the user and lock the field until the selection data is available.

...
'1_1' : {
	'id' : 'select1',
	'label' : 'select with fixed choices',
	'type' : 'select',
	'width' : '250px',
	// fixed list
	'selection' : [{key : 1,value : 'first option'}, {key : 2,value : 'second option'}]
},
'2_1' : {
	'id' : 'select2',
	'label' : 'select with direct return function',
	'type' : 'select',
	'width' : '250px',
	'selection' : function (callback) {
		// generate some options at runtime
		var data = [];
		for (var x = 0; x < 100; x++) {
			data.push({	'key' : x,'value' : 'Option ' + x});
		}
		// call the backend and return the data
		callback(data);
	}
},
'3_1' : {
	'id' : 'select3',
	'label' : 'select with (fake) ajax function',
	'type' : 'select',
	'width' : '250px',
	'selection' : function (callback) {
		// here you can call the backend via ajax (to fake a longer response time here with a timeout)
		setTimeout(function () {
			// call the backend and return the data
			callback([{key : 1,value : 'first option'}, {key : 2,value : 'second option'}]);
		}, 2000);
	}
}
...  

Validation of fields

A form is most often used to fetch data from the user and validate it before send it to the server. You can configure a few options to every field type (except the visual types like headline and separator).

  • You can add the parameter "mandatory:true" to a field so that the field is at least validated to hold any content.
  • You can define a function "valdiate" that gets called with two parameters (value of the field and a callback) to return the boolean "true" or an error message. The error is shown in a tooltip when the mouse hovers the field.
  • You can add the parameter "hasFeedback:true" so a visual feedback of the valid status of the field is given to the user
  • If the field is mandatory or has a validate function then you can set the field setting "validateOnBlur:true" to add a blur event handler. This validates the field immediately when the focus is lost.
The default visual feedback is coloured red for errors, yellow for warnings and gray for success. If you want to have green visual feedback (for the whole form) add the parameter "successIsGreen: true" to the form settings (see the second form example).

If a validation function needs time (e.g. an ajax call to the server for validation), the field gets locked until the callback gets and validation answer.

...
// e.g. a field name with an validation function that 
// return true when the length is more than 4 characters
'fields' : {
	'1_1' : {
		'id'          : 'text',
		'label'       : 'text',
		'placeholder' : 'text',
		'type'        : 'string',
		'width'       : '150px',
		'hasFeedback' : false,
		'mandatory'   : true, // this is a mandatory field
		'validate'    : function (value, callback) {
			if (value.length > 6) {
				callback(true);
			} else {
				callback("Please more than 6 characters!");
			}
		}
	}
},
...

Set field states (error, warning or success) via code

If you need to set a state like warning, error or success to a field without doing a validation, you can do that by calling the "setStates"-function of the gridform. The state can be set like this:

  • gridformname.setError(<field id>,<error text>);
  • gridformname.setWarning(<field id>,<warning text>);
  • gridformname.setSuccess(<field id>);


lock/unlock fields or the whole form

You can lock single fields or the whole form by using the "lock"-function on the form object. You can also switch the render-mode between "view" and "edit" in the settings or by call the switchMode-function.

Currently the gridform renders the form equaly in both modes; the only difference is the locking state is true at all fields in the view mode.
If you want to have a complete different rendering output in view mode, you can overwrite all the fields render-methods or define own fields (more on that later).

...
// lock the field "login" (the example is bound to the form t9)
t9.enable(false,'login');
//unlock the field "login"
t9.enable(true,'login');
// lock the whole form
t9.enable(false);
// unlock the whole form
t9.enable(true);
// render/switch to view mode
t9.switchMode('view');
// render/switch to edit mode
t9.switchMode('edit');
...

Set data / get data

The main cause for using forms is creating and editing data (of course). Therefore you can use the "getData" and the "setData"-method of the gridform object. You can provide the setter function with a json-object and set all the data you want in one call. Just provide a key-value pair for every field you want to set. A checkbox field expects an array that contains the "checked" elements in a list.

  • Set data: gridformname.setData(<key-value-object>);
  • Get data: gridformname.getData(<key-value-object>);
  • Get all the data of the form: gridformname.getData();
...
// set data
t10.setData({'login':'loginname','pwd':'test1234','product':[1]});
// set checkbox data
t10.setData({'product':[1,2,3]});
// get the password data: returns a single string (or object with keys in case of a checkbox)
t10.getData('pwd');
// get the form data: returns a json object with all the data
t10.getData()
...

Label style

Labels can be positioned above the fields or left to them. Another style option is to align the label right or left in the surrounding cell. The possible settings for that are:

  • labelType = "inline|over"
  • labelAlign = "right|left"



Use FontAwesome for the checkboxes and radio inputs

Since there are so many great web-fonts out there in the wild, you can choose them for your grid icons or form controls (like checkboxes and radio buttons).

If you want to use e.g. FontAwesome you can set the attribute "useFontAwesome" to true and take a look at the result with nice checkboxes and radio buttons.



Use any webfont for status icons

You can define the icons for error, warning, success and waiting/loading status by overwriting the class names for these states in the settings. By default the grid uses glyphyicons for that. The icon settings are

  • icon_success
  • icon_error
  • icon_warning
  • icon_waiting
Take a look at this funny replacement with FontAwesome icons.

t14 = $().gridform({
    'name' : 'form14',
    'debug' : false,
    'successIsGreen' : true,
    'fields' : fields,
    //Icons for the status
    icon_success : 'fa fa-thumbs-o-up',
    icon_error : 'fa fa-bug',
    icon_warning : 'fa fa-info-circle',
    icon_waiting : 'fa fa-spinner fa-spin',
    'dimensions' : {
        'col_1' : {
            'labelWidth' : '120px',
            'contentWidth' : "200px"
        }
    }
});

Add event handlers to fields

You can easily attach any handler to a field, since you can get the basic element from the grid. Just call the function

  • gridformname.getElement(<id>);
and attach any event to it. Here is an example with a custom focus and blur handler.

// Example name
t15.render('#example15');
// get the element
var elem = t15.getElement("string");
// add a focus handler
elem.on("focus", function () {
    // set a warning when accessing the field
    t15.setWarning("string", "ups, custom focus handler");
}).on("blur", function () {
    // add a blur handler: directly validate the field
    console.log("This is a custom handler");
    t15.validate("string");
});

Add custom field types

There are only basic field types available (for a reason). But if you want to add your own field types, just add them right away.
Think of a date field, that is used with a javascript library like Zebra_Datepicker.

This is a standard date field with Zebra_Datepicker:

You can add a custom field by adding an json-object to the global object called "gridform". In the object you need at least a "render" function, that returns some HTML code. Here is a list of all the functions you can provide with your field:

  • setLabel: function (data, cellSelectorLabel, parent)
  • render the field content: render(data, cellSelector, parent)
  • set the field content: set(data, value, cellSelector, parent)
  • set a placeholder: setPlaceholder(data, value, cellSelector, parent)
  • get the field content: get(data, cellSelector)
  • flush the field: flush(cellSelector, parent)
  • enable/disable the field: enable(field, enable, cellSelector)
  • get the field, input, select, etc.: getFieldNode(field, cellSelector)
  • set the status of the field: setStatus(field, type, cellSelectorLabel, cellSelectorContent, parent)
  • set an error: setError(field, error, cellSelectorLabel, cellSelectorContent, parent)
  • set success: setSuccess(field, error, cellSelectorLabel, cellSelectorContent, parent)
  • set a warning: setWarning(field, error, cellSelectorLabel, cellSelectorContent, parent)
  • set waiting: setWaiting(field, message, cellSelectorLabel, cellSelectorContent, parent)
  • reset all the field markings: resetFieldMark(data, cellSelectorLabel, cellSelectorContent, parent)
  • method that gets called after the content was created and added to the DOM: afterDOMCreation(data, cellSelector, parent)

// Very simple custom date function
gridform.addType("date", {
    // a simple render function
    render : function (data, cellSelector, parent) {
        var disabled = (parent.settings.mode === "edit") ? '' : 'disabled';
        return '<input ' + disabled + ' type="text" class="form-control"></input>';
    },
    //at least lock/unlock the field
    enable : function (data, enable, cellSelector) {

        if (enable === true) {
            $(cellSelector).find("input").removeAttr("disabled");
        } else if (enable === false) {
            $(cellSelector).find("input").attr("disabled", "disabled");
        }
        // set the locked status in the DatePicker
        var elem = $(cellSelector).find("input");
        elem.Zebra_DatePicker();
    },
    // after the element is in the DOM
    afterDOMCreation : function (data, cellSelector, parent) {
        //add the date-picker
        var elem = $(cellSelector).find("input");
        elem.Zebra_DatePicker();
    },
    // get data from the field
    get : function (data, cellSelector) {
       return $(cellSelector).find("input").val();
    }    
});

// define the grid
t16 = $().gridform({
    'name' : 'form16',
    'debug' : false,
    'fields' : {
        '1_1' : {
            'id' : 'date',
            'label' : 'Date',
            'type' : 'date'
        }
    },
    'dimensions' : {
        'col_1' : {
            'labelWidth' : '120px',
            'contentWidth' : "200px"
        }
    }
});
// render the form
t16.render('#example16');

Full example

Just play around with (nearly) all the features in one form.

comments powered by Disqus