我有一个控制器,它获取名为content.json的json数据。当我渲染UI时,我无法知道json是否可用。控制器加载时,控制器会尽快获取json数据,它是整个应用程序中用于各种目的的对象数组:
vg.ctrls.controller('vg.ctrls.getContentJson', ['$scope', '$http',
function($scope, $http) {
$http.get('models/content.json').success(function(data) {
if(data instanceof Array){
vg.content = data; // store in app global variable
} else {
vg.log('vg.ctrls.getContentJson: data not array.');
}
$scope.vg = vg;
// vg.Content.createMenu(); // Document may not be ready yet.
});
}]
);
在我的UI中,我有一个基于content.json的导航菜单。显然是在<ul>
中使用ng-repeat的好地方:
<li ng-repeat="entry in content">
<a ng-click="vg.Content.setById(entry.id)">{{entry.title}}</a>
</li>
不幸的是,在AngularJS呈现指令时,content.json并不总是被加载。所以,我在我的应用程序中创建了一个函数vg.Content.createMenu(),该函数生成菜单并将其放在$ http.get()的回调中 - 但是,此时文档并不总是准备就绪。
换句话说,我有两个异步进程和一个依赖于它们的函数,但是我不知道哪个将首先完成。我之前没有使用我自己的自定义事件的框架解决了类似的问题。但是,我想相信在AngularJS中有一种处理方法吗?
创建一个在content.json加载之前不会执行的自定义指令怎么样?
---------------------编辑-----------------------
这是一个中间解决方案:
vg.directives.directive('vgContentMenuByCategory', function(){
return {
scope: {
categoryId: '='
,title: '='
,content: '='
}
,replace: true
,link: function(scope, element, attrs){
scope.$watch('content', function(content){
var $ul = element.find('ul.dropdown-menu');
for (var i = 0; i < content.length; i++) {
var entry = content[i];
if(entry.category===scope.categoryId){
var $li = $('<li><a>'+entry.title+'</a></li>');
_goToContentClickHandler({$element:$li, id:entry.id});
$ul.append($li);
}
};
});
}
, templateUrl: 'templates/vgContentMenuByCategory.html'
}
});
这不是真正的&#34;正确的&#34;解决方案,因为我没有使用&#34; ng-repeat&#34;在我的模板中但是在范围内的循环中这样做。$ watch()。如果我在模板中使用ng-repeat,那么&#39;内容&#39;还没有加载。问题进一步复杂,因为我实际上想要在另一个运行类别的指令中使用上面的指令 - 而且还必须等待content.json加载。
那么,在加载值之前,如何使指令等待渲染模板或在其中执行任何指令?
答案 0 :(得分:0)
创建内容工厂:
app.factory('Content',function(){
var category;
var title;
var id;
return {
category:function(){return category;},
title:function(){return title;},
id:function(){return id;},
};
然后在你的app.js中定义一个带有get请求的函数来检索内容并填充app.js范围内的Content对象。最后,当路由到您的控制器时,将此功能添加到解析列表中。 定义控制器时,将参数扩展为
vg.ctrls.controller('vg.ctrls.getContentJson', ['$scope', '$http',
function($scope, $http,Content) {
访问Content
对象。
答案 1 :(得分:0)
好的,我明白了 - 感谢您的意见和答案以及本教程:https://youtu.be/rHmk0UhJSb4。
首先,我创建一个获取数据并通过方法填充数据的服务:
vg.ctrls.service('vg.ctrls.contentService', ['$http', '$q',
function($http, $q) {
var deferred = $q.defer();
$http.get('models/content.json').then(function(data) {
deferred.resolve(data);
});
this.getContent = function(){
return deferred.promise;
};
}]
);
然后,我创建一个注入服务并将数据放入范围的控制器:
vg.ctrls.controller('vg.ctrls.content', ["$scope", "vg.ctrls.contentService",
function($scope, service){
var promise = service.getContent();
promise.then(function(o){
$scope.content = o.data;
});
}]);
随后,当数据加载时,将更新该控制器范围内的指令,如:
<div class="well" id="test" ng-controller="vg.ctrls.testService">
<span ng-repeat="entry in content">
<p>{{entry.id}}: {{entry.title}}</p>
</span>
</div>
或者在这样的指令中:
vg.directives.directive('vgContentMenuAllCategories', function(){
return {
scope: {
content: '='
}
, controller: 'vg.ctrls.content'
, link: function(scope, element, attrs){
//vg.log('vgContentMenuAllCategories');
}
, template:
'<span ng-repeat="entry in content"><a ng-click="vg.Content.setById(entry.id)">{{entry.title}}</a><br/></span>'
}
});
为了确保数据在以后到达时有效,我修改了服务以便在5秒后获取数据 - 当数据到达时指令确实会更新:
var foo = function(){
$http.get('models/content.json').then(function(data) {
deferred.resolve(data);
});
};
setTimeout(foo, 5000);