AngularJS 在指令运行之前通过 AJAX 检索数据 [英] AngularJS retrieve data via AJAX before Directive runs
问题描述
我正在使用 AngularUI 的 uiMap 指令实例化一个谷歌地图.uiMap 指令适用于硬编码数据({mapOptions}
和 [myMarkers]
);但是,当我通过 $http.get()
检索此数据时遇到了麻烦(该指令在 AJAX 调用完成之前触发).
最初我在我的 GoogleMaps
控制器中执行 GET,但是当我意识到事情发生的顺序不正确时,我将 GET 移到了 uiMap
指令中.我有两个问题:
- 我认为这不是正确的做法.
- GET 还检索
[myMarkers]
的数据- 创建标记的函数/指令无处不在,因为它负责创建所有覆盖
所以我的问题是,在指令运行之前,应用程序中是否还有其他地方可以检索数据(并将其应用于范围)?
我阅读了 $q,这听起来像什么我想要,但我不确定我是否可以在我的控制器中而不是在指令中完成它(也不确定 $q.defer.resolve()
与 $ 有何不同http.success()
).
编辑我使用的大部分代码是从 AngularUI 的文档中复制/粘贴的,但这里有一个 plunk:http://plnkr.co/edit/t2Nq57
解决方案
基于 Andy 的回答,我使用了 uiMap 和 uiIf:
<div ui-if="mapReady">
注意事项 1 uiIf 不能位于指定控制器提供其条件的同一元素中(uiIf 的优先级高于 ngController,因此在 uiIf 执行之前不会设置其控制器).
注意事项 2 务必使用最uiIf 的最新版本(最新标签中提供的版本 v0.3.2 已过时).旧版本在某些情况下存在导致 TypeError 的错误.
Caveat 3 jQuery 必须包含在 AngularJS 之前(在 index.html 中);否则,您将收到一个 TypeError,指出 Object [object Object] 没有方法 'trigger'
(或 Object [object HTMLDivElement] 在 Windows 上没有方法 'trigger'
).Chrome 将允许您进入触发器函数,因为 Chrome 知道它,但 Angular 不知道(并且 Angular 正在抛出错误).
function GoogleMaps( $scope , $http ){var mapDefaults = {center: new google.maps.LatLng(25,-90),//以墨西哥湾为中心缩放:4,mapTypeId: google.maps.MapTypeId.ROADMAP};$scope.mapOptions = {};$scope.mapReady = false;$scope.markers = [];$http.get('map.json').then(function mapData(response) {var map_data = response.data,user_defaults = map_data.user.defaults;//{center: [lat,lng], 缩放: 15}$scope.mapOptions = {"center": (typeof user_defaults.center !== 'undefined') ?新 google.maps.LatLng(user_defaults.center[0],user_defaults.center[1]): mapDefaults.center,"zoom": (typeof user_defaults.zoom !== 'undefined') ?parseInt(user_defaults.zoom,10): mapDefaults.zoom,mapTypeId":mapDefaults.mapTypeId};//处理代码以填充标记对象$scope.mapReady = true;});//直接来自 http://angular-ui.github.com/#directives-map 上的示例$scope.addMarker = function($event) { ... };$scope.openMarkerInfo = function(marker) { ... };$scope.setMarkerPosition = function(marker, lat, lng) { ... };}//谷歌地图{}
缺点 uiMap 目前不支持 domready 上的渲染器.我正在研究此 GitHub 中建议的 uiMapMarker 替代版本问题/评论.
此问题的解决方案:https://stackoverflow.com/a/14617167/758177
工作示例:http://plnkr.co/edit/0CMdW3?p=preview
你可以延迟 ui-map 的执行,直到你的数据加载完毕.
HTML:
<div ui-map="myMap" ui-options="myOpts"></div>
JS:
$http.get('/mapdata').then(function(response) {$scope.myOpts = response.data;$scope.loadingIsDone = true;});
I'm using AngularUI's uiMap directives to instantiate a google map. The uiMap directive works great with hard-coded data ({mapOptions}
and [myMarkers]
); however I run into trouble when I retrieve this data via $http.get()
(the directive fires before the AJAX call has finished).
Initially I was executing the GET in my GoogleMaps
controller, but when I realised things were happening out of sequence, I moved the GET into the uiMap
directive. I've got 2 problems with this:
- I think this is not the correct way to do this.
- The GET also retrieves the data for
[myMarkers]
- The function/directive that creates the markers is ubiquitous in that it is responsible for creating all overlays
So my question is, is there somewhere else in the application where I can retrieve the data (and apply it to scope) before the directive runs?
I read up on $q, and that kind of sounds like what I want, but I'm not sure if I can do it within my controller rather than in the directive (also not sure how $q.defer.resolve()
is any different than $http.success()
).
EDIT Most of the code I'm using is copy/paste from AngularUI's doc, but here's a plunk: http://plnkr.co/edit/t2Nq57
Solution
Based on Andy's answer, I used a combination of uiMap and uiIf:
<!-- index.html -->
<div
id="map_container"
ng-controller="GoogleMaps">
<div ui-if="mapReady">
<div
ng-repeat="marker in markers"
ui-map-marker="markers[$index]"
ui-event="{'map-click':'openMarkerInfo(marker)'}"
></div>
<div
ui-map-info-window="myInfoWindow"
ng-include="'infobox.html'"
></div>
<div
id="map_canvas"
ui-map="myMap"
ui-options="mapOptions"
></div>
</div>
</div>
Caveat 1 uiIf cannot be in the same element that specifies the controller furnishing its condition (uiIf has higher priority than ngController, so its controller won't get set before uiIf executes).
Caveat 2 Be sure to use the most recent version of uiIf (the version supplied in the most recent tag, v0.3.2, is out of date). The old one has bug causing a TypeError under certain circumstances.
Caveat 3 jQuery MUST be included before AngularJS (in index.html); else you will receive a TypeError stating that Object [object Object] has no method 'trigger'
(or Object [object HTMLDivElement] has no method 'trigger'
on Windows). Chrome will allow you to step into the trigger function because Chrome knows about it, but Angular does not (and Angular is throwing the error).
function GoogleMaps( $scope , $http )
{
var mapDefaults = {
center: new google.maps.LatLng(25,-90),//centres on Gulf of Mexico
zoom: 4,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
$scope.mapOptions = {};
$scope.mapReady = false;
$scope.markers = [];
$http.get('map.json').then(function mapData(response) {
var map_data = response.data,
user_defaults = map_data.user.defaults; //{center: [lat,lng], zoom: 15}
$scope.mapOptions = {
"center": (typeof user_defaults.center !== 'undefined') ?
new google.maps.LatLng(user_defaults.center[0],user_defaults.center[1])
: mapDefaults.center,
"zoom": (typeof user_defaults.zoom !== 'undefined') ?
parseInt(user_defaults.zoom,10)
: mapDefaults.zoom,
"mapTypeId": mapDefaults.mapTypeId
};
//working on code to populate markers object
$scope.mapReady = true;
});
// straight from sample on http://angular-ui.github.com/#directives-map
$scope.addMarker = function($event) { … };
$scope.openMarkerInfo = function(marker) { … };
$scope.setMarkerPosition = function(marker, lat, lng) { … };
}//GoogleMaps{}
Drawback uiMap does not currently support rendering makers on domready. I'm looking into an alternative version of uiMapMarker suggested in this GitHub issue / comment.
Solution to this issue: https://stackoverflow.com/a/14617167/758177
Working example: http://plnkr.co/edit/0CMdW3?p=preview
You could just delay execution of ui-map until your data is loaded.
HTML:
<div ui-if="loadingIsDone">
<div ui-map="myMap" ui-options="myOpts"></div>
</div>
JS:
$http.get('/mapdata').then(function(response) {
$scope.myOpts = response.data;
$scope.loadingIsDone = true;
});
这篇关于AngularJS 在指令运行之前通过 AJAX 检索数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!