Tuesday 24 February 2015

CRUD & Validation in Knockout Grid

In this article we will see how to create a dynamic grid using knockout js and how to add a row wise validation by using knockout validation. We also look how add, insert and delete a row in a grid.

What we will achieve at final:

1)      Dynamically adding and inserting a row in grid and also deletion of row from grid.

2)      Validation by using Knockout Validation api.

3)      Generating  json of records.

Our final output should be something like below:

1)      If you click on Insert, it will add new record above the selected row likewise excels.

2)      If you click on Add New Row, it will add new row at the bottom of the grid.

3)      Now when you press Save it will validate all the row and notify by highlighting the border of the controls and if all the data validation is success it will generate json for you.

Now follow me step by step to achieve the above output:

1)      Reference the following script files:

a)      Jquery

b)      Knockoutjs

c)       Knockout validation

d)      Bootstrap (optional)

 

    <script src="Scripts/jquery-2.1.3.min.js" type="text/javascript"></script>

    <script src="Scripts/knockout-3.2.0.js" type="text/javascript"></script>

    <script src="Scripts/knockout.validation.min.js" type="text/javascript"></script>

    <link href="Content/bootstrap.min.css" rel="stylesheet" type="text/css" />

 

2)      Add this style part for highlighting the border of controls in case of validation failed:

<style>

            .required-field

            {

                border:2px solid red;

            }

    </style>

 

3)      Now create a script file or script section in a page and replace the script with the below given script:

<script>

 

        $(function () {

            var vm = function () {

 

                var self = this;

 

                // contains the list of row

                self.list = ko.observableArray();

 

                // for identifying the current added or inserted row

                self.current = ko.observable();

 

                // contains the list of countries

                self.countries = ko.observableArray([{

                        id: 1,

                        name: "India"

                    },{

                        id: 2,

                        name: "Australlia"

                    }

                ]);

 

                // contains the list of states

                self.states = ko.observableArray([{

                        id: 1,

                        countryid: 1,

                        name: "Uttar Pradesh"

                    },{

                        id: 2,

                        countryid: 1,

                        name: "Delhi"

                    },{

                        id: 3,

                        countryid: 2,

                        name: "Sydney"

                    },{

                        id: 4,

                        countryid: 2,

                        name: "Melbourne"

                    }

                ]);

 

                // will set when error need to show

                self.showErrors = ko.observable(false);

 

                // function for adding a new row in a table

                self.addRow = function(order) {

                   

                    var obj = {

                        Order: ko.observable(order),

                        FirstName:  ko.observable().extend({ required: true }),

                        LastName: ko.observable().extend({ required: true }),

                        Country: ko.observable().extend({ required: true }),

                        State: ko.observable().extend({ required: true }),

                        ContactNo: ko.observable().extend({ required: true }),

                        Designation: ko.observable().extend({ required: true }),

                        Countries: self.countries()

                    };

 

                    // return list of errors from an object

                    obj.errors = ko.validation.group(obj);

 

                    // display an error for each fields of an object

                    obj.showerror = function (item) {

                       

                        if (!item.isValid() && obj.showErrors()) {

                            return true;

                        }

                        else {

                            return false;

                        }

                    };

 

                    // computed function return filtered stated on the basis of country choosen

                    obj.States = ko.computed(function() {

 

                        if(obj.Country()) {

                           

                           var list = ko.utils.arrayFilter(self.states(), function(item) {

                           

                                return (item.countryid == obj.Country());

                           });

 

                           return list;

                        }

 

                        return [];

                    });

 

                    self.list.push(obj);

                    self.current(obj);

                };

 

                //calls on click of Add New Row

                self.addNew = function () {

 

                    self.addRow((self.list().length + 1));

                }

 

                //calls on click of Insert

                self.insert = function (obj) {

                   

                    self.addRow(obj.Order());

 

                    // arranging list after inserting row in between of a grid

                    obj.Order(obj.Order() + 1);

 

                    $.each(self.list(), function(i, item) {

                       

                        if(item.Order() >= obj.Order() && obj != item) {

                          

                            item.Order(item.Order() + 1);

                        }

                    });

                };

 

                // calls on click of Delete

                self.delete = function (obj) {

                   

                    self.list.remove(obj);

 

                    // arranging list after deleting row from in between of a grid

                    $.each(self.list(), function(i, item) {

                       

                        if(item.Order() >= obj.Order()) {

                          

                            item.Order(item.Order() - 1);

                        }

                    });

                };

 

                // return sorted list on the basis of Order field

                self.sortedlist = ko.computed(function() {

                   return self.list().sort(function (left, right) {

                        return left.Order() == right.Order() ? 0 : left.Order() < right.Order() ? -1 : 1

                    });

                });

 

                // calls on click of save

                self.save = function() {

                   

                    var isValid = true;

                    self.showErrors(true);

 

                    $.each(self.list(), function(i, item) {

                      

                        if(item.errors().length > 0) {

                            isValid = false;

                        }

                    });

 

                    if(isValid) {

                        //generating json of records

                        alert(ko.toJSON(self.sortedlist));

                    }

                    else {

                        //setting focus in required field

                        $(".required-field").first().focus();

                    }

                };

            };

 

            //initializing knockout validation

            ko.validation.init({

               

                registerExtenders: true,

                messagesOnModified: true,

                insertMessages: false

            });

 

            var viewModel = new vm();

            ko.applyBindings(viewModel);

        });

 

    </script>

 

I had explained a use of every object and function by commenting above of each. Please read it, I hope u got it easily.

4)      Now in the body section of html create a table and a paragraph by using following script:

    <table class="table table-bordered">

        <thead>

            <tr>

                <th>

                    S. No.

                </th>

                <th>

                    First Name

                </th>

                <th>

                    Last Name

                </th>

                <th>

                    Country

                </th>

                <th>

                    State

                </th>

                <th>

                    Contact No

                </th>

                <th>

                    Designation

                </th>

                <th>

                </th>

            </tr>

        </thead>

        <tbody data-bind="foreach: { data: sortedlist, as: 'row' }">

            <tr data-bind="style: { backgroundColor: row == $parent.current() ? '#E5E5E5': '' }">

                <td data-bind="text:Order">

                </td>

                <td>

                    <input type="text" data-bind="value:FirstName, css:{'required-field':row.showerror(row.FirstName)}, valueUpdate: 'afterkeydown'" />

                </td>

                <td>

                    <input type="text" data-bind="value:LastName, css:{'required-field':row.showerror(row.LastName)}" />

                </td>

                <td>

                    <select data-bind="options:Countries,

                                       optionsText: 'name',

                                       optionsValue: 'id',

                                       value:Country,

                                       optionsCaption: '--Select Country--',

                                       css:{'required-field':row.showerror(row.Country)}">

                    </select>

                </td>

                <td>

                    <select type="text" data-bind="options:States,

                                                   optionsText: 'name',

                                                   optionsValue: 'id',

                                                   value: State,

                                                   optionsCaption: '--Select State--',

                                                   css:{'required-field':row.showerror(row.State)}">

                    </select>

                </td>

                <td>

                    <input type="text" data-bind="value:ContactNo,css:{'required-field':row.showerror(row.ContactNo)}" />

                </td>

                <td>

                    <input type="text" data-bind="value:Designation,css:{'required-field':row.showerror(row.Designation)}" />

                </td>

                <td>

                    <input type="button" data-bind="event: { click: $parent.insert }" value="Insert" />

                    <input type="button" data-bind="event: { click: $parent.delete }" value="Delete" />

                </td>

            </tr>

        </tbody>

        <tfoot>

            <tr>

                <td colspan="8" align="right">

                    <input type="button" data-bind="event: { click: addNew }" value="Add New Row" />

                </td>

            </tr>

        </tfoot>

    </table>

    <p class="text-right col-md-12">

        <input type="submit" data-bind="event: { click: save }" value="Save" />

    </p>

 

Now you can browse the page and see the output. I hope it will give same output as I shown in above two screenshots.

Thanks for reading this article. If you have any doubts or suggestion, please enter by using comment box.

No comments: