Features

Custom Editors

Custom Editors

Features

Description

This sample shows how you can use custom editors to change the values in the cells of MultiRow control.

The sample uses the EditTemplateId property to specify the id of the template for cell editor. When the user starts editing a cell, the editor will show and get the focus.

There are three kinds of editors.

  • Using C1 Input controls which have "Value" or "Text" property

    You need to set the EditTemplate property of a cell.

    If the grid allows adding a new row, you need to set the editor's IsRequired to false. If you want the editor with the whole cell, you can set the style width to "100%".

    In this sample, "Date", "Time", "Country", "Amount" and "Color" use C1 Input controls as the editors.

  • Using other control or a C1 control which has NO "Value" or "Text" property

    You need to use grid's OnClientCellEditEnding event and set

                         cellEditEndingEventArgs.cancel = true;
                    
    to apply your updates.

    Then you need to consider when to update the cell value and remove the editor from a grid in your application. For example, when the editor blurs, we need to update the cell value and remove the editor.

    In this sample, the "Product" column uses <input /> as the editor.

    To get the binding column in the event handler, please use the MultiRow's getBindingColumn function.

  • Using grid's internal editor

    In this sample, "Amount2" and "Active" use grid's internal editor. Here, you do not need to do anything.

using C1.Web.Mvc;
using MultiRowExplorer.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using C1.Web.Mvc.Serialization;

namespace MultiRowExplorer.Controllers
{
    public partial class MultiRowController : Controller
    {
        private static List<Sale> Source = Sale.GetData(10).ToList<Sale>();
        public ActionResult CustomEditors()
        {
            ViewBag.Countries = Sale.GetCountries();
            ViewBag.Products = Sale.GetProducts();
            return View(Source);
        }

        public ActionResult MultiRowEditorsUpdate([C1JsonRequest]CollectionViewEditRequest<Sale> requestData)
        {
            return this.C1Json(CollectionViewHelper.Edit<Sale>(requestData, sale =>
            {
                string error = string.Empty;
                bool success = true;
                var fSale = Source.Find(item => item.ID == sale.ID);
                fSale.Country = sale.Country;
                fSale.Amount = sale.Amount;
                fSale.Start = sale.Start;
                fSale.End = sale.End;
                fSale.Product = sale.Product;
                fSale.Active = sale.Active;
                fSale.Amount2 = sale.Amount2;
                fSale.Color = sale.Color;
                return new CollectionViewItemResult<Sale>
                {
                    Error = error,
                    Success = success && ModelState.IsValid,
                    Data = fSale
                };
            }, () => Source));
        }

        public ActionResult MultiRowEditorsCreate([C1JsonRequest]CollectionViewEditRequest<Sale> requestData)
        {
            return this.C1Json(CollectionViewHelper.Edit(requestData, item =>
            {
                string error = string.Empty;
                bool success = true;
                try
                {
                    Source.Add(item);
                    item.ID = Source.Max(u => u.ID) + 1;
                }
                catch (Exception e)
                {
                    error = e.Message;
                    success = false;
                }
                return new CollectionViewItemResult<Sale>
                {
                    Error = error,
                    Success = success,
                    Data = item
                };
            }, () => Source));
        }

        public ActionResult MultiRowEditorsDelete([C1JsonRequest]CollectionViewEditRequest<Sale> requestData)
        {
            return this.C1Json(CollectionViewHelper.Edit(requestData, item =>
            {
                string error = string.Empty;
                bool success = true;
                try
                {
                    var resultItem = Source.Find(u => u.ID == item.ID);
                    Source.Remove(resultItem);
                }
                catch (Exception e)
                {
                    error = e.Message;
                    success = false;
                }
                return new CollectionViewItemResult<Sale>
                {
                    Error = error,
                    Success = success,
                    Data = item
                };
            }, () => Source));
        }
    }
}
@model IEnumerable<Sale>
@{
    List<string> countries = ViewBag.Countries;
    List<string> products = ViewBag.Products;
}

@section Scripts{
    <script type="text/javascript">
        c1.documentReady(function () {
            var grid = wijmo.Control.getControl('#customEditorsMultiRow');
            grid.hostElement.addEventListener('keydown', function (e) {
                if (e.keyCode == 32) {
                    e.preventDefault();
                }
            });
        });

        // The following scripts are added to customize updating for the Product column.

        // apply the customized updating for the Product column
        function cellEditEnding(grid, cellRangeEventArgs) {
            var row = cellRangeEventArgs.row, col = cellRangeEventArgs.col;
            var bcol = grid.getBindingColumn(grid.cells, row, col);
            // when it is the editor of the "Product" column,
            // apply the updating manually.
            if (!cellRangeEventArgs.cancel
                && cellRangeEventArgs.panel.cellType == wijmo.grid.CellType.Cell
                && bcol.binding == 'Product') {
                updateCellValue(grid, cellRangeEventArgs);
                cellRangeEventArgs.cancel = true;
            }
        }

        function productEditorFocus(event) {
            var input = event.currentTarget;
            if (input) {
                wijmo.setSelectionRange(input, 0, input.value.length);
            }
        }

        function productEditorBlur(event) {
            var input = event.currentTarget;
            setTimeout(function () {
                if (wijmo.contains(document.activeElement, input)
                    // ensure the input element is not removed from the page.
                    || !document.body.contains(input)) {
                    return;
                }
                var wrapper = input.parentNode,
                   cellRange = getActiveEditorCellRange(input),
                   grid = wijmo.Control.getControl('#customEditorsMultiRow');
                updateCellValue(grid, cellRange);
                wrapper.parentNode.removeChild(wrapper);
            });
        }

        // the id of the element would be [MultiRow's id] + "_Cell_r" + row + "_c" + col + "_"
        function getActiveEditorCellRange(ele) {
            var id = ele.id, strId,
                row, col, index;
            if (id) {
                strId = id.substr('customEditorsMultiRow_Cell_r'.length);
                index = strId.indexOf('_c');
                row = parseInt(strId.substring(0, index));
                col = parseInt(strId.substr(index + 2));
                return { row: row, col: col };
            }
        }

        // update the Product cell's value with its editor.
        function updateCellValue(grid, cellRangeEventArgs) {
            var row, col,
                sel = grid.selection,
                cv = grid.collectionView;

            row = cellRangeEventArgs.row;
            col = cellRangeEventArgs.col;
            cv.editItem(cv.items[row]);
            var input = getEditorControl(row, col);
            grid.setCellData(row, col, input.value);
            cv.commitEdit();
            cv.commitNew();
            grid.select(sel);
        }

        function getEditorControl(row, col) {
            var elementId = 'customEditorsMultiRow_Cell_r' + row + '_c' + col;
            return document.getElementById(elementId);
        }
    </script>
}


<script id="edtDate" type="text/template">
    @(Html.C1().InputDate()
        .Id("dateEditor")
        .Format("d")
        .IsRequired(false) // add this for new row
        .CssStyle("width", "100%") // full with the cell
        .TemplateBind("Value", "Start")
        .ToTemplate()
    )
</script>
<script id="edtTime" type="text/template">
    @(Html.C1().InputTime()
        .Id("timeEditor")
        .Step(30)
        .Format("t")
        .IsRequired(false) // add this for new row
        .CssStyle("width", "100%") // full with the cell
        .TemplateBind("Value", "End").ToTemplate()
    )
</script>
<script id="edtAmount" type="text/template">
    @(Html.C1().InputNumber()
        .Id("amountEditor")
        .Format("c2")
        .IsRequired(false) // add this for new row
        .CssStyle("width", "100%") // full with the cell
        .Step(10)
        .TemplateBind("Value", "Amount").ToTemplate()
    )
</script>
<script id="edtCountry" type="text/template">
    @(Html.C1().ComboBox()
        .Id("countryEditor")
        .IsEditable(false)
        .Bind(countries)
        .CssStyle("width", "100%") // full with the cell
        .TemplateBind("Text", "Country").ToTemplate()
    )
</script>
<script id="edtProduct" type="text/template">
    <input type="text" id="{{uid}}" onfocus="productEditorFocus(event)" onblur="productEditorBlur(event)" style="width:100%;height:100%" value="{{Product}}" />
</script>
<script id="edtColor" type="text/template">
    @(Html.C1().InputColor()
        .Id("colorEditor")
        .CssStyle("width", "100%") // full with the cell
        .TemplateBind("Text", "Color").ToTemplate()
    )
</script>

<!-- MultiRow hosting the custom editors -->
@(Html.C1().MultiRow<Sale>()
    .Id("customEditorsMultiRow")
    .KeyActionTab(KeyAction.Cycle)
    .AllowAddNew(true)
    .AllowDelete(true)
    .LayoutDefinition(ld =>
    {
        ld.Add().Cells(cells =>
        {
            cells.Add(cell => cell.Binding("ID").Header("ID").IsReadOnly(true));
            cells.Add(cell => cell.Binding("Active").Header("Active"));
        });
        ld.Add().Cells(cells =>
        {
            cells.Add(cell => cell.Binding("Start").Header("Date").Width("150").Format("d").CellTemplate(ctb => ctb.EditTemplateId("edtDate")));
            cells.Add(cell => cell.Binding("End").Header("Time").Format("t").CellTemplate(ctb => ctb.EditTemplateId("edtTime")));
        });
        ld.Add().Colspan(2).Cells(cells =>
        {
            cells.Add(cell => cell.Binding("Country").Header("Country").Colspan(2).CellTemplate(ctb => ctb.EditTemplateId("edtCountry")));
            cells.Add(cell => cell.Binding("Product").Header("Product").CellTemplate(ctb => ctb.EditTemplateId("edtProduct")));
            cells.Add(cell => cell.Binding("Color").Header("Color").CellTemplate(ctb => ctb.EditTemplateId("edtColor")));
        });
        ld.Add().Cells(cells =>
        {
            cells.Add(cell => cell.Binding("Amount").Header("Amount").Format("n2").CellTemplate(ctb => ctb.EditTemplateId("edtAmount")));
            cells.Add(cell => cell.Binding("Amount2").Header("Amount2"));
        });
    })
    .Bind(bl => bl.Update(Url.Action("MultiRowEditorsUpdate"))
        .Create(Url.Action("MultiRowEditorsCreate"))
        .Delete(Url.Action("MultiRowEditorsDelete"))
        .Bind(Model))
    .OnClientCellEditEnding("cellEditEnding")
    .CssClass("multirow")
)

@section Description{
    <p>
        This sample shows how you can use custom editors to change the values in the cells of <b>MultiRow</b> control.
    </p>
    <p>
        The sample uses the <b>EditTemplateId</b> property to specify the id of the template for cell editor.
        When the user starts editing a cell, the editor will show and get the focus.
    </p>
    <p>
    There are three kinds of editors.
</p>
<ul class="normal">
    <li>
        <b>Using C1 Input controls which have "Value" or "Text" property</b>
        <p>
            You need to set the <b>EditTemplate</b> property of a cell.
        </p>
        <p>
            If the grid allows adding a new row, you need to set the editor's <b>IsRequired</b> to false.
            If you want the editor with the whole cell, you can set the style width to "100%".
        </p>
        <p>
            In this sample, "Date", "Time", "Country", "Amount" and "Color" use C1 Input controls as the editors.
        </p>
    </li>
    <li>
        <b>Using other control or a C1 control which has NO "Value" or "Text" property</b>
        <p>
            You need to use grid's <b>OnClientCellEditEnding</b> event and set
            <pre>
                     cellEditEndingEventArgs.cancel = true;
                </pre>
            to apply your updates.
        </p>
        <p>
            Then you need to consider when to update the cell value and remove the editor from a grid in your application.
            For example, when the editor blurs, we need to update the cell value and remove the editor.
        </p>
        <p>
            In this sample, the "Product" column uses &lt;input /&gt; as the editor.
        </p>
        <p>
            To get the binding column in the event handler, please use the MultiRow's <b>getBindingColumn</b> function.
        </p>
    </li>
    <li>
        <b>Using grid's internal editor</b>
        <p>
            In this sample, "Amount2" and "Active" use grid's internal editor. Here, you do not need to do anything.
        </p>
    </li>
</ul>
}