$watch переменная службы Async не работает
Привет, я провел последние два дня, пытаясь сделать представление в зависимости от ответа асинхронной http-службы. Но это не работает для меня. Может кто-нибудь мне помочь?
Здесь есть код для основной идеи, но оригинальный немного отличается:
var myApp = angular.module('app', []);
myApp.directive('dashboard',['service1',function(service1){
return {
templateUrl: 'sometemplate.html',
controller: function ($scope) {
$scope.data = {};
service1.get('keyXXX');
$scope.$watch(service1.data['keyXXX'],function(n,o){
//how to make this work???
//I always get null or it would not get executed at all
});
}
}
}])
.service('service1',['someAsyncservice',function(someAsyncservice){
var _s={
data:{},
get:function(key){
if(this.data[key]==undefined)
{
this.data[key]={status:"loading",data:{}};
}
someAsyncservice().then(function(result){
_s[key].data=result;
_s[key].status="success";
});
}
}
return _s;
}])
2 ответа
Обновить:
Это расширенный пример, использующий в основном ваш оригинальный код, показывающий, как полностью обойтись без $apply
или же $watch
, Просто с помощью $q
Вы можете обойти большинство проблем, которые могут вызвать первые две функции:
(function (app, ng) {
'use strict';
app.controller('TestCtrl', ['$scope', 'RefreshViewService', function ($scope, RefreshViewService) {
$scope.key = 'key_A';
$scope.refresh = function refresh(key) {
$scope.busy = true;
RefreshViewService.refresh(key).then(function () {
$scope.busy = false;
});
};
}]);
app.directive('dashboard', ['service1', function(service1) {
return {
template: '<pre><strong>{{ key }}</strong>: {{ data|json }}</pre>',
scope: {
key: '@'
},
controller: function ($scope) {
// use currently provided data
$scope.data = service1.get($scope.key);
// load data
service1.load($scope.key).then(function (response) {
$scope.data = response;
});
}
};
}]);
app.service('service1', ['$q', 'someAsyncService', function($q, someAsyncService){
var data = {}, loading = {};
return {
/**
* returns the currently available data for `key`
*
* @param key
* @returns {*}
*/
get: function (key) {
if(data[key] === undefined) {
data[key] = {
status: 'loading',
data: {}
};
}
return data[key];
},
/**
* async load data for `key`
*
* @param key
* @returns {*}
*/
load: function(key){
// clear previous data
if (loading[key] === undefined) {
data[key].status = 'loading';
data[key].data = {};
}
return $q(function (resolve, reject) {
// only run if not already loading
if (loading[key] === undefined) {
loading[key] = someAsyncService(key).then(function(result) {
data[key].status = 'success';
data[key].data = result;
delete loading[key];
resolve(data[key]);
});
}
return loading;
});
}
};
}]);
/**
* mock refresh service
*/
app.service('RefreshViewService', ['service1', function(service1) {
return {
refresh: function (key) {
return service1.load(key);
}
};
}]);
/**
* mock async service
*/
app.service('someAsyncService', ['$q', '$timeout', function ($q, $timeout) {
return function(key) {
return $q(function (resolve, reject) {
$timeout(function () {
resolve({ 'requested key': key, 'foo': Math.floor(Math.random() * 100) });
}, 500 + Math.random() * 3000);
});
};
}]);
})(angular.module('app', []), angular);
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.min.js"></script>
<div data-ng-app="app" class="container">
<div data-ng-controller="TestCtrl">
<div class="radio">
<label>
<input type="radio" data-ng-model="key" data-ng-disabled="busy" value="key_A"> key A
</label>
<label>
<input type="radio" data-ng-model="key" data-ng-disabled="busy" value="key_B"> key B
</label>
</div>
<button class="btn btn-primary" data-ng-click="refresh(key)" data-ng-disabled="busy">Refresh</button>
<span data-ng-show="busy">loading...</span>
</div>
<hr>
<dashboard key="key_A"></dashboard>
<dashboard key="key_A"></dashboard>
<dashboard key="key_B"></dashboard>
предыдущий ответ:
Хотя, возможно, есть и другие (лучшие) способы, просто оберните наблюдаемое значение в функцию. Например:
$watch(function() { return service1.data['keyXXX']; }, ...
Но обратите внимание, что это будет работать только в том случае, если someAsyncservice
фактически запускает цикл дайджеста (например, используя $q
и тому подобное)!
Я на самом деле не проверял это, но попробовал:
$scope.$watch(function(){return service1.data['keyXXX']},function(n,o){
//how to make this work???
//I always get null or it would not get executed at all
});