0

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

我想把答案交给托马斯和罗德尼。不得不选择,我认为罗德尼帮助了最对不起托马斯。

4

2 回答 2

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 来在文档准备好时执行 applyBindings。

于 2013-05-30T23:58:00.813 回答
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>
于 2013-05-30T23:15:30.383 回答