Обновление HTML-элемента вне ng-view
У меня есть следующий HTML на странице:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="myCart">
<head>
<title>AngularJS Shopping Cart</title>
<link href="css/jsonstore.css" rel="stylesheet" />
</head>
<body>
<div id="container">
<div id="header">
<h1>The JSON Store</h1>
<div class="cart-info">
My Cart (<span class="cart-items">{{item.basketCount}}</span> items)
</div>
</div>
<div id="main" ng-view>
</div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular-resource.js"></script>
<script src="js/routing.js"></script>
<script src="js/dataresource.js"></script>
<script src="js/basketinfo.js"></script>
<script src="js/index.js"></script>
<script src="js/detail.js"></script>
</body>
</html>
div "main" заменяется шаблонами HTML моими маршрутами, однако я хотел бы обновить заголовок с помощью подсчета корзины покупок.
Я попробовал модель привязки, как показано в HTML и ниже:
function DetailController($scope, item, basketDetail) {
$scope.item = item;
$scope.item.basketCount = basketDetail.getCount();
//more code
}
Я также попробовал просто ввести службу и вызвать ее из HTML. Оба способа ничего не делают.
Может кто-нибудь помочь?
Спасибо
Ответы
Ответ 1
Ваш header
div - это действительно представление, как и другие виды, которые вы определили для использования с ng-view. Когда-нибудь вы можете показать больше, чем просто модель basketCount в этом заголовке. Но тот факт, что вы проецируете даже одну часть данных модели в этот заголовок, делает этот раздел видом. Поэтому я бы рекомендовал, чтобы у него была собственная $scope, чтобы спроектировать эту модель, следовательно, ее собственный контроллер.
Что остается тогда, где поставить модель basketCount? И мы должны учитывать, что несколько представлений могут позволить пользователю делать что-то, что должно повлиять на эту модель. Angular нормальный ответ для "большого доступа" - это инъекция зависимостей. Итак, я бы включил модель basketCount в сервис. Представления/контроллеры, которые нуждаются в доступе к нему, могут его внедрить. Когда-нибудь ваше приложение может иметь дополнительные представления, которые не нуждаются в доступе к этим моделям, поэтому эти представления не будут вводить службу.
Потенциально, вся корзина может быть смоделирована в этой службе:
app.factory('basketService', function() {
return {
items: [],
itemCount: 0,
...
}
});
function HeaderCtrl($scope, basketService) {
$scope.basket = basketService;
...
}
function DetailCtrl($scope, basketService) {
$scope.basket = basketService;
...
}
<div id="header" ng-controller="HeaderCtrl">
<h1>The JSON Store</h1>
<div class="cart-info">
My Cart (<span class="cart-items">{{basket.itemCount}}</span> items)
</div>
Ответ 2
Вам нужно будет ввести $rootScope, а затем обновить его:
function DetailController($scope, $rootScope, basketDetail) {
$rootScope.item = $rootScope.item || {};
$rootScope.item.basketCount = basketDetail.getCount();
//more code
}
Есть много способов сделать это, но это мое первое предложение, потому что оно, вероятно, самое легкое.
EDIT: по вашему запросу, другие способы сделать это...
Вы можете использовать $parent, чтобы нажать на родительскую область. Поверхность - это довольно быстро и чисто... Недостатком является то, что один из ваших контроллеров делает предположения о том, что он является родителем в некоторой степени (но это все еще не ужасно, действительно):
{{item.basketCount}}
<div ng-controller="InnerCtrl">
</div>
function InnerCtrl($scope, basketDetail) {
$scope.$parent.item = $scope.$parent.item || {};
$scope.$parent.item.basketCount = basketDetail.getCount();
}
Тогда существует упомянутый выше метод @asgoth, в котором вы используете вложенный контроллер и метод в родительской области для обновления родительской области. Действительно, но, как и мое другое решение в этом разделе "другие способы сделать это", оно основано на предположениях, сделанных о контейнере контроллера, а также опирается на то, что вы создаете дополнительный контроллер.
Наконец, вы можете создать службу. В настоящее время службы обычно не используются таким образом, но вы можете использовать их таким образом. Где вы можете воспользоваться службой basketDetail и использовать его для передачи значения взад и вперед. Например:
app.factory('basketDetail', function() {
return {
items: { basketCount: 0 },
getCount: function() {
//return something here
return 123;
}
}
});
function FooCtrl($scope, basketDetail) {
$scope.items = basketDetail.items;
$scope.items.basketCount = basketDetail.getCount();
}
function BarCtrl($scope, basketDetail) {
$scope.items = basketDetail.items;
}
<div ng-controller="FooCtrl">
{{items.basketCount}}
</div>
<div ng-controller="BarCtrl">
{{items.basketCount}}
</div>
Это работает, потому что $scope в обоих контроллерах поддерживает ссылку на тот же объект, который поддерживается службой basketDetail. Но опять же, это не очень рекомендуемый способ.
Все сказанное: $rootScope, ИМО, скорее всего, то, что вы ищете.
- Это не требует создания дополнительного контроллера.
- Это не требует создания каких-либо дополнительных ссылок на функции.
- Не приведет к созданию каких-либо дополнительных родительских/дочерних объектов. Вложенность и последующие часы.
Ответ 3
Нет необходимости в $rootScope
. Создайте родительский контроллер (например, RootController
) с помощью функции в своей области. Режимы дочернего объекта автоматически наследуют его:
<div id="container" ng-controller="RootController">
...
function RootController($scope) {
$scope.item = {};
$scope.setBasketCount = function (detail) {
$scope.item.basketCount = detail.getCount();
}
}
В вашем контроллере подробно используется функция setBasketCount()
:
function DetailController($scope, item, basketDetail) {
$scope.item = item;
$scope.setBasketCount(basketDetail);
//more code
}