Knockout foreach绑定仅显示第一个虚拟元素数据

时间:2012-11-15 19:37:40

标签: asp.net-mvc knockout.js asp.net-web-api

在网格上列出虚拟元素属性时,我遇到了淘汰赛的foreach绑定问题。

虽然web api按预期返回JSON数据,但是knockout并未正确显示虚拟元素属性。

我的UI显示产品列表,其中一个列是ProductCategory.Name。由于某种原因,它只显示每个产品类别的第一个外观。

Name        Category

Pr01        Cat01
Pr02        
Pr03        Cat02
Pr04        Cat03
Pr05        

第2和第5产品也是“Cat01”类别的产品。但由于某种原因,它没有显示出来。

我有以下型号:

public class Product
{
    [ScaffoldColumn(false)]
    public int ProductId { get; set; }

    public string Name { get; set; }
    public int ProductsCategoryId { get; set; }

    public virtual ProductsCategory ProductCategory { get; set; }
}

public class ProductsCategory
{
    public int ProductsCategoryId { get; set; }

    public string Name { get; set; }
}

这就是我绑定网格的方式:

<tbody data-bind="foreach: products">
    <tr>            
        <td class="left" data-bind="text: $data.Name"></td>
        <td class="left" data-bind="text: $data.ProductCategory.Name"></td>
    </tr>
</tbody>

这是JSON:

[{
    "$id": "1",
    "ProductCategory": {
        "$id": "2",
        "ProductsCategoryId": 1,
        "Reference": "OSOL                            ",
        "Name": "Óculos de Sol",
        "ProductsCategoryStatusId": 1
    },
    "ProductId": 3,
    "Reference": "HTHTOD                          ",
    "BarCode": "2122071530085                   ",
    "Name": "Thin Hard Trivex OD",
    "Description": null,
    "ProductsBrandId": 1,
    "ProductsCategoryId": 1,
    "ProductsSupplierId": 1,
    "ProductStatusId": 1
}, {
    "$id": "3",
    "ProductCategory": {
        "$ref": "2"
    },
    "ProductId": 4,
    "Reference": "HTHTOE                          ",
    "BarCode": "2122071531163                   ",
    "Name": "Thin Hard Trivex OE",
    "Description": "null",
    "ProductsBrandId": 1,
    "ProductsCategoryId": 1,
    "ProductsSupplierId": 1,
    "ProductStatusId": 1
}, {
    "$id": "4",
    "ProductCategory": {
        "$id": "5",
        "ProductsCategoryId": 2,
        "Reference": "OGRAU                           ",
        "Name": "Óculos de Grau",
        "ProductsCategoryStatusId": 1
    },
    "ProductId": 10,
    "Reference": "HTHTOX                          ",
    "BarCode": "2123180206342                   ",
    "Name": "Thin Hard Trivex OX",
    "Description": null,
    "ProductsBrandId": 2,
    "ProductsCategoryId": 2,
    "ProductsSupplierId": 1,
    "ProductStatusId": 1
}, {
    "$id": "6",
    "ProductCategory": {
        "$id": "7",
        "ProductsCategoryId": 3,
        "Reference": "LNTS                            ",
        "Name": "Lentes",
        "ProductsCategoryStatusId": 1
    },
    "ProductId": 16,
    "Reference": "HTHTOY                          ",
    "BarCode": "2123192208431                   ",
    "Name": "Thin Hard Trivex OY",
    "Description": null,
    "ProductsBrandId": 4,
    "ProductsCategoryId": 3,
    "ProductsSupplierId": 1,
    "ProductStatusId": 1
}, {
    "$id": "8",
    "ProductCategory": {
        "$ref": "2"
    },
    "ProductId": 12,
    "Reference": "HTHTOZ                          ",
    "BarCode": "2123192059538                   ",
    "Name": "Thin Hard Trivex OZ",
    "Description": null,
    "ProductsBrandId": 1,
    "ProductsCategoryId": 1,
    "ProductsSupplierId": 1,
    "ProductStatusId": 1
}]

如您所见,ProductsCategory数据出现一次,然后由同一类别中的下一个产品引用。

有关如何解决这个问题的建议,以显示网格上所有元素的类别名称?

2 个答案:

答案 0 :(得分:0)

你的json采用的是淘汰赛无法理解的格式。产品类别仅传输一次,第二次传输产品类别时,它包含第一个“参考”。

请参阅ID为3的对象,如下所示(错误示例)。

"$id":"3",
"ProductCategory":{"$ref":"2"}

以下是正确的。

"$id":"1",
"ProductCategory":{"$id":"2","ProductsCategoryId":1,"Reference":"OSOL ","Name":"Óculos de Sol","ProductsCategoryStatusId":1}

更新:如何处理上面的非标准json。

我看了一下示例项目。它在\ ProductStore \ App_Start \ WebApiConfig.cs

中有以下内容
var json = config.Formatters.JsonFormatter;
            json.SerializerSettings.PreserveReferencesHandling =
                Newtonsoft.Json.PreserveReferencesHandling.Objects;

根据这个http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization,保留对象引用会产生非标准的json,大多数客户端都不会使用它。

获得标准的json,这将允许敲除工作。

var json = config.Formatters.JsonFormatter;
            json.SerializerSettings.PreserveReferencesHandling =
                Newtonsoft.Json.PreserveReferencesHandling.None;  //this needs to be None

答案 1 :(得分:0)

您需要从其ID中创建ProductCategory个对象的映射。这样,当您渲染类别时,您可以从地图中获取正确的类别。

您可以将产品映射到解析引用的位置,也可以创建一个根据需要解析这些引用的函数。我为这个例子选择了后一种方法。

function ViewModel(data) {
    var self = this,
        productCategories = function (products) {
            var map = {};
            // throw all categories (with ids) into the map
            ko.utils.arrayForEach(products, function (item) {
                var category = item.ProductCategory;
                if (category.$id) map[category.$id] = category;
            });
            return map;
        } (data.products);

    self.products = ko.observableArray(data.products);

    self.getProductCategory = function (product) {
        var productCategory = product.ProductCategory,
            ref = productCategory.$ref;
        // get the referenced category
        if (ref) productCategory = productCategories[ref];
        return productCategory;
    }
}

然后像这样绑定它:

<tbody data-bind="foreach: products">
    <tr>            
        <td class="left" data-bind="text: Name"></td>
        <td class="left" data-bind="text: $root.getProductCategory($data).Name"></td>
    </tr>
</tbody>

Demo