【问题标题】:MVC4 Knockoutjs binding to a list<>MVC4 Knockoutjs 绑定到列表<>
【发布时间】:2013-05-26 16:09:32
【问题描述】:

我是一名 C# MVC 开发人员,希望将我的客户端 javascript 从混乱的事件处理程序发展为更有条理的系统,因此我开始研究 knockoutjs。最初它看起来很棒,关于如何将它放入我的生产环境的想法正在迅速形成。我已经尝试了一些基本原则,所有这些原则都非常有效,没有问题。 我想尝试一些更复杂的东西(特定于我正在从事的项目),但我无法让它工作。

我尝试搜索其他示例,但没有真正找到匹配的内容。

我想做的是将对象列表绑定到客户端。在这个例子中,我使用了一个人列表,我在页面上显示了这个列表,并且想在一个 ajax 请求上更新页面上的所有人(这个例子纯粹是为了测试而捏造的,但原理就是我之后)。

我正在使用 knockoutjs 映射插件为我做模型映射

我的 C# 代码

 public class HomeController : Controller
    {
        public ActionResult Index()
        {
            List<Person> people = new List<Person>()
            {
               new Person()
                {
                    FirstName = "Neil",
                    LastName = "Diamond"
                },
                new Person()
                {
                    FirstName = "Bob",
                    LastName = "Seager"
                },
                new Person()
                {
                    FirstName = "Tom",
                    LastName = "Jones"
                }
            };

            return View(people);
        }

        public JsonResult UpdateNames()
        {
            Random r = new Random();
            var num = r.Next(1, 100);
            List<Person> people = new List<Person>()
            {
               new Person()
                {
                    FirstName = string.Concat("Neil", num.ToString()),
                    LastName = string.Concat("Diamond", num.ToString())
                },
                new Person()
                {
                    FirstName = string.Concat("Bob", num.ToString()),
                    LastName = string.Concat("Seager", num.ToString())
                },
                new Person()
                {
                    FirstName = string.Concat("Tom", num.ToString()),
                    LastName = string.Concat("Jones", num.ToString())
                }
            };
            return Json(people, JsonRequestBehavior.AllowGet);
        }
    }

我的看法

@model List<TestingKnockout.Models.Person>

@{
    ViewBag.Title = "Home Page";
}

@for (int i = 0; i < Model.Count; i++)
{
    <p>Firstname: <strong data-bind="text: [@i].FirstName"></strong></p>
    <p>Lastname: <strong data-bind="text: [@i].LastName"></strong></p>
    <hr />
}

@section scripts
{
    <script src="~/Scripts/knockout-2.1.0.js"></script>
    <script src="~/Scripts/knockout.mapping.js"></script>
    <script type="text/javascript">
        var viewModel = {};
        $.ajax({
            url: "/Home/UpdateNames",
            cache: false,
            success: function (data) {
                viewModel = ko.mapping.fromJS(data);
                ko.applyBindings(viewModel);
            }
        });

        setInterval(function () {
            $.ajax(
                {
                    url: "/Home/UpdateNames",
                    cache: false,
                    success: function (data) {
                        ko.mapping.fromJS(data, viewModel);
                    }
                });
        }, 5000);
    </script>
}

任何帮助将不胜感激,或者如果我遗漏了明显的内容,或者如果这个问题之前出现过,请指出正确的方向。

问候

编辑

根据 Tomas 和 Rodney 的两个答案,我似乎错误地假设了某些淘汰行为。 Knockout 必须从整个模型作为 JSON 开始,然后从那里更新。我希望用初始数据呈现 HTML,然后淘汰以处理更新,但我认为我的方法不正确。 使用 Tomas 的 HTML 并借鉴 Rodney 的代码(对 json 序列化和人员可观察的细微更改),我将视图代码更改为以下代码,现在一切似乎都运行良好

@model List<TestingKnockout.Models.Person>

@{
    ViewBag.Title = "Home Page";
}

<div data-bind="foreach: people">
    <p>Firstname: <strong data-bind="text: FirstName"></strong></p>
    <p>Lastname: <strong data-bind="text: LastName"></strong></p>
    <hr />
</div>
@section scripts
{
    <script src="~/Scripts/knockout-2.1.0.js"></script>
    <script src="~/Scripts/knockout.mapping.js"></script>
    <script type="text/javascript">
        var viewModel = {
            people:  ko.mapping.fromJS(@Html.Raw(Json.Encode(Model)))    
            };
        ko.applyBindings(viewModel);    

        setInterval(function () {
            $.ajax(
                {
                    url: "/Home/UpdateNames",
                    cache: false,
                    success: function (data) {
                        ko.mapping.fromJS(data, viewModel.people);
                    }
                });
        }, 5000);
    </script>
}

我想把答案告诉 Tomas 和 Rodney。不得不选择,我认为罗德尼对托马斯的帮助最大。

【问题讨论】:

  • 您还想查看 SignalR 吗?真的很好,不用手动轮询服务器。
  • 投票只是举例,我打算用signalR

标签: c# asp.net-mvc-4 razor knockout.js knockout-mapping-plugin


【解决方案1】:

使用 Tomas 回答中的 HTML。

您需要将您的初始 c# 模型序列化为 javascript 列表。一种流行的方法是使用 JSON.NET 库。

将此c#代码添加到视图的开头

@using Newtonsoft.Json
@{
    var jsPeople = Html.Raw(JsonConvert.SerializeObject(Model));
}

用以下内容替换所有 javascript:

var viewModel = { people: ko.observable([]) };
viewModel.people(ko.mapping.fromJS(@jsPeople));

setInterval(function () {
    $.ajax(
    {
        url: "/Home/UpdateNames",
        cache: false,
        success: function (data) {
            viewModel.people(ko.mapping.fromJS(data));
        }
    });
}, 5000);

$(document).ready(function(){
    ko.applyBindings(viewModel);
});

哦,我应该提一下,我在这里使用 jquery 来在文档准备好时执行 applyBindings。

【讨论】:

    【解决方案2】:

    您错过了应该如何使用它的要点。您应该设置视图模板 (HTML)。然后以 JSON 格式加载数据(或者它可以与正在提供的页面一起)。

    可以在加载数据之前或加载初始数据集之后应用绑定。但这应该只发生一次。您应该放弃使用 ASP.NET MVC 视图渲染模型的习惯。 Knockout 应该负责将数据绑定到您的 HTML 模板。

    您可以在数据加载之前或加载期间控制屏幕上的可见内容。您的应用程序逻辑将在您的 JavaScript 中,您可以在其中操作对象,UI 更新由 Knockout 处理。

    <div data-bind="foreach: people">
       <p>Firstname: <strong data-bind="text: FirstName"></strong></p>
       <p>Lastname: <strong data-bind="text: LastName"></strong></p>
    </div>
    

    【讨论】:

    • 原谅我,我想我理解你所解释的概念,但我很难在现场申请。如果愿意,您能否使用更多代码进行详细说明?具体给出我问题中的代码,我应该改变什么才能让它工作?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-03
    • 1970-01-01
    • 2012-11-23
    • 2016-04-12
    • 1970-01-01
    • 2015-05-14
    • 1970-01-01
    相关资源
    最近更新 更多