【问题标题】:How to save VM back to Server with KnockoutJs如何使用 KnockoutJs 将 VM 保存回服务器
【发布时间】:2016-06-12 22:52:29
【问题描述】:

我在服务器上有一个带有 EF 6 的 ASP.Net MVC5 应用程序。该网站有十几个页面,每个页面都有一个网格,显示包含许多列的业务数据。

某些用户不会对某些页面(视图)上的某些列感兴趣,因此我需要一种方法让他们指出要使哪些视图可见。

在数据库中,一个 View 有很多 Columns,一个 User 可以指定要显示的任何视图的列(因此存储在 UserViewColumn 表中):

我正在使用以下 ViewModel 将从数据库中选择的数据传回给 View:

public class UserPrefsViewModel
    {
        public ICollection<VmUser> Users { get; set; }

        public UserPrefsViewModel()
        {
            this.Users = new List<VmUser>();
        }
    }

    public class VmUser
    {
        public int UserId { get; set; }
        public string AdLogonDomain { get; set; }
        public string AdLogonId { get; set; }
        public List<VmView> Views { get; set; }
    }

    public class VmView
    {
        public int ViewId { get; set; }
        public string Name { get; set; }
        public List<VmColumn> AllColumns { get; set; }
        public List<VmColumn> VisibleColumns { get; set; }
    }

    public class VmColumn
    {
        public int ColumnId { get; set; }
        public string Heading { get; set; }
    }

剃刀视图如下:

@model TVS.ESB.BamPortal.Website.Models.UserPrefsViewModel
@using System.Web.Script.Serialization
@{
    ViewBag.Title = "User Preferences";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>@ViewBag.Title</h2>
@{  string data = new JavaScriptSerializer().Serialize(Model); }

<div id="ViewsAndColumns" class="container">
    <div class="row">
        <div id="Views" class="col-md-3 pull-left">
            <span class="label-info">Views</span>
            <br />
            <table>
                <tr>
                    <td>
                        <select style="width:100px" size="5" data-bind="options:views, optionsText: 'Name', value:selectedView"> </select>
                    </td>
                </tr>
            </table>
        </div>
        <div id="Columns" class="col-md-9 pull-right">
            <table>
                <tr>
                    <td>
                        <span class="label-info">Available Columns</span>
                    </td>
                    <td>
                        <span class="label-info">To Display</span>
                    </td>
                </tr>
                <tr>
                    <td>
                        <select size="10" data-bind="options:allColumns, optionsText: 'Heading', value:selectedAvailableColumn"></select>
                    </td>
                    <td>
                        <select size="10" data-bind="options:columnsToAdd, optionsText: 'Heading', value:selectedColumnToRemove"></select>
                    </td>
                </tr>
                <tr>
                    <td>
                        <button class="btn-default" data-bind="click:addColumn">Add</button>
                    </td>
                    <td>
                        <button class="btn-default" data-bind="click:removeColumn">Remove</button>
                    </td>
                </tr>
                <tr>
                    <td>
                        <button class="btn-danger" data-bind="click:saveToDatabase.bind($data, '@ViewBag.Domain', '@ViewBag.LoginId')">Save to Database</button>
                    </td>
                </tr>
            </table>
        </div>
    </div>
</div>



@section Scripts {
    <script src="~/KnockoutVM/UserPrefs.js"></script>

    <script type="text/javascript">
        var vm = new ViewModel(@Html.Raw(data));
        ko.applyBindings(vm, document.getElementById("UserPrefsDiv"));
    </script>
}

这是一个屏幕截图:

我正在使用 knockoutjs 使用户能够将列从第一个选择列表添加到第二个,这是我的敲除文件:

function ViewModel(data) {
    var self = this;
    var viewColumns;
    var visibleViewColumns

    self.selectedAvailableColumn = ko.observable();
    self.selectedView = ko.observable(data.Users[0].Views[0]);
    self.views = ko.observableArray(data.Users[0].Views);
    self.selectedAvailableColumn = ko.observable();
    self.columnsToAdd = ko.observableArray();
    self.selectedColumnToRemove = ko.observable();

    var getById = function (items, id) {
        return ko.utils.arrayFirst(items(), function (item) {
            return item.ViewId == id;
        });
    };

    self.allColumns = ko.computed(function () {
        var view = getById(self.views, self.selectedView().ViewId);
        return view ? ko.utils.arrayMap(view.AllColumns, function (item) {
            return {
                ColumnId: item.Id,
                Heading: item.Heading
            };
        }) : [];
    }, this);

    self.addColumn = function () {
        if (self.columnsToAdd().indexOf(self.selectedAvailableColumn()) < 0) {
            self.columnsToAdd.push(self.selectedAvailableColumn());
        }
    };

    self.removeColumn = function () {
        self.columnsToAdd.remove(self.selectedColumnToRemove());
    };

    self.saveToDatabase = function () {
        var jsSaveModel = ko.toJS(data);

        $.ajax({
            type: "POST",
            url: location.href,
            data: ko.toJSON(jsSaveModel),
            contentType: 'application/json',
            async: true
        });
    };
};

我的问题是,我不知道在发布到服务器之前如何最好地管理这个淘汰视图模型以使其持久保存到数据库中。如您所见,我目前将数据从服务器 VM 加载到绑定到视图控件的可观察数组中。在服务器端 VM 中,它将是 User[x].Views[y].VisibleColumns 集合,我将使用它来填充 UserViewColumn 表,标识用户希望显示的列。

我想一种方法是更改​​ Knockout ViewModel 接收的 data 参数。在将 data 发布到服务器之前,我可以在 self.SaveToDatabase 函数中执行此操作吗?由于我对 Knockout 或任何 MVVM 框架的经验很少,因此我将不胜感激有关最佳实践的任何建议。

【问题讨论】:

    标签: mvvm knockout.js


    【解决方案1】:

    这可能会因为过于宽泛和基于意见而被标记,但我个人使用 AJAX。虽然这确实需要第二次往返服务器,但它会缩短显示时间,并且您可以在检索数据本身时显示微调器或其他东西。它还更加灵活,因为它允许您更轻松地在一台机器上托管内容并在另一台机器上托管数据,随着您的用户群增加以及您的托管解决方案需要平衡多台服务器之间的流量,这一点变得非常重要。

    无论如何,这里是您的 AJAX 处理程序在服务器端的样子:

        public class Model
        {
            public string Data { get; set; }
        }
    
        [HttpGet]
        public JsonResult GetModel(/* can use params here if required */)
        {
            var model = new Model { Data = "Some data" };
            return Json(model, JsonRequestBehavior.AllowGet);
        }
    
        [HttpPost]
        public JsonResult PostModel(Model model)
        {
            var result = new { status = "success"};
            return Json(result);
        }
    

    和客户端:

        getModel: function () {
            var self = this;
            $.ajax({
                url: "/GetModel",
                method: "GET",
                dataType: "json",
                success: function (model) {
                    // do something with model here and then let's post it back to the server
                    self.postModel(model);
                },
                fail: function () {
                    alert("Failed to retrieve model");
                },
                cache: false
            });
        },
    
        postModel: function (model) {
            var self = this;
            $.ajax({
                url: "/PostModel",
                method: "POST",
                data: model,
                dataType: "json",
                success: function (status) {
                    alert("Submitted!");
                },
                fail: function () {
                    alert("Failed to post model");
                },
                cache: false
            });
        }
    

    您通常需要做的是根据这些数据创建一个视图模型,the knockout site 提供了有关如何执行此操作的更多详细信息。

    【讨论】:

      猜你喜欢
      • 2013-01-21
      • 2010-10-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-06
      • 2019-03-30
      相关资源
      最近更新 更多