У меня есть приложение Rails и доступ к двум моделям через JSON API с использованием ng-ресурса.
В моем шаблоне я показываю список первых "заказов" модели:
<li ng-repeat="order in orders">
Order {{order.id}}:
Product: {{showProduct(order.product_id)}}
</li>
Каждый "заказ" содержит product_id
. Теперь я хотел бы получить доступ ко второй модели ("продукты") и отобразить внутри ng-repeat
правильный "продукт" с идентификатором product_id
соответствующего "заказа".
Для этого я подумал об использовании функции showProduct()
и использовал order.product_id
в качестве аргумента. Однако, когда я делаю это, он вызывает бесконечный цикл, который продолжает делать запросы GET в мою базу данных.
Здесь важная часть моего приложения.
var app = angular.module('shop', ['ngResource']);
app.factory('models', ['$resource', function($resource){
var orders_model = $resource("/orders/:id.json", {id: "@id"}, {update: {method: "PUT"}});
var products_model = $resource("/products/:id.json", {id: "@id"}, {update: {method: "PUT"}});
var o = {
orders: orders_model,
products: products_model
};
return o;
}]);
app.controller('OrdersCtrl', ['$scope', 'models', function($scope, models){
$scope.orders = models.orders.query();
$scope.showProduct = function(product_id){
return models.products.get({id: product_id});
};
}])
Это ошибки в моей консоли (что имеет смысл, так как это бесконечный цикл):
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations: []
Запрос GET в консоли Rails кажется прекрасным. Возможно, я пытаюсь думать гораздо сложнее, чем мне нужно.
Да, потому что у вас есть showProduct
в представлении, функция вызывается в каждом дайджесте, каждый раз возвращаясь к другому обещанию, чтобы он ломался:
Я предлагаю вам сделать:
models.orders.query().$promise
.then(function(orders){
$scope.orders = orders;
//using lodash here, I recommend you use it too
_.each(orders, function(order){
models.products.get({id: order.product_id }).$promise
.then(function(product){
order.product = product;
})
});
});
И в перспективе:
<li ng-repeat="order in orders">
Order {{order.id}}:
Product: {{order.product}}
</li>
Но использование этого кода вызовет один запрос для каждого порядка, который является довольно плохим: его анти-шаблон N + 1.
2 решения:
Глядя на ваш код, я сначала почувствовал, что он должен работать. Во всяком случае, если это не так, я бы попробовал это так:
В вашем контроллере:
$scope.showProduct = function(product_id){
var product = models.products.get({id: product_id}, function(){
return product;
});
};
Это вернет значение после поступления данных с сервера.
includes
в вашем ActiveRecord запроса , чтобы избежать на стороне сервера N + 1