KendoUI - 如何根据用户输入在运行时创建控件?

时间:2014-01-03 00:42:51

标签: javascript kendo-ui kendo-grid kendo-asp.net-mvc

有没有办法在运行时在KendoUI网格列中创建不同类型的控件?场景是,我的网格中有2列。第一列显示一个下拉列表,其中包含一些字符串,如'Name','StartDate'等。当用户从中选择一个值时,我想在第二列中显示一个适当的控件。如果用户选择“StartDate”,我想显示“DateTime”控件。你能通过ASP.Net MVC 5包装让我知道怎么做吗?

示例代码:

@(Html.Kendo().Grid<ArulUI.Models.UserFilter>()
    .Name("Grid")
    .Columns(columns =>
    {
        columns.ForeignKey(f => f.FilterName, (System.Collections.IEnumerable)ViewData["Filters"], "Name", "Name");
        columns.Bound(f => f.FilterValue).ClientTemplate("#= gridValueColumnFormatter(data) #");

        columns.Template(t => { }).HeaderTemplate("").ClientTemplate(@"
            <a href='javascript: void(0)' class='abutton delete' onclick='deleteRow(this)' title='remove'>remove</a>")
             .Width(100).Title("");
    })
    .ToolBar(toolbar =>
    {
        toolbar.Create();
        toolbar.Save();
    })

    .Editable(editable => editable.Mode(GridEditMode.InCell))
    .Editable(e => e.DisplayDeleteConfirmation(false))
    .Sortable()
    .Scrollable()
    .Events(e => e.Edit("onEdit"))
    .DataSource(dataSource => dataSource
        .Ajax()
        .ServerOperation(false)
        .Model(model =>
        {
            model.Id(f => f.Id);
            model.Field(f => f.Id).Editable(false);
        })
        .Create(create => create.Action("Filter_Create", "Home"))
        .Destroy(destroy => destroy.Action("Filter_Delete", "Home"))
        .Read(read => read.Action("Filter_Read", "Home"))
        .Update(update => update.Action("Filter_Update", "Home"))
    )
)

<script>

    function gridValueColumnFormatter(dataRow) {
        var returnValue = "";
        if (dataRow.FilterName == "DateTimeRange") {
            returnValue = kendo.format('{0:MM/dd/yyyy hh:mm}', new Date(dataRow.FilterValue));
        }
        else {
            returnValue = dataRow.FilterValue;
        }

        return returnValue;
    }


    function onEdit(e) {
        var actElement = document.activeElement;
        //alert(txt.id);
        if (actElement.id == "FilterValue") {
            var selectedValue = e.model.FilterValue;
            var selectedDate = Date.parse(selectedValue);
            console.log(selectedValue);
            console.log(selectedDate);

            if (e.model.FilterName == "DateTimeRange") {
                if (isNaN(selectedDate)) {
                    initDatePicker(new Date());
                } else {
                    //initDatePicker(selectedValue);
                    $("#FilterValue").kendoDateTimePicker({
                        value: new Date(selectedValue)
                    });
                }
            } else {
                if (!isNaN(selectedDate)) {
                    $("#FilterValue").val("");
                }
            }
        }
    }

    function initDatePicker(dateValue) {
        $("#FilterValue").empty();

        $("#FilterValue").kendoDateTimePicker({
            value: new Date(dateValue),
            format: "MM/dd/yyyy hh:mm",
            parseFormats: "MM/dd/yyyy hh:mm"
        });
        var dateTimePicker = $("#FilterValue").data("kendoDateTimePicker");
        dateTimePicker.value(dateValue);

    }

    function disposeDatePicker() {
        var datepicker = $("#FilterValue").data("kendoDateTimePicker");
        if (datepicker) {
            popup = datepicker.dateView.popup;
            element = popup.wrapper[0] ? popup.wrapper : popup.element;

            //Move the shared calendar to the body
            kendo.ui.DatePicker.sharedCalendar.element.hide().appendTo(document.body);

            //remove popup element;
            element.remove();
            //unwrap element
            var input = datepicker.element.show();

            input.removeClass("k-input"); //.css("width", "auto");
            input.insertBefore(datepicker.wrapper);

            datepicker.wrapper.remove();

            //remove DatePicker object
            input.removeData("kendoDateTimePicker");
        }
    }

    function deleteRow(element) {
        grid = $("#Grid").data("kendoGrid");
        grid.removeRow($(element).closest("tr"));
    }

    function createRow() {
        grid = $("#Grid").data("kendoGrid");
        grid.addRow();
    }
</script>

Controller:

public class HomeController : Controller
    {
        public static List<ArulUI.Models.Filter> ListFilter = new List<ArulUI.Models.Filter>();
        public static List<UserFilter> ListUserFilters = new List<UserFilter>();
        public void Seed()
        {
            ListFilter = new List<Models.Filter>{
                new ArulUI.Models.Filter { Name = "Name", Type="string"},
                new ArulUI.Models.Filter { Name = "Dept", Type="string"},
                new ArulUI.Models.Filter { Name = "Age", Type="string"},
                new ArulUI.Models.Filter { Name = "DateTimeRange", Type="datetime"}
            };

            ListUserFilters = new List<UserFilter> {
                new UserFilter { Id = 1, FilterName="Name", FilterValue = "Empty"},
                new UserFilter { Id = 2, FilterName="Dept", FilterValue = "Empty2"},
                //new UserFilter { Id = 2, FilterName="DateTimeRange", FilterValue = "12/20/2013 10:00"}
            };
        }

        public ActionResult Index()
        {
            this.Seed();
            ViewData["Filters"] = ListFilter.Select(f => new
            {
                Name = f.Name,
                Type = f.Type
            });

            return View();
        }

        public ActionResult Filter_Read([DataSourceRequest] DataSourceRequest request)
        {
            return Json(ListUserFilters.ToDataSourceResult(request));
        }

        public ActionResult Filter_Delete([DataSourceRequest] DataSourceRequest request, UserFilter userFilter)
        {
            if (userFilter != null && ModelState.IsValid)
            {
                var target = ListUserFilters.Where(f => f.Id == userFilter.Id).FirstOrDefault();

                if (target != null)
                {
                    ListUserFilters.Remove(target);
                }
            }

            return Json(ModelState.ToDataSourceResult());
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult Filter_Update([DataSourceRequest] DataSourceRequest request, UserFilter userFilter)
        {
            if (userFilter != null && ModelState.IsValid)
            {
                var target = ListUserFilters.Where(f => f.Id == userFilter.Id).FirstOrDefault();
                if (target != null)
                {
                    int targetIndex = ListUserFilters.IndexOf(target);
                    ListUserFilters[targetIndex].FilterName = target.FilterName;
                    ListUserFilters[targetIndex].FilterValue = target.FilterValue;
                }
            }

            return Json(ModelState.ToDataSourceResult());
        }

        public ActionResult Filter_Create([DataSourceRequest] DataSourceRequest request, UserFilter userFilter)
        {
            userFilter.Id = ListUserFilters[ListUserFilters.Count - 1].Id + 1;
            userFilter.Id = 10;
            ListUserFilters.Add(userFilter);

            return Json(new[] { userFilter }.ToDataSourceResult(request, ModelState));
        }


        public ActionResult About()
        {
            ViewBag.Message = "Your application description page.";

            return View();
        }

        public ActionResult Contact()
        {
            ViewBag.Message = "Your contact page.";

            return View();
        }
    }

谢谢

1 个答案:

答案 0 :(得分:1)

您可能必须自己实施,例如通过绑定下拉列表的change event将选定的控件类型(例如“kendoDatePicker”)存储在某个变量中,然后有一个数据结构,为每种控件类型提供适当的选项。然后,您可以根据该控件类型变量使第二列的编辑器模板动态化。

如果您使用内联编辑并且想要直接替换编辑器,则下拉更改处理程序可能看起来像这样(请注意,为了很好地显示各种值类型,您可能还需要一个复杂的显示模板):

change: function (e) {
    // select other column by index, for example
    var secondColumn = $(e.sender.element).closest("td").siblings().eq(0);
    var name = $(secondColumn).find("input").attr("name");
    secondColumn.empty(); // remove existing editor (you should also call .destroy() for existing widgets in there!)
    var model = grid._modelForContainer(secondColumn); // get associated data model from kendoGrid instance

    $("<input data-bind='value: " + name + "'/>").appendTo(secondColumn).kendoDatePicker();
    kendo.bind(secondColumn, model); // bind the model again manually
}

请参阅demo here

如果您使用单元格内编辑,那么您应该使用我之前建议的编辑器模板;动态列的模板函数可能如下所示:

editor: function (container, options) {
    // model.typeTitle is set by the dropdown column
    if (options.model.typeTitle === "DateTime") {
        $("<input data-bind='value:name' />")
            .appendTo(container).kendoDateTimePicker(controlOptions["kendoDateTimePicker"]);
    } else if (options.model.typeTitle === "String") {
        $("<input data-bind='value:name' />")
            .appendTo(container);
    } else if (options.model.typeTitle === "Number") {
        $("<input data-bind='value:name' />")
            .appendTo(container).kendoNumericTextBox();
    }  
}

Demo here