Master-Detail

Jan 31, 2013 at 1:54 PM
Hi,
I want your advise regarding creating a Master-Detail form, the form should look like the normal invoice,
The invoices will be listed in a grid and when the user clicks on the add button a dialog will be opened, this dialog should contain the invoice header and a grid for the items, I want to allow the user to add the invoice header and details in the same dialog so it can be saved together.

what's the best practice to do so using the library?

Thanks
Coordinator
Jan 31, 2013 at 6:44 PM
Hi,

At the general level I would suggest following approach:
  1. Have standard grid for invoices with custom add buton.
  2. On click of this buton you should open your own dialog with the form.
  3. The grid in that dialog should be configured with loadOnce = true (you will return empty result for it from server, unfortunately helper doesn't suport local datatype)
  4. You can use getGridParam and setGridParam client side function to get and set the data array (this is your details)
  5. Of course you need to handle save request yourself with JavaScript.
If you hit any hard obstacles on your road feel free to ask detailed questions.
Feb 1, 2013 at 8:28 PM
TPeczek wrote:
Hi,

At the general level I would suggest following approach:
  1. Have standard grid for invoices with custom add buton.
  2. On click of this buton you should open your own dialog with the form.
  3. The grid in that dialog should be configured with loadOnce = true (you will return empty result for it from server, unfortunately helper doesn't suport local datatype)
  4. You can use getGridParam and setGridParam client side function to get and set the data array (this is your details)
  5. Of course you need to handle save request yourself with JavaScript.
If you hit any hard obstacles on your road feel free to ask detailed questions.
Thanks for the quick response, would you please guide me with an example
Coordinator
Feb 2, 2013 at 6:12 AM
Edited Feb 2, 2013 at 6:13 AM
I can create a prototype demo later this week. Meantime I would strongly recommend that you should try pick it up by yourself. Just remember not to try use any built in jqGrid editing functionality. You have to do all the editing by yourself (create dialog, with the form etc.). You will see that this is not so complicated functionality. On my side I can promise I will sit down to this as soon as I will have time (but not sooner that middle of the week I'm afraid - I have crazy time here)
Coordinator
Feb 6, 2013 at 8:53 PM
Hi,

Here is a short walkthrough with sample code (I will skip all the non esential parts).

First you should have two model classes which might look more less like this:
public class OrderViewModel
{
    #region Properties
    public string Customer { get; set; }

    public string Employee { get; set; }

    ...

    public List<OrderDetailViewModel> Details { get; set; }
    #endregion
}

public class OrderDetailViewModel
{
    #region Properties
    ...
    #endregion
}
I kept the number of properties to minimum. I have also skiped all the attributes for clarity. Now based on the model you should initialize two helper instances (I'm showing only important options):
var ordersGrid = new Lib.Web.Mvc.JQuery.JqGrid.JqGridHelper<jqGrid.Models.OrderViewModel>("orders",
    ...
)
.Navigator(new Lib.Web.Mvc.JQuery.JqGrid.JqGridNavigatorOptions() { Add = false, Delete = false, Edit = false, View = false, Search = false, Refresh = false })
.AddNavigatorButton(caption: "Add", onClick: "onAddOrderClick");

var ordersDetailsGrid = new Lib.Web.Mvc.JQuery.JqGrid.JqGridHelper<jqGrid.Models.OrderDetailViewModel>("orderDetails",
    dataType: Lib.Web.Mvc.JQuery.JqGrid.JqGridDataTypes.Json,
    editingUrl: "clientArray",
    loadOnce: true,
    ...
    url: Url.Action("OrderDetailsLoadOnce"),
).Navigator(new Lib.Web.Mvc.JQuery.JqGrid.JqGridNavigatorOptions() { ... });
For the first grid it is important to disable all the built in edit functionalities and provide your own button. For the second grid you need to enable loadOnce and set editingUrl in order to make sure that all the built in edit functionalities will work locally. You can check the "Advanced --> Load once" sample in my samples project (http://tpeczek.codeplex.com/releases/view/62741) for more details.

Now in your HTML you will render first grid and create a dialog with fields for adding the order. The second grid should go inside of that dialog:
@ordersGrid.GetHtml()
<div id="dialog" title="Add Order" style="display:none">
    <fieldset>
        <label for="Customer">Customer: </label><input type="text" name="Customer" id="Customer" /><br />
        <label for="Employee">Employee: </label><input type="text" name="Employee" id="Employee" /><br />
        @*Put additional fields here*@
        <br />
        @ordersDetailsGrid.GetHtml()
    </fieldset>
</div>
All we are missing now is the JavaScript part. Forst the handler for custom button we have added to the first grid:
<script type="text/javascript">
    var onAddOrderClick = function(e) {
        e.preventDefault();
        e.stopPropagation();

        $('#dialog').dialog('open');
    };

    ...
</script>
Nothing special here. What is left to do is rendereing both grids JavaScript and initializing the dialog:
<script type="text/javascript">
    ...

    $(document).ready(function () {
        @ordersGrid.GetJavaScript()
        @ordersDetailsGrid.GetJavaScript()
        $('#dialog').dialog({
            autoOpen: false,
            width: 600,
            buttons: [
                { text: 'Save', click: function() {
                    $.ajax({
                        type: 'POST',
                        url: '@Url.Action("AddOrder")',
                        contentType: 'application/json; charset=utf-8',
                        data: JSON.stringify({
                            Customer: $('#Customer').val(),
                            Employee: $('#Employee').val(),
                            ...
                            Details: $('#orderDetails').jqGrid('getGridParam', 'data')
                        }),
                        success: function(data) { $(this).dialog('close'); }
                    });
                } },
                { text: 'Cancel', click: function() { $(this).dialog('close'); } }
            ],
            close: function(event, ui) {
                $('#Customer').val('');
                $('#Employee').val('');
                ...
                $('#orderDetails').jqGrid('setGridParam', { data: {} }).trigger('reloadGrid');
            }
        });
    });
</script>
Now what you need to look at here are the handler for dialog close event (this is where we clear all the form fields and data from second grid) and handler for Save button of the dialog (this where we are posting the Order data to the server).

This should explain the entire approach, feeling the blanks should be easy now as there is nothing complicated there.