DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • What Is SQL Injection and How Can It Be Avoided?
  • Non-blocking Database Migrations
  • Data Model Tracing and Reporting on a Relational Database
  • Introduction to Data Replication With MariaDB Using Docker Containers

Trending

  • Mastering Fluent Bit: Installing and Configuring Fluent Bit on Kubernetes (Part 3)
  • A Guide to Developing Large Language Models Part 1: Pretraining
  • Rethinking Recruitment: A Journey Through Hiring Practices
  • Fixing Common Oracle Database Problems
  1. DZone
  2. Data Engineering
  3. Big Data
  4. MVC CRUD Actions Using KnockoutJS

MVC CRUD Actions Using KnockoutJS

In this post, we'll walk you through a tutorial on how to create an MVC CRUD application using KnockoutJS in conjunction with an SQL database and Visual Studio.

By 
Sibeesh Venu user avatar
Sibeesh Venu
·
Mar. 13, 17 · Tutorial
Likes (10)
Comment
Save
Tweet
Share
22.8K Views

Join the DZone community and get the full member experience.

Join For Free

in this post, we are going to create an mvc crud application with the help of knockout js . we will be using sql database and visual studio for our development. if you are new to mvc, i strongly recommend you to read my previous post about mvc here . now let’s begin.

download the source code

  • mvc crud actions using knockoutjs
  • introduction to knockout js

    according to knockoutjs documentation , knockout is a javascript library that helps you to create rich, responsive display and editor user interfaces with a clean underlying data model. anytime you have sections of ui that update dynamically (e.g., change depending on the user’s actions or when an external data source changes), ko can help you implement it more simply and maintainable.

    it has benefits such as:

    • pure javascript library – works with any server or client-side technology.

    • can be added on top of your existing web application without requiring major architectural changes.

    • compact – around 13kb after gzipping.

    • works on any mainstream browser (ie 6+, firefox 2+, chrome, safari, edge, others).

    • a comprehensive suite of specifications (developed bdd-style) means its correct functioning can easily be verified on new browsers and platforms.

    background

    as i am working on a project which uses knockout for binding the server data, a friend of mine requested that i create a crud application with knockout, so that he can easily learn it. i just accepted his request and here we are going to create an mvc crud application with the help of knockout js. i hope you will like this.

    create an empty mvc application

    to get started we will create an empty mvc application as follows.

    image title

    add_new_empty_mvc_project

    creating a database and entity data model

    here i am creating a database with name “trialdb,” you can always create a db by running the query given below.

    use [master]
    go
    
    /****** object:  database [trialdb]    script date: 20-11-2016 03:54:53 pm ******/
    create database [trialdb]
     containment = none
     on  primary
    ( name = n'trialdb', filename = n'c:\program files\microsoft sql server\mssql13.sqlexpress\mssql\data\trialdb.mdf' , size = 8192kb , maxsize = unlimited, filegrowth = 65536kb )
     log on
    ( name = n'trialdb_log', filename = n'c:\program files\microsoft sql server\mssql13.sqlexpress\mssql\data\trialdb_log.ldf' , size = 8192kb , maxsize = 2048gb , filegrowth = 65536kb )
    go
    
    alter database [trialdb] set compatibility_level = 130
    go
    
    if (1 = fulltextserviceproperty('isfulltextinstalled'))
    begin
    exec [trialdb].[dbo].[sp_fulltext_database] @action = 'enable'
    end
    go
    
    alter database [trialdb] set ansi_null_default off
    go
    
    alter database [trialdb] set ansi_nulls off
    go
    
    alter database [trialdb] set ansi_padding off
    go
    
    alter database [trialdb] set ansi_warnings off
    go
    
    alter database [trialdb] set arithabort off
    go
    
    alter database [trialdb] set auto_close off
    go
    
    alter database [trialdb] set auto_shrink off
    go
    
    alter database [trialdb] set auto_update_statistics on
    go
    
    alter database [trialdb] set cursor_close_on_commit off
    go
    
    alter database [trialdb] set cursor_default  global
    go
    
    alter database [trialdb] set concat_null_yields_null off
    go
    
    alter database [trialdb] set numeric_roundabort off
    go
    
    alter database [trialdb] set quoted_identifier off
    go
    
    alter database [trialdb] set recursive_triggers off
    go
    
    alter database [trialdb] set  disable_broker 
    go
    
    alter database [trialdb] set auto_update_statistics_async off
    go
    
    alter database [trialdb] set date_correlation_optimization off
    go
    
    alter database [trialdb] set trustworthy off
    go
    
    alter database [trialdb] set allow_snapshot_isolation off
    go
    
    alter database [trialdb] set parameterization simple 
    go
    
    alter database [trialdb] set read_committed_snapshot off
    go
    
    alter database [trialdb] set honor_broker_priority off
    go
    
    alter database [trialdb] set recovery simple 
    go
    
    alter database [trialdb] set  multi_user 
    go
    
    alter database [trialdb] set page_verify checksum  
    go
    
    alter database [trialdb] set db_chaining off
    go
    
    alter database [trialdb] set filestream( non_transacted_access = off ) 
    go
    
    alter database [trialdb] set target_recovery_time = 60 seconds 
    go
    
    alter database [trialdb] set delayed_durability = disabled 
    go
    
    alter database [trialdb] set query_store = off
    go
    
    use [trialdb]
    go
    
    alter database scoped configuration set maxdop = 0;
    go
    
    alter database scoped configuration for secondary set maxdop = primary;
    go
    
    alter database scoped configuration set legacy_cardinality_estimation = off;
    go
    
    alter database scoped configuration for secondary set legacy_cardinality_estimation = primary;
    go
    
    alter database scoped configuration set parameter_sniffing = on;
    go
    
    alter database scoped configuration for secondary set parameter_sniffing = primary;
    go
    
    alter database scoped configuration set query_optimizer_hotfixes = off;
    go
    
    alter database scoped configuration for secondary set query_optimizer_hotfixes = primary;
    go
    
    alter database [trialdb] set  read_write 
    go


    create a table

    to create a table, you can run the query below.

    use [trialdb]
    go
    
    /****** object:  table [dbo].[course]    script date: 20-11-2016 03:57:30 pm ******/
    set ansi_nulls on
    go
    
    set quoted_identifier on
    go
    
    create table [dbo].[course](
        [courseid] [int] not null,
        [coursename] [nvarchar](50) not null,
        [coursedescription] [nvarchar](100) null,
     constraint [pk_course] primary key clustered 
    (
        [courseid] asc
    )with (pad_index = off, statistics_norecompute = off, ignore_dup_key = off, allow_row_locks = on, allow_page_locks = on) on [primary]
    ) on [primary]
    
    go


    so our database is ready. now we will create an entity data model with the database we created.

    image title

    create_entity_data_model

    install knockout js

    to install knockout js in your project, please right click on your project and click on manage nuget package, and search for ‘knockout.’

    image title

    install_knockout

    now let us start our coding as everything is set.

    c – create operation

    so we are going to see the create operation, as it comes first in crud. let us set up our controller first. you can see the controller code for create operation here.

    // get: home/create
           public actionresult create()
           {
               return view();
           }
    
           // post: home/create
           [httppost]
           public string create(course course)
           {
               if (!modelstate.isvalid) return "model is invalid";
               _db.courses.add(course);
               _db.savechanges();
               return "cource is created";
           }


    here, the first action calls the view for the create operation and the second operation inserts the data into the database. and _db is our entity.

     private readonly trialdbentities _db = new trialdbentities(); 

    now let’s go ahead and create a view for the create operation.

    @model mvccrudknockout.models.course
    
    @{
        viewbag.title = "create";
    }
    
    <div class="form-horizontal">
        <h4>course</h4>
        <hr>
    
        <div class="form-group">
            <label class="control-label col-md-2" for="coursename">coursename</label>
            <div class="col-md-10">
                <input class="form-control text-box single-line" id="coursename" name="coursename" type="text" value="" data-bind="value: coursename">
            </div>
        </div>
    
        <div class="form-group">
            <label class="control-label col-md-2" for="coursedescription">coursedescription</label>
            <div class="col-md-10">
                <input class="form-control text-box single-line" id="coursedescription" name="coursedescription" type="text" value="" data-bind="value: coursedescription">
            </div>
        </div>
    
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="button" data-bind="click: createcourse" value="create" class="btn btn-default">
            </div>
        </div>
    </div>
    
    <div>
        @html.actionlink("back to list", "read")
    </div>
    <script src="~/scripts/jquery-1.10.2.min.js"></script>
    <script src="~/scripts/knockout-3.4.0.js"></script>
    <script src="~/scripts/koscripts/kocreate.js"></script>


    did you notice that we are binding data to our input controls as data-bind=”value: coursename” ? this value is related to the view model we are going to set. the interesting thing about this is, the values in the model will get changed as you change the values in the input. you don’t need to add any kind of code for that operation.

    lastly, we bind a click event as follows:

     <input type="button" data-bind="click: createcourse" value="create" class="btn btn-default"> 

    this will call the function createcourse which we are going to specify in our view model. now you may be thinking, 'what is this view model?' this knockout uses an mvvm pattern and now lets us read some basic information provided in the knockout js documentation .

    mvvm and view models

    model-view-view model (mvvm) is a design pattern for building user interfaces. it describes how you can keep a potentially sophisticated ui simple by splitting it into three parts:

    1. a model : your application’s stored data. this data represents objects and operations in your business domain (e.g., bank accounts that can perform money transfers) and is independent of any ui. when using ko, you will usually make ajax calls to some server-side code to read and write this stored model data.

    2. a view model : a pure-code representation of the data and operations on a ui. for example, if you’re implementing a list editor, your view model would be an object holding a list of items and exposing methods to add and remove items. note that this is not the ui itself: it doesn’t have any concept of buttons or display styles. it’s not the persisted data model either – it holds the unsaved data the user is working with. when using ko, your view models are pure javascript objects that hold no knowledge of html. keeping the view model abstract in this way lets it stay simple, so you can manage more sophisticated behaviors without getting lost.

    3. a view : a visible, interactive ui representing the state of the view model. it displays information from the view model, sends commands to the view model (e.g., when the user clicks buttons), and updates whenever the state of the view model changes.

    when using ko, your view is simply your html document with declarative bindings to link it to the view model. alternatively, you can use templates that generate html using data from your view model.

    now back to our create operation: kocreate.js is the file in which we are going to write our operation. now please open that file and bind view model as follows:

    $(function () {
        ko.applybindings(modelcreate);
    });


    image title

    knockout_apply_bindings

    now, the following is our view model and associated functions:

    var modelcreate = {
        coursename: ko.observable(),
        coursedescription: ko.observable(),
        createcourse: function () {
            try {
                $.ajax({
                    url: '/home/create',
                    type: 'post',
                    datatype: 'json',
                    data: ko.tojson(this), //here the data wil be converted to json
                    contenttype: 'application/json',
                    success: successcallback,
                    error: errorcallback
                });
            } catch (e) {
                window.location.href = '/home/read/';
            }
        }
    };
    
    function successcallback(data) {
        window.location.href = '/home/read/';
    }
    function errorcallback(err) {
        window.location.href = '/home/read/';
    }


    here ko.observable() are special objects which can notify the changes and update the model accordingly. so if you need to update your ui automatically when the view model changes, you can use observable() . now please run your view and check whether it is working fine.

    image title


    create_page

    r – read operation

    as we have completed our create operation, now it is time for read. please open your controller and write the actions as follows:

    // get: home
            public actionresult read()
            {
                return view();
            }
    
            //get all courses
            public jsonresult listcourses()
            {
                return json(_db.courses.tolist(), jsonrequestbehavior.allowget);
            }


    you can create your read view as follows:

    @{
        viewbag.title = "read";
    }
    
    <h2>index</h2>
    
    <p>
        @html.actionlink("create new", "create")
    </p>
    <table class="table">
        <tr>
            <th>
                course name
            </th>
            <th>
                course description
            </th>
            <th></th>
        </tr>
        <tbody data-bind="foreach: courses">
        <tr>
            <td data-bind="text: coursename"></td>
            <td data-bind="text: coursedescription"></td>
            <td>
                <a data-bind="attr: { 'href': '@url.action("edit", "home")/' + courseid }" class="btn-link">edit</a>
                <a data-bind="attr: { 'href': '@url.action("delete", "home")/' + courseid }" class="btn-link">delete</a>
            </td>
        </tr>
        </tbody>
    </table>
    <script src="~/scripts/jquery-1.10.2.min.js"></script>
    <script src="~/scripts/knockout-3.4.0.js"></script>
    <script src="~/scripts/koscripts/koread.js"></script>
    here we are using data-bind=”foreach: courses” for looping through our model we are going to create 


    here we are using data-bind=”foreach: courses” for looping through our model that we are going to create now. so shall we do that? please create a js file with name koread.js and add the following code:

    $(function () {
        ko.applybindings(modelview);
        modelview.viewcourses();
    });
    
    var modelview = {
        courses: ko.observablearray([]),
        viewcourses: function () {
            var thisobj = this;
            try {
                $.ajax({
                    url: '/home/listcourses',
                    type: 'get',
                    datatype: 'json',
                    contenttype: 'application/json',
                    success: function (data) {
                        thisobj.courses(data); //here we are assigning values to ko observable array
                    },
                    error: function (err) {
                        alert(err.status + " : " + err.statustext);
                    }
                });
            } catch (e) {
                window.location.href = '/home/read/';
            }
        }
    };


    here goes the output:

    image title

    read_page

    now, it is time for the update operation. are you ready?

    u – update operation

    as we did for the above two operations, let us create some actions in our controller first.

    // get: home/edit/5
            public actionresult edit(int? id)
            {
                if (id == null)
                    return new httpstatuscoderesult(httpstatuscode.badrequest);
                var course = _db.courses.find(id);
                if (course == null)
                    return httpnotfound();
                var serializer = new javascriptserializer();
                viewbag.selectedcourse = serializer.serialize(course);
                return view();
            }
    
            // post: home/update/5
            [httppost]
            public string update(course course)
            {
                if (!modelstate.isvalid) return "invalid model";
                _db.entry(course).state = entitystate.modified;
                _db.savechanges();
                return "updated successfully";
            }


    here, the first action with parameter id is called whenever a user clicks on the edit link from the table we created. and we are setting the queried data to viewbag so that we can use it for our related operation. for now, we can create a view as follows:

    @{
        viewbag.title = "edit";
    }
    
    <h2>edit</h2>
    
    
    @using (html.beginform())
    {
        @html.antiforgerytoken()
    
        <div class="form-horizontal">
            <h4>course</h4>
    
            <div class="form-group">
                <label class="control-label col-md-2" for="coursename">coursename</label>
                <div class="col-md-10">
                    <input class="form-control text-box single-line" id="coursename" name="coursename" type="text" value="" data-bind="value: coursename">
                </div>
            </div>
    
            <div class="form-group">
                <label class="control-label col-md-2" for="coursedescription">coursedescription</label>
                <div class="col-md-10">
                    <input class="form-control text-box single-line" id="coursedescription" name="coursedescription" type="text" value="" data-bind="value: coursedescription">
                </div>
            </div>
    
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="button" data-bind="click: updatecourse" value="update" class="btn btn-default">
                </div>
            </div>
        </div>
    }
    <script type="text/javascript">
        var selectedcourse = '@html.raw(viewbag.selectedcourse)';
    </script>
    <div>
        @html.actionlink("back to list", "read")
    </div>
    <script src="~/scripts/jquery-1.10.2.min.js"></script>
    <script src="~/scripts/knockout-3.4.0.js"></script>
    <script src="~/scripts/koscripts/koupdate.js"></script>


    and create a js with name koupdate.js and add the following code:

    var parsedselectedcourse = $.parsejson(selectedcourse);
    $(function () {
        ko.applybindings(modelupdate);
    });
    
    var modelupdate = {
        courseid: ko.observable(parsedselectedcourse.courseid),
        coursename: ko.observable(parsedselectedcourse.coursename),
        coursedescription: ko.observable(parsedselectedcourse.coursedescription),
        updatecourse: function () {
            try {
                $.ajax({
                    url: '/home/update',
                    type: 'post',
                    datatype: 'json',
                    data: ko.tojson(this),
                    contenttype: 'application/json',
                    success: successcallback,
                    error: errorcallback
                });
            } catch (e) {
                window.location.href = '/home/read/';
            }
        }
    };
    
    function successcallback(data) {
        window.location.href = '/home/read/';
    }
    function errorcallback(err) {
        window.location.href = '/home/read/';
    }


    now, run your application and see the edit/update operation.

    image title

    edit_page

    d – delete operation

    so our last operation, delete. let’s edit our controller as follows:

    // get: home/delete/5
            public actionresult delete(int? id)
            {
                if (id == null)
                    return new httpstatuscoderesult(httpstatuscode.badrequest);
                var course = _db.courses.find(id);
                if (course == null)
                    return httpnotfound();
                var serializer = new javascriptserializer();
                viewbag.selectedcourse = serializer.serialize(course);
                return view();
            }
    
            // post: home/delete/5
            [httppost, actionname("delete")]
            public string delete(course course)
            {
                if (course == null) return "invalid data";
                var getcourse = _db.courses.find(course.courseid);
                _db.courses.remove(getcourse);
                _db.savechanges();
                return "deleted successfully";
            }


    the code looks exactly same as our update operation, so no explanation. still, if you get any issues, please ask. now let us create our view.

    @model mvccrudknockout.models.course
    
    @{
        viewbag.title = "delete";
    }
    
    <h2>delete</h2>
    
    <h3>are you sure you want to delete this?</h3>
    @using (html.beginform())
    {
        @html.antiforgerytoken()
    
        <div class="form-horizontal">
            <h4>course</h4>
    
            <div class="form-group">
                <label class="control-label col-md-2" for="coursename">coursename</label>
                <div class="col-md-10">
                    <input class="form-control text-box single-line" id="coursename" name="coursename" type="text" value="" data-bind="value: coursename">
                </div>
            </div>
    
            <div class="form-group">
                <label class="control-label col-md-2" for="coursedescription">coursedescription</label>
                <div class="col-md-10">
                    <input class="form-control text-box single-line" id="coursedescription" name="coursedescription" type="text" value="" data-bind="value: coursedescription">
                </div>
            </div>
    
            <div class="form-group">
                <div class="col-md-offset-2 col-md-10">
                    <input type="button" data-bind="click: deletecourse" value="delete" class="btn btn-default">
                </div>
            </div>
        </div>
    }
    <script type="text/javascript">
        var selectedcourse = '@html.raw(viewbag.selectedcourse)';
    </script>
    <div>
        @html.actionlink("back to list", "read")
    </div>
    <script src="~/scripts/jquery-1.10.2.min.js"></script>
    <script src="~/scripts/knockout-3.4.0.js"></script>
    <script src="~/scripts/koscripts/kodelete.js"></script>


    and you can always create our knockout codes as follows:

    ar parsedselectedcourse = $.parsejson(selectedcourse);
    $(function () {
        ko.applybindings(modeldelete);
    });
    
    var modeldelete = {
        courseid: ko.observable(parsedselectedcourse.courseid),
        coursename: ko.observable(parsedselectedcourse.coursename),
        coursedescription: ko.observable(parsedselectedcourse.coursedescription),
        deletecourse: function () {
            try {
                $.ajax({
                    url: '/home/delete',
                    type: 'post',
                    datatype: 'json',
                    data: ko.tojson(this),
                    contenttype: 'application/json',
                    success: successcallback,
                    error: errorcallback
                });
            } catch (e) {
                window.location.href = '/home/read/';
            }
        }
    };
    
    function successcallback(data) {
        window.location.href = '/home/read/';
    }
    function errorcallback(err) {
        window.location.href = '/home/read/';
    }


    if everything goes fine, you will get a page as follows:

    image title

    delete_page

    that’s all for today. you can always download the source code attached to see the complete code and application. happy coding!

    references

  • knockout js
  • knockout js observables
  • see also

  • external links and tutorials
  • conclusion

    did i miss anything that you may think is needed? did you find this post as useful? i hope you liked this article. please share me your valuable suggestions and feedback.

    Database View model Data (computing) Web application Knockout (web framework) Data model (GIS) JavaScript library

    Published at DZone with permission of Sibeesh Venu, DZone MVB. See the original article here.

    Opinions expressed by DZone contributors are their own.

    Related

    • What Is SQL Injection and How Can It Be Avoided?
    • Non-blocking Database Migrations
    • Data Model Tracing and Reporting on a Relational Database
    • Introduction to Data Replication With MariaDB Using Docker Containers

    Partner Resources

    ×

    Comments
    Oops! Something Went Wrong

    The likes didn't load as expected. Please refresh the page and try again.

    ABOUT US

    • About DZone
    • Support and feedback
    • Community research
    • Sitemap

    ADVERTISE

    • Advertise with DZone

    CONTRIBUTE ON DZONE

    • Article Submission Guidelines
    • Become a Contributor
    • Core Program
    • Visit the Writers' Zone

    LEGAL

    • Terms of Service
    • Privacy Policy

    CONTACT US

    • 3343 Perimeter Hill Drive
    • Suite 100
    • Nashville, TN 37211
    • support@dzone.com

    Let's be friends:

    Likes
    There are no likes...yet! 👀
    Be the first to like this post!
    It looks like you're not logged in.
    Sign in to see who liked this post!