1

My API populates some nested models. Using a shopping example, when you query orders, the items property is populated with the description and quantity instead of returning just the item IDs.

orders: [
    {_id: 1,
     items: [
         {_id: 100,
          description: "apple", // from lookup in the Items table
          quantity: 4 // from lookup in the Items table
         }, ...
     ],
     ...
    }, ...
]

My view looks like:

<div ng-repeat="order in vm.orders">
    <ul ng-repeat="item in order.items">
        <li ng-model="vm.orders[$parent.$index].items[$index].description" ng-blur="item.$update()"></li>
        <li ng-model="vm.orders[$parent.$index].items[$index].quantity" ng-blur="item.$update()"></li>
    </ul>
</div>

The goal is to let the user update the item description and quantity from this view. (The lis are contenteditable directives.) The update call should be made on the Item $resource, not the Order $resource.

Is there a way to get Angular to recognize that the embedded documents are Items, upon which I can call methods like $update?

The workaround that I have is to change the ng-blur to call a controller method equivalent to this:

ng-blur="Item.update({_id: item._id})"

(If I do that, there's also no point in using the $parent.$index and $index syntax -- just order.item and item.description.)

ZachB
  • 13,051
  • 4
  • 61
  • 89
  • What's with all the `$parent.$index` stuff? Just use `ng-model="item.description"` and `ng-model="item.quantity"` – Phil May 06 '15 at 00:41
  • need more clarity on what a `bona fide item` is. Not sure what you are even asking in that regard – charlietfl May 06 '15 at 00:42
  • @charlietfl updated. Meant that they're `Item` models that have methods available on them. – ZachB May 06 '15 at 00:44
  • what does `methods available` mean? – charlietfl May 06 '15 at 00:45
  • 1
    @charlietfl as in, I can call `item.$update`. There is an `Item` `$resource` in my app. – ZachB May 06 '15 at 00:45
  • Can't determine that in the html...you need a controller method to validate items before trying to update – charlietfl May 06 '15 at 00:46
  • @Phil that's from http://stackoverflow.com/questions/15256600/passing-2-index-values-within-nested-ng-repeat -- attempt to template by reference instead of by value, but it doesn't help if the references are not to `Item` models. – ZachB May 06 '15 at 00:47

1 Answers1

1

What you want to do is transform the nested resources into actual resources. To do so, add a response transformer to your Order resource. For example

.factory('Order', function($resource, $http, Item) {
    var responseTransformer = function(order) {
        order.items = order.items.map(function(item) {
            return new Item(item);
        });
        return order;
    };

    // somewhat lifted from https://docs.angularjs.org/api/ng/service/$http#overriding-the-default-transformations-per-request
    var appendResponseTransformer = function(transformer) {
        var defaults = $http.defaults.transformResponse;
        defaults = angular.isArray(defaults) ? defaults : [defaults];
        return defaults.concat(transform);
    };

    return $resource('/orders', whatever, {
        get: {
            method: 'GET',
            url: '/orders/:id',
            params: { id: '@id' },
            transformResponse: appendResponseTransform(responseTransformer)
        },
        query: {
            method: 'GET',
            isArray: true,
            transformResponse: appendResponseTransform(function(orders) {
                return orders.map(responseTransformer);
            })
        }
    });
});

An alternative to this would have been to just handle the item update in your controller. For example

ng-blur="updateItem(item)"

with

$scope.updateItem = function(item) {
    Item.update(item);
};
Phil
  • 157,677
  • 23
  • 242
  • 245
  • Thanks for pointing out the "proper" solution and the alternative. The controller method is less code to maintain for sure. – ZachB May 06 '15 at 00:59
  • @ZachB I'm not sure which one I'd call the *proper* solution. Response transformers are handy for some things but imagine if the nesting went deeper. Also having to add the slightly different transformer for the `query` action is easy to forget to do. Another problem with response transformers is that they'll try and transform error responses as well which means you need to add additional logic – Phil May 06 '15 at 01:05