Обновление директивы JS Angular при изменении Сервиса
Я пытаюсь выполнить этот ответ SO, объясняя, как рендерировать рекурсивную структуру JSON с помощью директивы. Однако, в отличие от предоставленного ответа, мои данные не известны при загрузке DOM и Angular выполняется в первый раз.
Вместо этого мои данные извлекаются из поля ввода HTML и сохраняются в службе Angular (когда пользователь отправляет форму).
Как сохранить актуальную директиву Angular при изменении данных службы?
Обновление в ответ на ответ
@musically_ut предоставил отличный ответ, который помог, но выявил связанную с этим проблему, предотвратив реализацию (обновленный здесь).
Директива отображает HTML, содержащий Angular {{expressions}}
, которые обращаются к данным, хранящимся в $scope
. Поскольку исходное решение было $watch
, когда служба предоставила данные. Как я могу обеспечить добавление "новых" данных в $scope
до отображения директивы?
Обзор архитектуры и потока:
-
ControllerA
→ Получить вход от пользователя
-
ControllerA
→ Использовать службу для преобразования данных
-
ControllerB
→ $watch
для изменений службы
-
Directive
→ $watch
для изменений службы
-
ControllerB
→ Добавить данные в $scope
-
Directive
→ Отобразить преобразованные данные (из службы), используя
директивы
Проблема заключается в шагах 5 и 6. Директива отображает {{expressions}}
, прежде чем ControllerB добавит данные в $scope
. Даже если это сработало, оно кажется слишком сложным и "взломанным".
На самом деле, чтобы регрессировать, я использую $watch
в ControllerB для прослушивания, когда преобразованные данные готовы в службе. Даже это кажется немного переполненным ( сервис не выполняет асинхронные вызовы).
Ответы
Ответ 1
Вы можете ввести службу при определении директивы, а затем настроить $watch
на данные. Итак, в вашем случае:
.directive('tree', function ($compile, myService) {
return {
// ...
link: function (scope, element, attrs) {
scope.$watch(function () {
return myService.getData();
},
function (newVal) {
if (typeof newVal !== 'undefined') {
// ...
}
}
});
}
});
Это будет следить за данными для изменения и запускать код при каждом изменении данных.
Однако , если данные не изменяются после установки один раз, лучший способ (более эффективный) - вернуть обещание от службы (методы $http
возвращают обещание напрямую или вы может создать его с помощью службы $q
), а затем добавить ваши вычисления в качестве продолжения данных.
.directive('tree', function ($compile, myService) {
return {
// ...
link: function (scope, element, attrs) {
myService.getData().then(function (data) {
// ...
}, function (err) {
// Handle error
});
}
}
});
Ответ 2
Я написал короткую функцию, которая позволяет помещать данные в Object без замены.
Вы можете использовать его в своем сервисе. Таким образом, вам не нужно использовать часы. Вы можете использовать обычный цикл дайджеста Angular.
Например, посмотрите этот простой контроллер и службу:
Демо: JSFidde - http://jsfiddle.net/y09kx7f7/1/ с утверждать тесты
Контроллер:
app.controller('dem',function($scope,me){
$scope.user=me.user; // {name:'user name'}
})
Контроллер будет автоматически переключаться без просмотра при каждом изменении имени пользователя!
Сервис
.factory('me',function($timeout){
var obj={}
obj.user={name:'hello'}
$timeout(function(){ //Example of change the data
newUser={name:'israel'}
cloneInto(obj.user,newUser)
},1000)
return obj
})
Функция cloneInto, которую я написал:
// The function it is like a=b,
// but keeping the object in his original memory position.
function cloneInto(a,b){
var i
for (i in a){
if(typeof a[i]!='object') //For supporting deep-copy
delete a[i]
}
for (i in b){
if (typeof b[i]=='object'){
if(!a[i]) a[i]={}
cloneInto(a[i],b[i])
}
else{
a[i]=b[i]
}
}
}