O escopo isolado das diretivas não funciona corretamente em conjunto com visualizações aninhadas?(Roteador AngularJS/UI)
Pergunta
Estou usando o ui-router em um projeto AngularJS onde tenho uma visualização aninhada que contém uma diretiva personalizada.Esta diretiva renderiza um campo de entrada (digamos um campo de filtro) e seu valor deve estar sincronizado com o escopo do controlador.
Isso funciona bem para esta diretiva, quando a visualização/estado não está aninhada:
jsFiddle/não aninhado/funcionando conforme esperado
var myApp = angular.module('myApp', ['ui.router', 'myComponents'])
.config(['$stateProvider', function ($stateProvider) {
$stateProvider.
state('home', {
url: '',
template: '<my-filter text-filter="theFilter"></my-filter><button ng-click="inspect()">inspect</button>{{ theFilter |json}}',
controller: 'myController'
});
}]);
var components = angular.module('myComponents', []);
components.directive('myFilter', [function () {
return {
restrict: 'E',
template: '<input type="text" name="filter" ng-model="textFilter">',
scope: {
textFilter: '='
}
};
}]);
components.controller('myController', ['$scope', function ($scope) {
$scope.theFilter = 'initial filter';
$scope.inspect = function () {
alert($scope.theFilter);
}
}]);
Visualizar:
<div ng-app="myApp">
<div ui-View></div>
</div>
Quando altero o texto do campo de entrada, ele se reflete no escopo...
... mas quando aninho a visualização/estado, o valor no escopo mantém seu valor inicial, mas espero que seja alterado de acordo com o valor do campo de entrada ao substituir.
var myApp = angular.module('myApp', ['ui.router', 'myComponents'])
.config(['$stateProvider', function ($stateProvider) {
$stateProvider.
state('home', {
abstract: true,
url: '',
template: 'Nested View:<div ui-view></div>',
controller: 'myController'
}).
state('home.detail', {
url: '',
template: '<my-filter text-filter="theFilter"></my-filter><button ng-click="inspect()">inspect</button>{{ theFilter |json}}'
});;
}]);
var components = angular.module('myComponents', []);
components.directive('myFilter', [function () {
return {
restrict: 'E',
template: '<input type="text" name="filter" ng-model="textFilter">',
scope: {
textFilter: '='
}
};
}]);
components.controller('myController', ['$scope', function ($scope) {
$scope.theFilter = 'initial filter';
$scope.inspect = function () {
alert($scope.theFilter);
}
}]);
Visualizar:
<div ng-app="myApp" >
<div ui-View></div>
</div>
Aqui, o texto no escopo (ver controlador) permanece o mesmo.
Alguma ideia de como posso obter o mesmo resultado com visualizações aninhadas do primeiro exemplo?
PS:A diretiva precisa de permanecer reutilizável
Solução
Isso está relacionado a um problema comum.Como mencionado neste vídeo Angular JS - melhores práticas (29:19), e explicado aqui: Escopos aninhados em Angular JS
“Sempre que você tem um modelo ng, deve haver um ponto em algum lugar.Se você não tem um ponto, você está fazendo errado."
Portanto, o controlador deve criar um objeto:
components.controller('myController', ['$scope', function($scope) {
// here theFilter is an object
// with property value
$scope.theFilter = { value : 'initial filter'};
$scope.inspect = function() {
alert($scope.theFilter.value);
}
}]);
e o modelo deve funcionar com um objeto com propriedade value
:
components.directive('myFilter', [function() {
return {
restrict: 'E',
template: '<input type="text" name="filter" ng-model="textFilter.value">',
scope: {
textFilter: '='
}
};
}]);
O atualizado jsfiddle