【问题标题】:Do not post SelectList with Knockout不要发布带有 Knockout 的 SelectList
【发布时间】:2015-05-05 17:45:29
【问题描述】:

我正在使用 Knockout 运行 ASP.net MVC4 应用程序。

我有一个发布我的淘汰赛表格的通用脚本。

我需要优化发送到服务器的数据,因为当我发布我的 Knockout ViewModel 时,包含所有项目的 SelectList 也会发布!

示例服务器视图模型:

Public Class FooViewModel Public Property Bar As String Public Property Products As List(Of SelectListItem) End Class

将我的 Knockout ViewModel 转换为 JSON 的 JS 代码

var data = ko.toJSON(viewModel);

data 变量包含所有产品项目,并且不是很优化。

我找到了这段代码(有效):

viewModel.toJSON = function () {
        var copy = ko.toJS(this);
        // remove any unneeded properties           
        delete copy.Products;            
        return copy;
    }

但我需要一个通用解决方案...!在这里,我看不到如何使其通用...

一个快速而肮脏的解决方案是在每个数组属性上添加一个后缀,例如“_NoPost”,然后循环并删除每个具有这个后缀的属性,但它闻起来......很糟糕:/

有什么想法吗?

【问题讨论】:

  • 如果您只想传递产品数组而不是总 viewModel 数据,为什么不能像这样尝试ko.toJSON(this,products)
  • 您好,感谢您的尝试。 1°)这是相反的,我不想要产品数组 2°)我想要一种通用的方式来做到这一点。算法语句看起来像“将数据发送到服务器,除了所有 SelectList”因为发布数据的脚本不知道他必须忽略哪些数组属性。我清楚还是应该在我的问题中添加一些细节?
  • “通用”是什么意思?你的意思是 Vanilla JS 而不是 Knockout?如果是这样,您实际上是在要求对 Knockout 映射插件或 Knockout ko.toJS 函数进行 vanilla JS 重写。此外,为什么不立即排除对 ko.toJSON 的调用中的属性,以便您可以从中检索干净的对象你的数据库(而不是在ko.toJS 电话中)??
  • 我的意思是“通用”:在属性上放置一个标志或其他东西以忽略它向服务器发布数据。而不是删除必须忽略的每个 viewModel 的每个属性。

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


【解决方案1】:

一种选择是将表单数据与查找数据分开,如下所示。当您需要将表单数据发布到服务器时,这将允许您只获取表单数据。

Public Class FormViewModel
     Public Property Bar As String
End Class

Public Class FooViewModel
     Public Property FormData As FormViewModel
     Public Property Products As List(Of SelectListItem)
End Class

这会让你

var data = ko.toJSON(viewModel);
$post(url, data.FormData, function(d){...});

在您的 HTML 中,您还必须包含 FormData 作为变量的一部分,即

<input data-bind="value: FormData.Bar">

编辑

根据您的反馈,您可以使用以下函数为您构造一个“干净”的对象。这个想法是传入原始 JSON 对象以及一个映射对象,该对象将指示哪些属性应该被排除/留下:

function MapJson(obj, map) {

    if (obj == undefined)
        return;

    map = map || {};
    var ret = {};

    for (var prop in obj) {

        if (map[prop] != undefined && map[prop] == false)
            continue;

        if (typeof obj[prop] !== "object")
            ret[prop] = obj[prop];
        else {
            if (map.constructor == Array) {
                ret[prop] = MapJson(obj[prop], map[0]);
            }
            else
                ret[prop] = MapJson(obj[prop], map[prop]);
        }

    }

    return ret;
}

然后您可以像这样使用它 - 通过将属性的值设置为 false,它将从数据中排除。该示例显示了如何阻止子对象中的数组以及数组中的数组:

var obj = {
    Name: "John Doe",
    Vehicle: {
        Details: {
            Make: "Mazda",
            Model: 2010
        },
        Registration: "ABC123",
        ServiceDates: ["01 Jan", "23 Feb", "13 March"]
    },
    WeekDays: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
    Children: [{ Name: "Mary", Age: 4, Hobbies: ["Soccer", "Chess", "Swim"] }, { Name: "Jane", Age: 2, Hobbies: ["Tennis", "Movies", "Reading"] }]
};

var map = {
    Vehicle: {
        ServiceDates: false
    },
    Children: [{
        Hobbies: false,
    }]
};

MapJson(obj, map);

希望对你有帮助。

编辑 2

这里有一个基于您在评论中发布的数据的工作示例。

 var vm = {
    "Type":"PropertyTax",
    "Label":"d",
    "StartDate":"2015-01-01T00:00:00",
    "EndDate":"2015-12-31T00:00:00",
    "Value":0,
    "RegularizationMonth":0,
    "TotalConsumption":null,
    "UnitPrice":null,
    "Active":true,"Products":[{"Selected":false,"Text":"XXX 39","Value":"28"},{"Selected":false,"Text":"ZZZ","Value":"38"}],"ChargeProducts":[{"ProductID":"28","Products":[{"Selected":false,"Text":"XXX 39","Value":"28"},{"Selected":false,"Text":"XXX 41","Value":"8"}]}],
    "map":{"Products":false,"ChargeProducts":[{"Products":false}]}
    };

    var result = MapJson(vm, vm.map);

    console.log("Result: ", result);

【讨论】:

  • 您好,感谢您的回答。这可能有效,但我在某些情况下 FormViewModel 有带有产品数组的子 ViewModel 也可以忽略......您的解决方案仅适用于第一级 ViewModel。它应该是递归的。示例 : Public Class FormViewModel Public Property Bar As String Public Property ChildViewModel as ChildVM End Class Public Class ChildVM Public Property ID as Integer Public Property Products As List(Of SelectListItem) (=> ToIgnore) End Class
  • 您希望排除所有集合/列表,还是需要保留一些(发布到服务器)?
  • 并非所有收藏!有些人必须活下去:)
  • 我已经更新了答案以包含一个可能的解决方案,用于根据映射对象动态排除某些 JSON 数据。
  • 感谢您的编辑。我试过你的功能:viewModel.map = { Products: false, ChargeProducts: [{ Products: false }] }; //稍后 var data = ko.toJSON(viewModel);数据 = MapJson(数据,viewModel.map);这是行不通的。在 console.log 中的数据我有 Object { 0: "{", 1: """, 2: "T", 3: "y", 4: "p", 5: "e", 6: "" "等...我放了一个 console.log("property : " + prop + " value : " + ret[prop]);在 MapJson 中,它似乎为原始 JSON 上的每个字符找到了一个属性“属性:2976 值:s”“属性:2977 值:[”等
【解决方案2】:

如果您使用 KO.Mapping,您可以选择忽略某些部分。

            var mapping = { 'ignore': ["SomeFieldProperty"] };
            ko.mapping.fromJS(data, mapping, viewModel);

文档中的这一部分列出了您可以操纵 ko.mapping 来来去去的绑定的所有方法:

http://knockoutjs.com/documentation/plugins-mapping.html

向下滚动到底部以查看 ignore 上的内容以及涵盖如何管理绑定和解除绑定的主题。

【讨论】:

  • 您好,谢谢您的回答。我需要对数组进行绑定,因为它们可以通过 ajax 调用加载。此外,您的解决方案需要针对每个不同 ViewModel 的特定代码(在转换为 JSON 时,我有删除 viewModel.PropertyToIgnore 的解决方案)。
  • 我可能误解了,但我使用忽略映射从 ajax 调用中抓取一个巨大的对象,然后使用忽略忽略其中我不需要观察的数组上的绑定(列出选项列表,以及每个选项的选项,选项不需要绑定,因为我只是将它们用作选项的数据源)。此外,将它们送回 - 它不会将它们呈现出来。最后,我会放弃 ko.mapping - 它非常方便,但虽然需要更多的前期准备,但我发现只滚动我自己的 VM 会更容易。
猜你喜欢
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-02
  • 1970-01-01
相关资源
最近更新 更多