How to create Master Detail entry form in asp.net MVC4



 How to create Master Detail entry form in asp.net MVC4

Introduction

In one of the previous article, I have explained how to show master-details data in asp.net MVC application with collapse / expand option and also I have explained how we can show master-details data in report viewer control in asp.net webform application. But Sometimes we need to create master details entry form in the single page, like Order and order details. Here we will see, how we can create master details entry form in a single page in asp.net MVC application.

Steps :

Step - 1 : Create New Project.

Go to File > New > Project > Select asp.net MVC4 web application > Entry Application Name > Click OK > Select Basic > Select view engine Razor > OK

Step-2: Add a Database.

Go to Solution Explorer > Right Click on App_Data folder > Add > New item > Select SQL Server Database Under Data > Enter Database name > Add.


Step-3: Create table for Save data.

Here I will create 2 table (as below). 1 for save master record (Order) and another for save details record (order items).
Open Database > Right Click on Table > Add New Table > Add Columns > Save > Enter table name > Ok.
In this example, I have used 2 tables as below

Order

OrderDetails


Here in this OrderDetails table, I have added a Foreign Key on OrderID field which is References to OrderID filed of Order table.

See relation in image : 


Step-4: Add Entity Data Model.

Go to Solution Explorer > Right Click on Project name form Solution Explorer > Add > New item > Select ADO.net Entity Data Model under data > Enter model name > Add.
A popup window will come (Entity Data Model Wizard) > Select Generate from database > Next >
Chose your data connection > select your database > next > Select tables > enter Model Namespace > Finish.

Step-5: Create a view model.

Here we will create a ViewModel. First we will add a new folder named "ViewModel" and inside this folder we will create a class as below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcMasterDetails.Models
{
    public class OrderVM
    {
        public string OrderNo { get; set; }
        public DateTime OrderDate { get; set; }
        public string Description { get; set; }
        public List<OrderDetail> OrderDetails {get;set;}
    }
}
        

Step-6: Create a Controller.

Go to Solution Explorer > Right Click on Controllers folder form Solution Explorer > Add > Controller > Enter Controller name > Select Templete "empty MVC Controller"> Add.

Here I have created a controller "HomeController"

Step-7: Add new action into your controller for Get Method

Here I have added "Index" Action into "Home" Controller. Please write this following code

public ActionResult Index()
{
    return View();
}
        

Step-8: Add view for your Action & design.

Right Click on Action Method (here right click on Index action) > Add View... > Enter View Name > Select View Engine (Razor) > Add.
HTML Code
@{
    ViewBag.Title = "Index";
}

<h2>Master Details entry form</h2>
<div class="container" style="max-width:640px">
    <div class="master">
        <h4>Order details</h4>
        <table>
            <tr>
                <td>Order No</td>
                <td>
                    <input type="text" id="orderNo" />
                    <span class="error">Order no required</span>
                </td>
                <td>Order Date</td>
                <td>
                    <input type="text" id="orderDate" />
                    <span class="error">Valid order date required (ex. MM-dd-yyyy)</span>
                </td>
            </tr>
            <tr>
                <td>Description</td>
                <td colspan="3">
                    <textarea id="description" style="width:100%"></textarea>
                </td>
            </tr>
        </table>
    </div>
    <div class="details">
        <h4>Order Items</h4>
        <table width="100%">
            <tr>
                <td>Item Name</td>
                <td>Quantity</td>
                <td>Rate</td>
                <td>&nbsp;</td>
            </tr>
            <tr>
                <td>
                    <input type="text" id="itemName" />
                    <span class="error">Item name required</span>
                </td>
                <td>
                    <input type="text" id="quantity" />
                    <span class="error">Valid quantity required</span>
                </td>
                <td>
                    <input type="text" id="rate" />
                    <span class="error">Valid rate required</span>
                </td>
                <td>
                    <input type="button" id="add" value="add" />
                </td>
            </tr>
        </table>
        <div id="orderItems" class="tablecontainer">

        </div>
        <div style="padding:10px 0px; text-align:right">
            <input id="submit" type="button" value="Save" style="padding:10px 20px" />
        </div>
    </div>
</div>
        

Updated on 18 may 2016 : Added yellow mark code for support remove functionality.

Step-9: Add jquery code

Jquery Code
    <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
    <script>
        //Date Picker
        $(function () {
            $('#orderDate').datepicker({
                dateFormat : 'mm-dd-yy'
            });
        });

        $(document).ready(function () {
            var orderItems = [];
            //Add button click function
            $('#add').click(function () {
                //Check validation of order item
                var isValidItem = true;
                if ($('#itemName').val().trim() == '') {
                    isValidItem = false;
                    $('#itemName').siblings('span.error').css('visibility', 'visible');
                }
                else {
                    $('#itemName').siblings('span.error').css('visibility', 'hidden');
                }

                if (!($('#quantity').val().trim() != '' && !isNaN($('#quantity').val().trim()))) {
                    isValidItem = false;
                    $('#quantity').siblings('span.error').css('visibility', 'visible');
                }
                else {
                    $('#quantity').siblings('span.error').css('visibility', 'hidden');
                }

                if (!($('#rate').val().trim() != '' && !isNaN($('#rate').val().trim()))) {
                    isValidItem = false;
                    $('#rate').siblings('span.error').css('visibility', 'visible');
                }
                else {
                    $('#rate').siblings('span.error').css('visibility', 'hidden');
                }

                //Add item to list if valid
                if (isValidItem) {
                    orderItems.push({
                        ItemName: $('#itemName').val().trim(),
                        Quantity: parseInt($('#quantity').val().trim()),
                        Rate: parseFloat($('#rate').val().trim()),
                        TotalAmount: parseInt($('#quantity').val().trim()) * parseFloat($('#rate').val().trim())
                    });

                    //Clear fields
                    $('#itemName').val('').focus();
                    $('#quantity,#rate').val('');

                }
                //populate order items
                GeneratedItemsTable();

            });
            //Save button click function
            $('#submit').click(function () {
                //validation of order
                var isAllValid = true;
                if (orderItems.length == 0) {
                    $('#orderItems').html('<span style="color:red;">Please add order items</span>');
                    isAllValid = false;
                }

                if ($('#orderNo').val().trim() == '') {
                    $('#orderNo').siblings('span.error').css('visibility', 'visible');
                    isAllValid = false;
                }
                else {
                    $('#orderNo').siblings('span.error').css('visibility', 'hidden');
                }

                if ($('#orderDate').val().trim() == '') {
                    $('#orderDate').siblings('span.error').css('visibility', 'visible');
                    isAllValid = false;
                }
                else {
                    $('#orderDate').siblings('span.error').css('visibility', 'hidden');
                }

                //Save if valid
                if (isAllValid) {
                    var data = {
                        OrderNo: $('#orderNo').val().trim(),
                        OrderDate: $('#orderDate').val().trim(),
                        //Sorry forgot to add Description Field
                        Description : $('#description').val().trim(),
                        OrderDetails : orderItems
                    }

                    $(this).val('Please wait...');

                    $.ajax({
                        url: '/Home/SaveOrder',
                        type: "POST",
                        data: JSON.stringify(data),
                        dataType: "JSON",
                        contentType: "application/json",
                        success: function (d) {
                            //check is successfully save to database 
                            if (d.status == true) {
                                //will send status from server side
                                alert('Successfully done.');
                                //clear form
                                orderItems = [];
                                $('#orderNo').val('');
                                $('#orderDate').val('');
                                $('#orderItems').empty();
                            }
                            else {
                                alert('Failed');
                            }
                            $('#submit').val('Save');
                        },
                        error: function () {
                            alert('Error. Please try again.');
                            $('#submit').val('Save');
                        }
                    });
                }

            });
            //function for show added items in table
            function GeneratedItemsTable() {
                if (orderItems.length > 0)
                {
                    var $table = $('<table/>');
                    $table.append('<thead><tr><th>Item</th><th>Quantity</th><th>Rate</th><th>Total</th><th></th></tr></thead>');
                    var $tbody = $('<tbody/>');
                    $.each(orderItems, function (i, val) {
                        var $row = $('<tr/>');
                        $row.append($('<td/>').html(val.ItemName));
                        $row.append($('<td/>').html(val.Quantity));
                        $row.append($('<td/>').html(val.Rate));
                        $row.append($('<td/>').html(val.TotalAmount));
                        var $remove = $('<a href="#">Remove</a>');
                        $remove.click(function (e) {
                            e.preventDefault();
                            orderItems.splice(i, 1);
                            GeneratedItemsTable();
                        });
                        $row.append($('<td/>').html($remove));
                        $tbody.append($row);
                    });
                    console.log("current", orderItems);
                    $table.append($tbody);
                    $('#orderItems').html($table);
                }
                else {
                    $('#orderItems').html('');
                }
            }
        });

    </script>
        
Complete HTML Code
    @{
        ViewBag.Title = "Index";
    }

    <h2>Master Details entry form</h2>
    <div class="container" style="max-width:640px">
        <div class="master">
            <h4>Order details</h4>
            <table>
                <tr>
                    <td>Order No</td>
                    <td>
                        <input type="text" id="orderNo" />
                        <span class="error">Order no required</span>
                    </td>
                    <td>Order Date</td>
                    <td>
                        <input type="text" id="orderDate" />
                        <span class="error">Valid order date required (ex. MM-dd-yyyy)</span>
                    </td>
                </tr>
                <tr>
                    <td>Description</td>
                    <td colspan="3">
                        <textarea id="description" style="width:100%"></textarea>
                    </td>
                </tr>
            </table>
        </div>
        <div class="details">
            <h4>Order Items</h4>
            <table width="100%">
                <tr>
                    <td>Item Name</td>
                    <td>Quantity</td>
                    <td>Rate</td>
                    <td>&nbsp;</td>
                </tr>
                <tr>
                    <td>
                        <input type="text" id="itemName" />
                        <span class="error">Item name required</span>
                    </td>
                    <td>
                        <input type="text" id="quantity" />
                        <span class="error">Valid quantity required</span>
                    </td>
                    <td>
                        <input type="text" id="rate" />
                        <span class="error">Valid rate required</span>
                    </td>
                    <td>
                        <input type="button" id="add" value="add" />
                    </td>
                </tr>
            </table>
            <div id="orderItems" class="tablecontainer">

            </div>
            <div style="padding:10px 0px; text-align:right">
                <input id="submit" type="button" value="Save" style="padding:10px 20px" />
            </div>
        </div>
    </div>

<link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css">
@section Scripts{
    <script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
    <script>
        //Date Picker
        $(function () {
            $('#orderDate').datepicker({
                dateFormat : 'mm-dd-yy'
            });
        });

        $(document).ready(function () {
            var orderItems = [];
            //Add button click function
            $('#add').click(function () {
                //Check validation of order item
                var isValidItem = true;
                if ($('#itemName').val().trim() == '') {
                    isValidItem = false;
                    $('#itemName').siblings('span.error').css('visibility', 'visible');
                }
                else {
                    $('#itemName').siblings('span.error').css('visibility', 'hidden');
                }

                if (!($('#quantity').val().trim() != '' && !isNaN($('#quantity').val().trim()))) {
                    isValidItem = false;
                    $('#quantity').siblings('span.error').css('visibility', 'visible');
                }
                else {
                    $('#quantity').siblings('span.error').css('visibility', 'hidden');
                }

                if (!($('#rate').val().trim() != '' && !isNaN($('#rate').val().trim()))) {
                    isValidItem = false;
                    $('#rate').siblings('span.error').css('visibility', 'visible');
                }
                else {
                    $('#rate').siblings('span.error').css('visibility', 'hidden');
                }

                //Add item to list if valid
                if (isValidItem) {
                    orderItems.push({
                        ItemName: $('#itemName').val().trim(),
                        Quantity: parseInt($('#quantity').val().trim()),
                        Rate: parseFloat($('#rate').val().trim()),
                        TotalAmount: parseInt($('#quantity').val().trim()) * parseFloat($('#rate').val().trim())
                    });

                    //Clear fields
                    $('#itemName').val('').focus();
                    $('#quantity,#rate').val('');

                }
                //populate order items
                GeneratedItemsTable();

            });
            //Save button click function
            $('#submit').click(function () {
                //validation of order
                var isAllValid = true;
                if (orderItems.length == 0) {
                    $('#orderItems').html('<span style="color:red;">Please add order items</span>');
                    isAllValid = false;
                }

                if ($('#orderNo').val().trim() == '') {
                    $('#orderNo').siblings('span.error').css('visibility', 'visible');
                    isAllValid = false;
                }
                else {
                    $('#orderNo').siblings('span.error').css('visibility', 'hidden');
                }

                if ($('#orderDate').val().trim() == '') {
                    $('#orderDate').siblings('span.error').css('visibility', 'visible');
                    isAllValid = false;
                }
                else {
                    $('#orderDate').siblings('span.error').css('visibility', 'hidden');
                }

                //Save if valid
                if (isAllValid) {
                    var data = {
                        OrderNo: $('#orderNo').val().trim(),
                        OrderDate: $('#orderDate').val().trim(),
                        //Sorry forgot to add Description Field
                        Description : $('#description').val().trim(),
                        OrderDetails : orderItems
                    }

                    $(this).val('Please wait...');

                    $.ajax({
                        url: '/Home/SaveOrder',
                        type: "POST",
                        data: JSON.stringify(data),
                        dataType: "JSON",
                        contentType: "application/json",
                        success: function (d) {
                            //check is successfully save to database 
                            if (d.status == true) {
                                //will send status from server side
                                alert('Successfully done.');
                                //clear form
                                orderItems = [];
                                $('#orderNo').val('');
                                $('#orderDate').val('');
                                $('#orderItems').empty();
                            }
                            else {
                                alert('Failed');
                            }
                            $('#submit').val('Save');
                        },
                        error: function () {
                            alert('Error. Please try again.');
                            $('#submit').val('Save');
                        }
                    });
                }

            });
            //function for show added items in table
            function GeneratedItemsTable() {
                if (orderItems.length > 0)
                {
                    var $table = $('<table/>');
                    $table.append('<thead><tr><th>Item</th><th>Quantity</th><th>Rate</th><th>Total</th><th></th></tr></thead>');
                    var $tbody = $('<tbody/>');
                    $.each(orderItems, function (i, val) {
                        var $row = $('<tr/>');
                        $row.append($('<td/>').html(val.ItemName));
                        $row.append($('<td/>').html(val.Quantity));
                        $row.append($('<td/>').html(val.Rate));
                        $row.append($('<td/>').html(val.TotalAmount));
                        var $remove = $('<a href="#">Remove</a>');
                        $remove.click(function (e) {
                            e.preventDefault();
                            orderItems.splice(i, 1);
                            GeneratedItemsTable();
                        });
                        $row.append($('<td/>').html($remove));
                        $tbody.append($row);
                    });
                    console.log("current", orderItems);
                    $table.append($tbody);
                    $('#orderItems').html($table);
                }
                else {
                    $('#orderItems').html('');
                }
            }
        });

    </script>
}

<style>
    /*Adding some css for looks good*/
    span.error {
        display:block;
        visibility:hidden;
        color:red;
        font-size:90%;
    }


    /*css for table*/
    .container td {
        vertical-align: top;
    }
    .tablecontainer table {
        width: 100%;
        border-collapse: collapse;
        border-top: 1px solid #BFAEAE;
        border-right: 1px solid #BFAEAE;
    }
    .tablecontainer th {
        border-bottom: 2px solid #BFAEAE !important;
    }
    .tablecontainer th, .tablecontainer td {
        text-align: left;
        border-left: 1px solid #BFAEAE;
        padding: 5px;
        border-bottom: 1px solid #BFAEAE;
    }
    .ui-widget {
        font-size:12px !important;
    }
</style>
        

Step-10: Add new action into your controller for save order and order details (POST Method)

Here I have added "SaveOrder" Action into "Home" Controller. Please write this following code

        //Post action for Save data to database
        [HttpPost]
        public JsonResult SaveOrder(OrderVM O)
        {
            bool status = false;
            if (ModelState.IsValid)
            {
                using (MyDatabaseEntities dc = new MyDatabaseEntities())
                {
                    Order order = new Order { OrderNo = O.OrderNo, OrderDate = O.OrderDate, Description = O.Description };
                    foreach (var i in O.OrderDetails)
                    {
                        //
                       // i.TotalAmount = 
                        order.OrderDetails.Add(i);
                    }
                    dc.Orders.Add(order);
                    dc.SaveChanges();
                    status = true;
                }
            }
            else
            {
                status = false;
            }
            return new JsonResult { Data = new { status = status} };
        }
        

Step-11: Run Application.


Must see : Advanced master details entry form with inline edit & delete


How to create Master Detail entry form in asp.net MVC4

Hello ! My name is Sourav Mondal. I am a software developer working in Microsoft .NET technologies since 2010.

I like to share my working experience, research and knowledge through my site.

I love developing applications in Microsoft Technologies including Asp.Net webforms, mvc, winforms, c#.net, sql server, entity framework, Ajax, Jquery, web api, web service and more.