在我的应用程序中,我有一个来自服务器的Books
列表。
我使用ko.mapping
为从Book
AJAX调用点击客户端的每个GetBooks
生成可观察属性。
这很有效 - 映射正在处理我必须手动处理的许多“噪音”。
但是说我想创建一个新的Book
。我一直养成为所有模型创建具有空属性的对象的习惯 - 所以对于book
,我有类似的东西:
var defaultBook = {
title: null,
price: null,
genre: null,
pages: null
}
然后,当我创建新Book
时,我只需ko.mapping.fromJS(defaultBook)
和applyBindings
到我的add
表单。
这是新对象创建的标准方法 - 在客户端的某处保留空模型的集合吗?我觉得这是一个愚蠢的问题但只是想确保我不会错过一个更好,更标准的模式。这让我很痛苦,因为这意味着如果我在服务器上更改属性名称,我需要在我的客户端模型定义上更改它......但也许这是不可避免的。
答案 0 :(得分:0)
我昨天遇到了这个问题
MyApp.PersonNameEditViewModel = MyApp.define({
init: function (data) {
var fields = {
nameTypeId: null,
personNameId: null,
personId: null,
firstname: "",
prefix: "",
surname: ""
}
this.nameTypeId = null;
this.personNameId = null;
this.firstname = ko.observable().extend({ required: true });
ko.utils.extend(fields, data);
ko.mapping.fromJS(fields, {}, this);
this.name = ko.computed(this.getName, this);
this.title = this.name;
this.new = this.personNameId === null;
},
prototype: {
getName: function () {
var parts = [this.surname(), this.firstname(), this.prefix()];
return ko.utils.arrayFilter(parts, function(part) {
return part != "";
}).join(", ") || "Untitled";
}
}
});
我正在使用发送到构造函数
的数据扩展fields对象ko.utils.extend(fields, data);
这种方式既可以用于新添加的行,也可以用于后端的现有行。我从映射插件
中使用它var mapping = {
personNames: {
create: function (options) {
return new MyApp.PersonNameEditViewModel(options.data);
}
}
}
ko.mapping.fromJS(data, mapping, this);
创建新行时
newAlternativname: function () {
new MyApp.DetailsEditViewModel(new MyApp.PersonNameEditViewModel({ personId: this.personId(), nameTypeId: MyApp.NameTypes.AlternativeName }), true, this.personNames).modal();
}
正如您所看到的,我将一些内容作为数据发送,但在添加新行时并非全部,ko.utils.extend
确保通过ko.mapping.fromJS
添加和映射缺少的字段
答案 1 :(得分:0)
虽然@Anders的答案是好的和正确的(你应该在客户端这样做),但它只涉及客户端和TO询问服务器端的模型更改。这是我在类似情况下所做的。我为StringBuilder创建了一个扩展方法,用于构建javascript变量:
public static class ScriptBuilder
{
public static StringBuilder BuildGlobalVariable(this StringBuilder sb, string name, object value)
{
return sb.AppendFormat("var {0} = {1};", name,
JsonConvert.SerializeObject(value, new JsonSerializerSettings()
{
ContractResolver = new CamelCasePropertyNamesContractResolver()
}));
}
}
CamelCasePropertyNamesContractResolver()仅用于以小写形式创建属性名称,以遵循javascript表示法。然后在我的JsModelsController中我有这个方法:
public class JsModelsController : Controller
{
public JavaScriptResult ServerModels()
{
var sb = new StringBuilder();
return sb.BuildGlobalVariable("Book", new Book()).ToString();
}
}
书籍在哪里:
public class Book
{
public string Title { get; set; }
public string Price { get; set; }
public string Genre { get; set; }
public int? Pages { get; set; }
}
所以现在你只需要在_Layout.cshtml页面的某处添加一个脚本标签,如下所示:
<script src="JsModels/ServerModels"></script>
希望它应该在您的页面上加载以下脚本:
var Book = {&#34; title&#34;:null,&#34; price&#34;:null,&#34; genre&#34;:null,&#34; pages&#34;:null };
P.S。我知道创建全局JS对象是一种不好的做法,因此您可以将所有服务器模型累积到一个JS全局对象中,如下所示:
return sb.BuildGlobalVariable("ServerModels", new
{
Book = new Book(),
Person = new Person()
}).ToString();
Person是另一个服务器类。这也不完美,但允许只有一个全局JS变量,其中包含所有服务器模型。