Компонент Angular 1.5, обновляющий родительский контроллер через ngRoute
Я использую ngRoute для создания одностраничного приложения Angular. Хотите перейти на компонентную версию.
Проблема в отдельных областях. Мне нужен доступ к реквизитам и методам основного контроллера. Попытка использовать привязки, но не работает. Я не могу найти проблему с этим. Это приложение отлично работает без использования компонентов. Когда я пытаюсь изменить вид домашней страницы на компонент, он падает. Это основные части кода:
фреймворк
<html ng-app="angularModule" >
<body ng-controller="angularController as angCtrl" >
<div ng-show="angCtrl.user.isLoggedIn" >Sign Out</div>
<div ng-hide="angCtrl.user.isLoggedIn" cd-visible="angCtrl.showSignIn">Sign In</div>
<div id="contentLayer" class="contentLayer" ng-view ></div>
шаблон домашней страницы
<h1 class="pageLabel" >HomePage</h1>
<blockquote>This can be anything. No bindings.</blockquote>
angularController
var app = angular.module ('angularModule', ['ngRoute'] );
app.directive ('cdVisible',
function () {
return function (scope, element, attr) {
scope.$watch (attr.cdVisible,
function (visible) {
element.css ('visibility', visible ? 'visible' : 'hidden');
}
);
};
}
);
app.config ( [ '$locationProvider', '$routeProvider',
function config ($locationProvider, $routeProvider) {
$locationProvider.hashPrefix ('!');
$routeProvider
.when ('/sign-in', {
templateUrl: '/ng-sign-in',
controller: signInController
})
... more routes
.when ('/home', {
template: '<home-page showSignIn="angCtrl.showSignIn" menuSelect="angCtrl.menuSelect" ></home-page>'
})
.otherwise ('/home');
}
]);
function homePageController () {
this.menuSelect ('Devices'); // this statement has no effect on angularController.menuSelection chrome shows it as an anonymous function
this.showSignIn = false; // this bombs: Expression 'undefined' in attribute 'showSignIn' used with directive 'homepage' is non-assignable!
}
app.component ('homePage', {
templateUrl: '/ng-homepage',
controller: homePageController,
bindings: {
menuSelect: '&',
showSignIn: '='
}
});
app.controller ('angularController', [ '$http', '$window', '$location',
function ($http, $window, $location) {
var self = this;
this.user = {
"isLoggedIn": false
};
this.showSignIn = true;
this.menuSelection = "";
this.errorMessage = "";
this.menuSelect =
function (selection) {
self.menuSelection = selection;
};
this.setUserData =
function (userData) {
self.user = userData;
};
this.setShowSignIn =
function (show) {
self.showSignIn = show;
};
this.menuSelect ('');
this.getUserData(); // I removed this for this post
}
]);
Я добавил комментарий к тому месту, где он выдает исключение. Контроллер домашней страницы пытается обновить модель angularController. Первый ничего не делает, второй бросает исключение. Что я делаю неправильно?
2 ответа
Прежде всего showSignIn
является примитивным, поэтому angular будет обращаться с ним точно так же, как showSignIn="7+2"
, Если вам нужно изменить это значение внутри компонента, вам следует использовать объект с showSignIn
имущество.
Сейчас menuSelect
немного жестче, вероятно, консоль Chrome показывает что-то вроде
function (locals) {
return parentGet(scope, locals);
}
Это потому, что вы просто передаете ссылку на angCtrl.menuSelect
к компоненту.
Для того, чтобы выполнить menuSelect
функция изнутри homePageController
вам нужно сделать (в HTML):
<home-page menu-select="angCtrl.menuSelect(myMsg)"></home-page>
И затем назовите это так в контроллере компонента:
this.menuSelect({ myMsg:"Devices" })
(myMsg)
в HTML есть вызов angular для возврата этой ссылки, тогда при выполнении мы передаем параметр { myMsg:"Devices" }
чтобы соответствовать параметру в ссылке, которую мы только что сделали. Вы можете проверить этот ответ, который объясняет его более подробно.
В процессе прочтения вашего ответа на меня обрушилась одна ошибка: компонент домашней страницы маршрута /home должен использовать команду kebab case show-sign-in-select для атрибутов, а не lower-camelCase, как было изначально закодировано.
Ваши предложения оба сработали. Благодарю. Без компонентов я использовал прототипное наследование для доступа к свойствам и методам в родительской области. Из-за природы наследования прототипов javascript единственный способ изменить скаляры в родительской области - это вызвать методы установки в родительской области. Видимо, что-то подобное здесь применимо. Подробнее о наследовании прототипа в javascript.
Это было упражнение для проверки концепции. Я хотел проверить свою способность обновлять свойства и объекты в родительской области из компонента, а также выполнять метод в родительской области. Этот пример обновляет скаляр в родительской области 2 различными способами:
- вставить его в объект, привязать к объекту и ссылаться на него, используя этот объект из компонента, как это делается с логическим значением loginData.showSignIn
- построить метод установки в родительской области видимости и привязать к нему и вызвать метод установки из компонента, как это делается с помощью menuSelect (который на самом деле является не более чем установщиком для menuSelection)
и демонстрирует вызов функции при этом.
Окончательный рабочий код: (шаблон домашней страницы не изменяется)
фреймворк
<html ng-app="angularModule" >
<body ng-controller="angularController as angCtrl" >
<div ng-show="angCtrl.user.isLoggedIn" >Sign Out</div>
<div ng-hide="angCtrl.user.isLoggedIn" cd-visible="angCtrl.loginData.showSignIn">Sign In</div>
<div id="contentLayer" class="contentLayer" ng-view ></div>
angularController
var app = angular.module ('angularModule', ['ngRoute'] );
app.directive ('cdVisible',
function () {
return function (scope, element, attr) {
scope.$watch (attr.cdVisible,
function (visible) {
element.css ('visibility', visible ? 'visible' : 'hidden');
}
);
};
}
);
app.config ( [ '$locationProvider', '$routeProvider',
function config ($locationProvider, $routeProvider) {
$locationProvider.hashPrefix ('!');
$routeProvider
.when ('/sign-in', {
templateUrl: '/ng-sign-in',
controller: signInController
})
... more routes
.when ('/home', {
template: '<home-page login-data="angCtrl.loginData" menu-select="angCtrl.menuSelect(mySelection)" ></home-page>'
})
.otherwise ('/home');
}
]);
function homePageController () {
this.menuSelect ( { mySelection: 'Overview' });
this.loginData.showSignIn = true;
}
app.component ('homePage', {
templateUrl: '/ng-homepage',
controller: homePageController,
restrict: 'E',
bindings: {
menuSelect: '&',
loginData: '='
}
});
app.controller ('angularController', [ '$http', '$window', '$location',
function ($http, $window, $location) {
var self = this;
this.user = {
"isLoggedIn": false
};
this.loginData = {
"showSignIn": false
};
this.menuSelection = "";
this.errorMessage = "";
this.menuSelect =
function (selection) {
self.menuSelection = selection;
};
this.setUserData =
function (userData) {
self.user = userData;
};
this.setShowSignIn =
function (show) {
self.showSignIn = show;
};
this.menuSelect ('');
this.getUserData(); // I removed this for this post
}
]);