MVC4 Knockoutjs绑定到列表<>

时间:2013-05-30 22:47:24

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

我是一名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>
}

任何帮助都会非常感激,或者如果我错过了显而易见的问题,或者如果这个问题出现之前请指出我正确的方向。

此致

修改

来自托马斯和罗德尼的回答,似乎我错误地假设了一些淘汰赛的行为。 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一个答案。不得不选择,我认为罗德尼对托马斯的帮助最大。

2 个答案:

答案 0 :(得分:3)

使用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来在文档准备就绪时执行applyBinding。

答案 1 :(得分: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>