Domanda

I have a collection of items. The items are broken down into "types" and then further divided within the type into "categories". I do not know the names of the "types" or the "categories" before hand.

I would like to do some nested foreach binding to represent the data hierarchically. Something like this:

<ul data-bind="foreach: OrderItems.Types">
<li>
    ItemType: <span data-bind='text: $data'></span>
    <ul data-bind="foreach: Categories">
      <li>
        Category: <span data-bind='text: $data'></span>
        <ul data-bind="foreach: OrderItems">
          <li>
            Item: <span data-bind="text: Name"> </span>
          </li>
        </ul>              
      </li>
    </ul>
</li>

var order = {
"OrderNumber": "394857",
"OrderItems": {
    "Types": {
        "Services": {
            "Categories": {
                "carpet cleaning": {
                    "OrderItems": [
                        {
                            "OrderItemID": "9d398f88-892c-11e3-8f31-18037335d26a",
                            "Name": "ARug-Oriental Rugs (estimate on site)"
                        },
                        {
                            "OrderItemID": "9d398f53-892c-11e3-8f31-18037335d26a",
                            "Name": "C1-Basic Cleaning  (per room)"
                        },
                        {
                            "OrderItemID": "9d398f54-892c-11e3-8f31-18037335d26a",
                            "Name": "C2-Clean & Protect  (per room)"
                        },
                        {
                            "OrderItemID": "9d398f55-892c-11e3-8f31-18037335d26a",
                            "Name": "C3-Healthy Home Package (per room)"
                        }
                    ]
                },
                "specialty": {
                    "OrderItems": [
                        {
                            "OrderItemID": "9d398f8f-892c-11e3-8f31-18037335d26a",
                            "Name": "SOTHR-Other"
                        }
                    ]
                },
                "tile & stone": {
                    "OrderItems": [
                        {
                            "OrderItemID": "9d398f8e-892c-11e3-8f31-18037335d26a",
                            "Name": "TILE-Tile & Stone Care"
                        }
                    ]
                },
                "upholstery": {
                    "OrderItems": [
                        {
                            "OrderItemID": "9d398f7b-892c-11e3-8f31-18037335d26a",
                            "Name": "U3S1-Upholstery - Sofa (Seats 3: 7 linear feet)"
                        },
                        {
                            "OrderItemID": "9d398f7c-892c-11e3-8f31-18037335d26a",
                            "Name": "U3S2-Upholstery - Sofa - Clean & Protect (Seats 3: 7 linear feet"
                        }
                    ]
                }
            }
        },
        "Products": {
            "Categories": {
                "carpet cleaning": {
                    "OrderItems": [
                        {
                            "OrderItemID": "9d398f84-892c-11e3-8f31-18037335d26a",
                            "Name": "PLB-Leave Behind Item"
                        }
                    ]
                }
            }
        }
    }
}
};

var viewModel = ko.mapping.fromJS(order);
ko.applyBindings(viewModel);

here's a fiddle with the above code: http://jsfiddle.net/mattlokk/6Q5f7/5/

È stato utile?

Soluzione

To bind against your structure, you would need to turn the objects into arrays. Given that you are using the mapping plugin, the easiest way would likely be to use a binding that translates an object with properties to an array of key/values.

Here is a sample binding:

ko.bindingHandlers.objectForEach = {
    init: function(element, valueAccessor, allBindings, data, context) {
        var mapped = ko.computed({
            read: function() {
                var object = ko.unwrap(valueAccessor()),
                    result = [];

                ko.utils.objectForEach(object, function(key, value) {
                    var item = {
                        key: key,
                        value: value
                    };

                    result.push(item);
                });


                return result;
            },
            disposeWhenNodeIsRemoved: element
        });

        //apply the foreach bindings with the mapped values
        ko.applyBindingsToNode(element, { foreach: mapped }, context);

        return { controlsDescendantBindings: true };   
    }
};

This will create a computed on-the-fly that maps the object to an array of key/values. Now you can use objectForEach instead of foreach against your objects.

Here is a basic sample: http://jsfiddle.net/rniemeyer/nn3jg/ and here is an example with your fiddle: http://jsfiddle.net/rniemeyer/47Wbe/

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top