ASP.NET MVC Master Detail Entry Form
Asked Answered
G

6

20

I’m trying to implement an order entry form using ASP.NET MVC but facing a lot of difficulties. All the samples that I found are related to viewing master detail forms, and none for adding or editing.

Suppose I have two tables: Order and OrderLines that are related to each others with one-to-many relationship. In the main view I had a “New” button when clicked it should show a new order view composed of the order fields, a grid that shows the order lines, and a “Save” button that when clicked will persist the whole order along with its lines into a database. The grid should have three buttons: “Add Line”, “Edit Line”, and “Delete Line”. When the “Add Line” is clicked a new view should be shown that allows the user to add the line to the order view grid lines –at this stage the database is not affected-. When the user clicks “Edit Line” a view will be shown that allows the user to edit the selected line and when done update the order grid lines.

The most difficult problems are:

How to pass the order and its lines collection between the order view and the order line views?

How to update the order view based on changes in the order line view?

And how to persist changes between views without the database being involved?

Is there a concrete example that shows how to implement this using MVC?

Views

Your help and feedback is appreciated.

Gerrard answered 10/1, 2011 at 11:31 Comment(0)
V
3

Pleas have a look at my blog post on creating master detail form in asp.net mvc. it also contains demo project that you can download

Vernacularism answered 22/5, 2011 at 17:47 Comment(0)
L
2

Unlike WebForms, ASP.NET MVC does not try to hide the stateless nature of HTTP. To work with a complex object across multiple forms you have a couple of options:

  • Save the object on the server with each change so that the updated object is available using only an id
  • Use jquery to populate the order line form and save details to the main form

I usually go with the client side option myself, with the main form having hidden fields for the data that will be edited in the subform. You may find the server side option easier though - if you really don't want to involve the database you can keep your partially updated object in the session.

Lighterage answered 11/1, 2011 at 0:29 Comment(1)
Thank you. May you provide a short sample that uses the JQuery method?Gerrard
B
2

Step 1: Create view model

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 2: Add javascript for add order lines

<script src="//code.jquery.com/ui/1.11.4/jquery-ui.js"></script>

    $(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() != '' &amp;&amp; !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() != '' &amp;&amp; !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('&lt;span style="color:red;"&gt;Please add order items&lt;/span&gt;');
                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 &gt; 0) {
                var $table = $('&lt;table/&gt;');
                $table.append('&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Item&lt;/th&gt;&lt;th&gt;Quantity&lt;/th&gt;&lt;th&gt;Rate&lt;/th&gt;&lt;th&gt;Total&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;');
                var $tbody = $('&lt;tbody/&gt;');
                $.each(orderItems, function (i, val) {
                    var $row = $('&lt;tr/&gt;');
                    $row.append($('&lt;td/&gt;').html(val.ItemName));
                    $row.append($('&lt;td/&gt;').html(val.Quantity));
                    $row.append($('&lt;td/&gt;').html(val.Rate));
                    $row.append($('&lt;td/&gt;').html(val.TotalAmount));
                    $tbody.append($row);
                });
                $table.append($tbody);
                $('#orderItems').html($table);
            }
        }
    });

</script>

Step 3: Create an action for save data

[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} };
    }

you can download source code and video tutorial

Beating answered 22/9, 2015 at 2:52 Comment(0)
S
1

You could try Telericks free MVC grid control...

http://demos.telerik.com/aspnet-mvc/grid/hierarchyserverside

Suitable answered 10/1, 2011 at 14:26 Comment(4)
Thank You. I think I didn't make my question clear enough! I'm not looking for a control. I need to know how the different views interact when I have a master detail entry form in ASP.NET MVC.Gerrard
Fair enough.... I was trying to provide a solution.... the control takes care of a lot of those issues you describe.Suitable
I guess Emad wants to have full control over the code, I'm looking for same answer, I don't want use Telerik, for MVC I don't want ending being tied to controls and forced to program the way controls want again as in webforms, I want to be "free" this time.Nisi
Also Devexpress has a grid control with Master/Detail capabilities mvc.devexpress.com/GridView/MasterDetailcontrol But Telerik and DevEx grid controls Master/Detail samples just do viewing not adding or editing.Hufuf
K
1

Just off the top of my head (a kind of brain dump)...

  • You could have a main grid part of the form. This would be full view loaded from an action (either with an order number or not depending on loading an existing one or not).

  • When clicking an event (new or edit) this could open a partial view in a "lightbox" style. This would then pass back a json object back to the main form.

  • The passed json object would then be rendered using templating to the bottom of the table (for a new one) or update an existing record. This could also be saved back to the server in the same ajax call. Or just update the client side and need the user to click a save button.

  • An isDirty flag will be needed so any changes set it to true and the when the browser tries to leave or close etc. then you can prompt the user to save or not.

Hope this helps.

edit

Not tried this but could be interesting with the none db aspect of your question click

Keenakeenan answered 17/2, 2011 at 21:46 Comment(0)
M
0

Step 3: Create an action for save data. [HttpPost]

    public JsonResult SaveOrder(OrderVM O)

    {

        bool status = false;

        if (ModelState.IsValid)

        {

            using (ManageMobileStoreWebContext dc = new ManageMobileStoreWebContext())

            {

                //Random rnd = new Random();

                //OrderID = rnd.Next(),

                Order order = new Order { OrderNo = O.OrderNo, OrderDate = O.OrderDate, Description = O.Description };

                foreach (var i in O.OrderDetails)

                {

                    if(order.OrderDetails == null)

                    {

                        order.OrderDetails = new List<OrderDetail>();

                    }

                    // i.TotalAmount = 

                    order.OrderDetails.Add(i);

                   //dc.OrderDetails.Add(i);

                }

                dc.Orders.Add(order);

                dc.SaveChanges();

                status = true;

            }

        }

        else

        {

            status = false;

        }

        return new JsonResult { Data = new { status = status } };

    }
Marduk answered 4/12, 2018 at 9:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.