Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Single Page Application Using ASP.NET MVC And jQuery With CRUD methods

0.00/5 (No votes)
10 Jun 2018 2  
In this article, I explain you how to implement single page application using asp.net mvc, jquery and sammy.js

Introduction

In this article, I will tell you how to create a single page application using ASP.NET MVC and jQuery. Without using Angular, React, and other third-party JavaScripts, it is difficult to achieve SPA. In this article, I will explain only controller and UI level interaction. I skipped the data access layer. If you want, please download the attachment which includes the overall code of the application.

Note - I used code first approach for CRUD operations. After downloading the project file, restore packages and change the connection string web.config and run the update-database command in Package Manager Console.

Background

Required Contents

  • ASP.NET MVC
  • JQUERY
  • Sammy.JS (for Routing)

Using the code

Create a new MVC project.

Add jQuery and Sammy.js reference to your layout page. Add div tag (MainContent) in which we render all the partial views.

<head>  
    <meta charset="utf-8" />  
    <meta name="viewport" content="width=device-width, initial-scale=1.0">  
    <title>@ViewBag.Title - My ASP.NET Application</title>  
    @Styles.Render("~/Content/css")  
    @Scripts.Render("~/bundles/modernizr")  
    <script src="~/Scripts/jquery-1.10.2.js"></script>  
    <script src="~/Scripts/sammy-0.7.4.js"></script>  
</head>  

Create layout-routing.js file in your project which contains your application routing structure which is shown as below.

var mainContent;  
var titleContent;  
  
$(function () {  
    mainContent = $("#MainContent"); /// render partial views.  
    titleContent = $("title"); // render titles.  
});  
  
var routingApp = $.sammy("#MainContent", function () {  
    this.get("#/Student/Index", function (context) {  
        titleContent.html("Student Page");  
        $.get("/Student/Index", function (data) {  
            context.$element().html(data);  
        });  
    });  
  
    this.get("#/Student/Add", function (context) {  
        titleContent.html("Add Student");  
        //$("#BigLoader").modal('show'); // If you want to show loader  
        $.get("/Student/Add", function (data) {  
            //$("#BigLoader").modal('hide');  
            context.$element().html(data);  
        });  
    });  
  
    this.get("#/Student/Edit", function (context) {  
        titleContent.html("Edit Student");  
        $.get("/Student/Edit", {  
            studentID: context.params.id // pass student id  
        }, function (data) {  
            context.$element().html(data);  
        });  
    });  
  
    this.get("#/Home/About", function (context) {  
        titleContent.html("About");  
        $.get("/Home/About", function (data) {  
            context.$element().html(data);  
        });  
    });  
  
    this.get("#/Home/Contact", function (context) {  
        titleContent.html("Contact");  
        $.get("/Home/Contact", function (data) {  
            context.$element().html(data);  
        });  
    });  
});  
  
$(function () {  
    routingApp.run("#/Student/Index"); // default routing page.  
});  
  
function IfLinkNotExist(type, path) {  
    if (!(type != null && path != null))  
        return false;  
  
    var isExist = true;  
  
    if (type.toLowerCase() == "get") {  
        if (routingApp.routes.get != undefined) {  
            $.map(routingApp.routes.get, function (item) {  
                if (item.path.toString().replace("/#", "#").replace(/\\/g, '').replace("$/", "").indexOf(path) >= 0) {  
                    isExist = false;  
                }  
            });  
        }  
    } else if (type.toLowerCase() == "post") {  
        if (routingApp.routes.post != undefined) {  
            $.map(routingApp.routes.post, function (item) {  
                if (item.path.toString().replace("/#", "#").replace(/\\/g, '').replace("$/", "").indexOf(path) >= 0) {  
                    isExist = false;  
                }  
            });  
        }  
    }  
    return isExist;  
}  

IfLinkNotExist() check if url should not repeat, after we will add dynamic url in routing list on page load.

Add layout-routing reference in _layout.cshtml page.

<script src="~/layout-routing.js"></script>  
    @*@Scripts.Render("~/bundles/jquery")*@  
    @Scripts.Render("~/bundles/bootstrap")  
    @RenderSection("scripts", required: false)  

Add a new controller ‘WelcomeController’ which has only one action ‘Index’.

namespace MvcSpaDemo.Controllers  
{  
    public class WelcomeController : Controller  
    {  
        public ActionResult Index()  
        {  
            return View();  
        }  
    }  
}

Create the View of ‘Index’ action using right-click.

In that View, attach the layout page link. (We need to render the layout page for the first time).

@{  
    ViewBag.Title = "Index";  
    Layout = "~/Views/Shared/_Layout.cshtml";  
}  
  
<h1>Welcome</h1>  

Now, create student Controller which includes student CRUD operation modules. (Add, update, delete, View).

View Students

public ActionResult Index()  
 {  
     return PartialView();  
 }  
  
 public ActionResult _Index()  
 {  
     var students = StudentData.GetStudents();  
     return PartialView(students);  
  } 

Add two Views without layout page. One for outer student contents like header, add button, etc. and another for student table.

Index.cshtml 

@{  
    Layout = null;  
}  
  
<h4>Students</h4>  
  
<div class="row">  
    <a href="#/Student/Add">Add Student</a>  
</div>  
  
<div class="row">  
    <div id="StudentDiv">  
    </div>  
</div>  
  
<script>  
    $(function () {  
        GetStudents();  
    });  
  
    function GetStudents() {  
        $.get("/Student/_Index/", function (data) {  
            $("#StudentDiv").html(data);  
        });  
    }  
  
    function DeleteStudent(studentID) {  
        if (confirm("Delete student?")) {  
            $.get("/Student/Delete/", { studentID: studentID }, function (data) {  
                GetStudents();  
            });  
        }  
    }  
</script>  

_Index.cshtml

@model IEnumerable<MvcSpaDemo.Entities.Student>  
@{  
    Layout = null;  
}  
  
<table class="table table-striped table-bordered">  
    <thead>  
        <tr>  
            <th>ID</th>  
            <th>Name</th>  
            <th>Email</th>  
            <th>Class</th>  
            <th>Action</th>  
        </tr>  
    </thead>  
    <tbody>  
        @foreach (var item in Model)  
        {  
            <tr>  
                <td>@item.StudentID</td>  
                <td>@item.FirstName @item.LastName</td>  
                <td>@item.Email</td>  
                <td>@item.Class</td>  
                <td>  
                    <a href="#/Student/Edit?id=@item.StudentID">Edit</a>  
                    <a href="javascript::;" onclick="DeleteStudent('@item.StudentID')">Delete</a>  
                </td>  
            </tr>  
        }  
    </tbody>  
</table>  

Change the default controller and action in RouteConfig.cs.

public class RouteConfig  
    {  
        public static void RegisterRoutes(RouteCollection routes)  
        {  
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");  
  
            routes.MapRoute(  
                name: "Default",  
                url: "{controller}/{action}/{id}",  
                defaults: new { controller = "Welcome", action = "Index", id = UrlParameter.Optional }  
            );  
        }  
    }  

Run the application using F5. Do the same routing for About and Contact page also.

Add Student asd 

Now, add "Create Student Actions" in Controller.

public ActionResult Add()  
        {  
            var student = new Student();  
            ViewBag.Status = "Add";  
            return PartialView(student);  
        }  
  
        [HttpPost]  
        public ActionResult Create(Student student)  
        {  
            StudentData.AddStudent(student);  
            return Json(true, JsonRequestBehavior.AllowGet);  
        }  

We will add the add page with dynamic routing script for create or update.

@model MvcSpaDemo.Entities.Student  
@{  
    ViewBag.Title = "Add";  
    Layout = null;  
  
    // We use same page for add and edit.  
    var urlPostString = "/Student/Create";  
    if (ViewBag.Status == "Edit")  
    {  
        urlPostString = "/Student/Update";  
    }  
}  
  
<h2>@ViewBag.Status Student</h2>  
  
<form id="frmStudent" name="frmStudent" method="post" action="#@urlPostString">  
    @Html.HiddenFor(x => x.StudentID)  
    <div class="row">  
        <div class="form-group">  
            <label for="Variables">First Name</label>  
            @Html.TextBoxFor(x => x.FirstName, new { @class = "form-control square" })  
        </div>  
        <div class="form-group">  
            <label for="Variables">Last Name</label>  
            @Html.TextBoxFor(x => x.LastName, new { @class = "form-control square" })  
        </div>  
        <div class="form-group">  
            <label for="Variables">Email</label>  
            @Html.TextBoxFor(x => x.Email, new { @class = "form-control square" })  
        </div>  
        <div class="form-group">  
            <label for="Variables">Class</label>  
            @Html.TextBoxFor(x => x.Class, new { @class = "form-control square" })  
        </div>  
        <div class="form-group">  
            <input type="submit" class="btn btn-primary" value="Submit" />  
        </div>  
    </div>  
</form>  
  
<script>  
    $("#frmStudent").on("submit", function (e) {  
        debugger;  
        //if ($("#frmStudent").valid()) {  
        routingApp.runRoute('post', '#@urlPostString');  
        e.preventDefault();  
        e.stopPropagation();  
        //}  
    });  
  
    // add dynamic create or update link  
  
    debugger;  
    if (IfLinkNotExist("POST", "#@urlPostString")) {  
        routingApp.post("#@urlPostString", function (context) {  
            //$("#BigLoader").modal('show');  
            var formData = new FormData($('#frmStudent')[0]);  
            $.ajax({  
                url: '@urlPostString',  
                data: formData,  
                type: "POST",  
                contentType: false,  
                processData: false,  
                success: function (data) {  
                    //$("#BigLoader").modal('hide');  
                    if (data) {  
                        if ('@ViewBag.Status' == 'Add')  
                            alert("Student successfully added");  
                        else if ('@ViewBag.Status' == 'Edit')  
                            alert("Student successfully updated");  
                        window.location.href = "#/Student/Index";  
                    }  
                    else {  
                        alert('Something went wrong');  
                    }  
                },  
                error: function () {  
                    alert('Something went wrong');  
                }  
            });  
        });  
    }  
  
</script>  

Now, run the application.

Edit Student

Now, move on to Edit Module. Add Edit actions in Controller.

public ActionResult Edit(int studentID) // studentID nothing but parameter name which we pass in layout-routing.  
        {  
            var student = StudentData.GetStudentById(studentID);  
            ViewBag.Status = "Edit";  
            return PartialView("Add", student);  
        }  
  
        [HttpPost]  
        public ActionResult Update(Student student)  
        {  
            StudentData.UpdateStudent(student);  
            return Json(true, JsonRequestBehavior.AllowGet);  
        }  

We used the same partial view for add and edit, so there  is no need to create a new View for edit. 

After adding the action methods, just run the application.

Delete Student 

Now, we will implement the Delete operation.

We have already written Delete button's code in Student Index.cshtml.

function GetStudents() {  
        $.get("/Student/_Index/", function (data) {  
            $("#StudentDiv").html(data);  
        });  
    }  
  
    function DeleteStudent(studentID) {  
        if (confirm("Delete student?")) {  
            $.get("/Student/Delete/", { studentID: studentID }, function (data) {  
                GetStudents();  
            });  
        }  
    }  

Run the application.

I hope you have enjoyed this article. Your valuable feedback, questions, or comments about this article are always welcome.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here