Features

Batch Editing

Batch Editing

This sample shows the Batch update mode for updating the MultiRow data to server.

Features

Description

The MultiRow control has built-in support for Excel-like, fast, in-cell editing. Users can begin editing by simply typing in to any cell (quick-edit mode), or by pressing F2 or clicking a cell twice (full-edit mode). There is no need to add extra columns with 'Edit' buttons that switch between display and edit modes.

There are two modes for updating data to server.

Normal Mode

In this mode, which is the default mode, the item updated or created gets committed to the server once the corresponding row finishes editing. The removed row will be committed to the server immediately.

If user wants to update the data, the Update action Url should be provided. If one wants to add or remove the data, the Create or the Delete action Url should be provided. And the user should edit the data in the corresponding action.

Batch Mode

In this mode user can update, create or remove multiple items and commit all the changes to the data source once. The user can commit multiple modifications by sorting, paging or filtering the grid data or simply on a button-click.

The BatchEditing action Url should be provided in this mode.

Note: To disable data update during sort/filter/page operations, set the DisableServerRead property of MultiRow's ItemSource to True. This will enable client-side sorting, filtering, paging and data will only be submitted when the collectionView's commit method is explicitly called from the client-side.

using C1.Web.Mvc.Fluent;
using C1.Web.Mvc.Grid;
using C1.Web.Mvc.MultiRow;
using C1.Web.Mvc.MultiRow.Fluent;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MultiRowExplorer.Models
{
    public class LayoutDefinitionsBuilders
    {
        public static Action<ListItemFactory<CellGroup, CellGroupBuilder>> OneLine
        {
            get
            {
                return ld =>
                {
                    ld.Add().Colspan(15).Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Id").Header("ID").CssClass("id"))
                            .Add(cell => cell.Binding("Date").Header("Ordered"))
                            .Add(cell => cell.Binding("ShippedDate").Header("Shipped"))
                            .Add(cell => cell.Binding("Amount").Header("Amount").Format("c").CssClass("amount"))
                            .Add(cell => cell.Binding("Customer.Name").Name("CustomerName").Header("Customer"))
                            .Add(cell => cell.Binding("Customer.Address").Name("CustomerAddress").Header("Address"))
                            .Add(cell => cell.Binding("Customer.City").Name("CustomerCity").Header("City")
                                .DataMap(dm => { dm.DisplayMemberPath("Value").SelectedValuePath("Value").Bind(Orders.GetCities().ToValues()); }))
                            .Add(cell => cell.Binding("Customer.State").Name("CustomerState").Header("State"))
                            .Add(cell => cell.Binding("Customer.Zip").Name("CustomerZip").Header("Zip"))
                            .Add(cell => cell.Binding("Customer.Email").Name("CustomerEmail").Header("Customer Email").CssClass("email"))
                            .Add(cell => cell.Binding("Customer.Phone").Name("Customerphone").Header("Customer Phone"))
                            .Add(cell => cell.Binding("Shipper.Name").Name("ShipperName").Header("Shipper"))
                            .Add(cell => cell.Binding("Shipper.Email").Name("ShipperEmail").Header("Shipper Email").CssClass("email"))
                            .Add(cell => cell.Binding("Shipper.Phone").Name("ShipperPhone").Header("Shipper Phone"))
                            .Add(cell => cell.Binding("Shipper.Express").Name("ShipperExpress").Header("Express"));
                    });
                };
            }
        }

        public static Action<ListItemFactory<CellGroup, CellGroupBuilder>> TwoLines
        {
            get
            {
                return ld =>
                {
                    ld.Add().Header("Order").Colspan(2).Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Id").Header("ID").CssClass("id").Width("150"))
                            .Add(cell => cell.Binding("Date").Header("Ordered").Width("150"))
                            .Add(cell => cell.Binding("Amount").Header("Amount").Format("c").CssClass("amount"))
                            .Add(cell => cell.Binding("ShippedDate").Header("Shipped"));
                    });
                    ld.Add().Header("Customer").Colspan(3).Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Customer.Name").Name("CustomerName").Header("Customer").Width("200"))
                            .Add(cell => cell.Binding("Customer.Email").Name("CustomerEmail").Header("Customer Email").Colspan(2).CssClass("email"))
                            .Add(cell => cell.Binding("Customer.Address").Name("CustomerAddress").Header("Address"))
                            .Add(cell => cell.Binding("Customer.City").Name("CustomerCity").Header("City").ShowDropDown(true)
                                .DataMap(dm => { dm.DisplayMemberPath("Value").SelectedValuePath("Value").Bind(Orders.GetCities().ToValues()); }))
                            .Add(cell => cell.Binding("Customer.State").Name("CustomerState").Header("State"));
                    });
                    ld.Add().Header("Shipper").Colspan(2).Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Shipper.Name").Name("ShipperName").Header("Shipper").Colspan(2))
                            .Add(cell => cell.Binding("Shipper.Email").Name("ShipperEmail").Header("Shipper Email").Width("200").CssClass("email"))
                            .Add(cell => cell.Binding("Shipper.Express").Name("ShipperExpress").Header("Express"));
                    });
                };
            }
        }

        public static Action<ListItemFactory<CellGroup, CellGroupBuilder>> ThreeLines
        {
            get
            {
                return ld =>
                {
                    ld.Add().Header("Order").Colspan(2).Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Id").Header("ID").Colspan(2).CssClass("id"))
                            .Add(cell => cell.Binding("Amount").Header("Amount").Format("c").Colspan(2).CssClass("amount"))
                            .Add(cell => cell.Binding("Date").Header("Ordered"))
                            .Add(cell => cell.Binding("ShippedDate").Header("Shipped"));
                    });
                    ld.Add().Header("Customer").Colspan(3).Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Customer.Name").Name("CustomerName").Header("Customer"))
                            .Add(cell => cell.Binding("Customer.Email").Name("CustomerEmail").Header("Customer Email").Colspan(2).CssClass("email"))
                            .Add(cell => cell.Binding("Customer.Address").Name("CustomerAddress").Header("Address").Colspan(2))
                            .Add(cell => cell.Binding("Customer.Phone").Name("CustomerPhone").Header("Phone"))
                            .Add(cell => cell.Binding("Customer.City").Name("CustomerCity").Header("City")
                                .DataMap(dm => { dm.DisplayMemberPath("Value").SelectedValuePath("Value").Bind(Orders.GetCities().ToValues()); }))
                            .Add(cell => cell.Binding("Customer.State").Name("CustomerState").Header("State"))
                            .Add(cell => cell.Binding("Customer.Zip").Name("CustomerZip").Header("Zip"));
                    });
                    ld.Add().Header("Shipper").Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Shipper.Name").Name("ShipperName").Header("Shipper").Width("*"))
                            .Add(cell => cell.Binding("Shipper.Email").Name("ShipperEmail").Header("Shipper Email").CssClass("email"))
                            .Add(cell => cell.Binding("Shipper.Express").Name("ShipperExpress").Header("Express"));
                    });
                };
            }
        }

        public static Action<ListItemFactory<CellGroup, CellGroupBuilder>> Sales
        {
            get
            {
                return ld =>
                {
                    ld.Add().Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("ID").Header("ID"));
                        cells.Add(cell => cell.Binding("Active").Header("Active"));
                    });
                    ld.Add().Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Start").Header("Start"));
                        cells.Add(cell => cell.Binding("End").Header("End"));
                    });
                    ld.Add().Colspan(2).Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Country").Header("Country").Colspan(2));
                        cells.Add(cell => cell.Binding("Product").Header("Product"));
                        cells.Add(cell => cell.Binding("Color").Header("Color"));
                    });
                    ld.Add().Colspan(2).Cells(cells =>
                    {
                        cells.Add(cell => cell.Binding("Amount").Header("Amount"));
                        cells.Add(cell => cell.Binding("Amount2").Header("Amount2"));
                        cells.Add(cell => cell.Binding("Discount").Header("Discount").Colspan(2));
                    });
                };
            }
        }
    }
}
using System.Data.Entity.Validation;
using MultiRowExplorer.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using C1.Web.Mvc.Serialization;
using C1.Web.Mvc;
using System.Data;
using System.Data.Entity;

namespace MultiRowExplorer.Controllers
{
    public partial class MultiRowController : Controller
    {
        //
        // GET: /BatchEditing/

        public ActionResult BatchEditing(CollectionViewRequest<Supplier> requestData)
        {
            return View(db.Suppliers.ToList());
        }

        public ActionResult MultiRowBatchEdit([C1JsonRequest]CollectionViewBatchEditRequest<Supplier> requestData)
        {
            return this.C1Json(CollectionViewHelper.BatchEdit(requestData, batchData =>
            {
                var itemresults = new List<CollectionViewItemResult<Supplier>>();
                string error = string.Empty;
                bool success = true;
                try
                {
                    if (batchData.ItemsCreated != null)
                    {
                        batchData.ItemsCreated.ToList().ForEach(st =>
                        {
                            db.Suppliers.Add(st);
                            itemresults.Add(new CollectionViewItemResult<Supplier>
                            {
                                Error = "",
                                Success = ModelState.IsValid,
                                Data = st
                            });
                        });
                    }
                    if (batchData.ItemsDeleted != null)
                    {
                        batchData.ItemsDeleted.ToList().ForEach(supplier =>
                        {
                            var fSupplier = db.Suppliers.Find(supplier.SupplierID);
                            db.Suppliers.Remove(fSupplier);
                            itemresults.Add(new CollectionViewItemResult<Supplier>
                            {
                                Error = "",
                                Success = ModelState.IsValid,
                                Data = supplier
                            });
                        });
                    }
                    if (batchData.ItemsUpdated != null)
                    {
                        batchData.ItemsUpdated.ToList().ForEach(supplier =>
                        {
                            db.Entry(supplier).State = EntityState.Modified;
                            itemresults.Add(new CollectionViewItemResult<Supplier>
                            {
                                Error = "",
                                Success = ModelState.IsValid,
                                Data = supplier
                            });
                        });
                    }
                    db.SaveChanges();
                }
                catch (DbEntityValidationException e)
                {
                    var errorList = e.EntityValidationErrors.SelectMany(i => i.ValidationErrors).Select(i => i.ErrorMessage).ToList();

                    try
                    {
                        var refreshableObjects = db.ChangeTracker.Entries().Where(c => c.State == EntityState.Modified).ToList();
                        refreshableObjects.ForEach(o => o.Reload());
                    }
                    catch (Exception er)
                    {
                        errorList.Add(er.Message);
                    }

                    error = string.Join(",", errorList);
                    success = false;
                }
                catch (Exception e)
                {
                    error = e.Message;
                    success = false;
                }

                return new CollectionViewResponse<Supplier>
                {
                    Error = error,
                    Success = success,
                    OperatedItemResults = itemresults
                };
            }, () => db.Suppliers.ToList()));
        }
    }
}
@model IEnumerable<Supplier>

@section Styles{
    <style>
        .queryErrorMessage {
            color: #f00;
        }
    </style>
}

@section Scripts{
    <script type="text/javascript">
        function batchUpdate() {
            var batchEditMultiRow = wijmo.Control.getControl('#batchEditMultiRow'),
                cv = batchEditMultiRow.collectionView;
            cv.commit();

            var isChanged = (cv.itemsAdded && cv.itemsAdded.length)
                    || (cv.itemsRemoved && cv.itemsRemoved.length)
                    || (cv.itemsEdited && cv.itemsEdited.length);
            if (isChanged) {
                setQueryMessage('Updating...');
            } else {
                setQueryMessage('No changes.');
            }

        }

        function onQueryComplete(sender, e) {
            if (e.result.success) {
                setQueryMessage('Done.');
            } else {
                setQueryMessage(e.result.error, 'queryErrorMessage');
            }
        }

        function setQueryMessage(message, className) {
            var element = document.getElementById('queryMessage');
            element.innerHTML = message;
            element.className = className;
        }
    </script>
}

<input type="button" value="Update" class="btn" onclick="batchUpdate()" />
<span id="queryMessage"></span>
@(
Html.C1().MultiRow<Supplier>()
    .Id("batchEditMultiRow")
    .LayoutDefinition(ld =>
    {
        ld.Add().Cells(cells =>
        {
            cells.Add(c => c.Binding("SupplierID").IsReadOnly(true).Format("d").Align("center"));
        });
        ld.Add().Colspan(2).Cells(cells =>
        {
            cells.Add(c => c.Binding("CompanyName").Colspan(2))
            .Add(c => c.Binding("ContactName").Width("150"))
            .Add(c => c.Binding("ContactTitle").Width("200"));
        });
        ld.Add().Colspan(3).Cells(cells =>
        {
            cells.Add(c => c.Binding("Country"))
            .Add(c => c.Binding("Region"))
            .Add(c => c.Binding("City"))
            .Add(c => c.Binding("Address").Colspan(3));
        });
    })
    .Bind(ib => ib.DisableServerRead(true).Bind(Model).BatchEdit(Url.Action("MultiRowBatchEdit")).OnClientQueryComplete("onQueryComplete"))
    .AllowAddNew(true)
    .AllowDelete(true)
    .CssClass("multirow")
)

@section Summary{
    This sample shows the Batch update mode for updating the MultiRow data to server.
}

@section Description{
    <p>        
        The <b>MultiRow</b> control has built-in support for Excel-like, fast, in-cell editing.
        Users can begin editing by simply typing in to any cell (quick-edit mode), or by pressing F2 or clicking a cell twice (full-edit mode).
        There is no need to add extra columns with 'Edit' buttons that switch between display and edit modes.
    </p>
    
    <p>There are two modes for updating data to server.</p>
    <h4>Normal Mode</h4>
    <p>In this mode, which is the default mode, the item updated or created gets committed to the server once the corresponding row finishes editing. 
       The removed row will be committed to the server immediately.</p>
    <p>
        If user wants to update the data, the Update action Url should be provided. If one wants to add or remove the data, the Create or the Delete action Url should be provided.
        And the user should edit the data in the corresponding action.
    </p>
    <h4>Batch Mode</h4>
    <p>
        In this mode user can update, create or remove multiple items and commit all the changes to the data source once.
        The user can commit multiple modifications by sorting, paging or filtering the grid data or simply on a button-click.
    </p>
    <p>The <b>BatchEditing</b> action Url should be provided in this mode.</p>
    <p>
        <b>Note:</b> To disable data update during sort/filter/page operations, set the <b>DisableServerRead</b> property of MultiRow's <b>ItemSource</b> to True.
        This will enable client-side sorting, filtering, paging and data will only be submitted when the collectionView's <b>commit</b> method is explicitly called from the client-side.
    </p>
}