Adding Form Fields Dynamically with Knockout.js

A couple of years ago I did a post entitled Adding Form Fields Dynamically with jQuery.  In this post I am going to re-visit the same problem but this time use Knockout.js to create the dynamic form fields.

View The Demo

Introducing Knockout.js

Knockout.js is a Model-View-View-Model Javascript library. What it excels at is 'binding' data such as Javascript objects, arrays and JSON to your output HTML. To use Knockout.js take a trip to knockoutjs.com to view their excellent tutorials and documentation. To use it you need to either download the Knockout.js file or you can use a distributed version of the file by adding:

<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.1.0/knockout-min.js">
</script>

Data Binding

Knockout.js works by 'binding' your data model to your HTML output. The hook it uses for this are HTML's custom attributes. Primarily this is done by declaring a data-bind on a HTML element and then adding some knockout.js logic to it.

<div data-bind="someCommand">

Note: HTML attributes are part of the HTML5 specification but you can safely use in both newer HTML5 browsers as well as older ones.

In our example we are going to set up the HTML form as follows:

<form method="post">
<div data-bind="foreach: myFieldList">
  <p>
  <label data-bind="text: label"></label>
  <input data-bind="attr: { name: fname}">
  <span class="removeVar" data-bind="click: removeField">Remove Variable</span>
   </p>
</div>

<p>
<span id="addVar" data-bind="click: addField">Add Variable</span>
</p>

<p class="alignRight">
<input type="submit" value="Check">
</p>

</form>

Notice the use of the data-bind custom attribute to bind various Knockout.js commands to the HTML elements

The Javascript itself consists of:

function fieldModel(){
        var self = this;
	var noTracker = 3;
	self.myFieldList = ko.observableArray([{label : "Variable 1", fname : "var1"},{label : "Variable 2", fname : "var2"},{label : "Variable 3", fname : "var3"}]);

	self.removeField = function(dynamicField){
	    self.myFieldList.remove(dynamicField);
	}

	self.addField = function() {
	    noTracker++;
	    self.myFieldList.push({label : "Variable "+ noTracker, fname : "var"+ noTracker});
    	}
}
ko.applyBindings(fieldModel);

Primarily this is involved in creating a data model fieldModel with initial properties as well as a couple of methods removeField and addField. This is fundamentally 'vanilla' Javascript apart from ko.observableArray which is Knockout's extended version of an array that makes it easier to manipulate, and the ko.applyBindings(fieldModel); that 'binds' our data model to the HTML above.