我是一名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一个答案。不得不选择,我认为罗德尼对托马斯的帮助最大。
答案 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>