AngularJS在指令

时间:2016-05-06 22:00:28

标签: javascript jquery angularjs google-maps dom

我是AngularJS的新手。我搜索了一些关于如何在指令中操作DOM的页面,但是大多数都在操纵指令本身的DOM。我的问题是在指令之外操纵DOM。

我的项目中有一个Google地图,地图上有一些标记可以显示事件。我想要做的是,当单击标记时,应用程序应在幻灯片栏中显示事件的详细信息。根据下面的代码,要求是当我单击触发updateMarkers()指令的标记时,它应该在HTML中更改{{detail}}的值。我现在正在做的是尝试使用" ="给指令访问其控制器范围中的值,但这种方式不起作用。如果您知道,请提供一些帮助,谢谢。

HTML:

<div id="wrapper" >
    <div class="container-fluid">
        <div class="row">
            <div class="col-lg-12">                  
                <app-map id="map" center="loc" markers="cities" details="details" show-detail="getDetails(directivedata)" on-init="gotoCurrentLocation(directiveData)"> </app-map>                  
            </div>
            <div>**********{{details}}</div>
        </div>
    </div>
</div>

控制器的一部分:

app.controller("appCtrl", function ($scope, $http) {
    $scope.nearbyEvent;
    $scope.details = "something";   //should be changed when click markers in map
    //code.....}

指令:

app.directive("appMap", ['$http', function ($http) {
    return {
        restrict: "E",
        replace: true,
        template: "<div></div>",
        scope: {
            center: "=",        // Center point on the map (e.g. <code>{ latitude: 10, longitude: 10 }</code>).
            markers: "=",       // Array of map markers (e.g. <code>[{ lat: 10, lon: 10, name: "hello" }]</code>).
            details: "=",       //used for resend a REST api and store data in here
            width: "@",         // Map width in pixels.
            height: "@",        // Map height in pixels.
            zoom: "@",          // Zoom level (one is totally zoomed out, 25 is very much zoomed in).
            mapTypeId: "@",     // Type of tile to show on the map (roadmap, satellite, hybrid, terrain).
            panControl: "@",    // Whether to show a pan control on the map.
            zoomControl: "@",   // Whether to show a zoom control on the map.
            scaleControl: "@",   // Whether to show scale control on the map.
            onInit: "&",
            showDetail: "&"
        },
        link: function (scope, element, attrs) {
        //some code.....
             function updateMarkers() {
                if (map && scope.markers.length > 0) {
                    window.alert("get me");
                    // clear old markers
                    if (currentMarkers != null) {
                        for (var i = 0; i < currentMarkers.length; i++) {

                            currentMarkers.setMap(null);
                            window.alert("get here1*****");
                        }
                    }                          
                    // create new markers
                    currentMarkers = [];
                    var markers = scope.markers; 

                    function makeHappen(thi){
                        return function(){
                            scope.details = thi;
                            window.alert("***" + "in directive    " + thi); 
                        }
                    }

                    for (var i = 1; i < markers.length-1; i++) {                    
                        var m = markers[i];
                        if(m.venue == null || m.venue.lat == 0.0)
                            continue;
                        var loc = new google.maps.LatLng(m.venue.lat, m.venue.lon);
                        var eventName = m.description;  
                        var mm = new google.maps.Marker({ position: loc, map: map, title: m.name, id: m.id, count: i});                                                 
                        mm.addListener('click', makeHappen(eventName), false);                     
                        currentMarkers.push(mm);

                    }
                }
            }

2 个答案:

答案 0 :(得分:1)

我认为这与此处报道的问题类似: How to access parent scope from within a custom directive *with own scope* in AngularJS?

希望它有所帮助!

答案 1 :(得分:1)

使用.表示法正确启用双向数据绑定。 details是控制器中的基本类型。虽然指令中的隔离范围可以访问details,但当您在details函数中为makeHappen分配内容时,它会在隔离范围中创建新的details

<击>

在这种情况下,不是控制器中的基本类型$scope.details,而是将其作为对象,例如:$scope.details = {msg: 'something' }。在模板中打印即:{{details.msg}}。在隔离范围的details函数中将details.msg更改为makeHappen

更新

抱歉我的错误。看起来,您不需要将scope.details从字符串更改为对象。以下变化足以使其发挥作用。

function makeHappen(thi){
    return function(){
        scope.$apply(function() {
            scope.details = thi;  
        })
    }
}

对于隔离范围,只要在指令范围中更改共享变量(控制器范围var与指令范围共享),控制器中的变量也会更新。它是原始的还是对象并不重要,因为指令范围和控制器范围之间没有原型继承。但是,如果指令的scope属性为true(scope: true)而不是隔离范围,那么 scope.details 必须是一个对象才能看到控制器范围中更改的值(我之前解释过)。

所需的唯一更改是将scope.details = thi包裹在scope.$apply(function(){//code})内或在makeHappen返回函数结束时调用scope.$apply()

所以,问题是,为什么需要致电scope.$apply()或将某些代码放入scope.$apply(function() {//code})?原因是:

  

$ apply()用于从外部执行角度表达式   角度框架。 (例如,来自浏览器DOM事件,   setTimeout,XHR或第三方库。)

在您的情况下,您附加了一个事件监听器mm.addListener('click', makeHappen(eventName), false);。单击标记时将调用makeHappen函数。它发生在角度背景之外。 Angular不知道scope.details值已更改。因此,scope.details的观察者不会被调用,因此,您不会看到任何更新。而且,解决方案scope.$apply()来了。每当您致电scope.$apply()时,它会在内部调用scope.$digest(),实际更新任何绑定或观察者。

那么,你何时需要致电scope.$apply()?在场景的后面,Angular几乎包含了你在angular的上下文中编写的$ apply()中的所有代码。 ng-click$timeout$http回调等事件都包含在scope.$apply()内,因此您无需明确调用它。如果你自己打电话给$ apply,你会收到错误。

有关$ apply的更多信息,您可以访问以下链接: https://docs.angularjs.org/api/ng/type/ $ rootScope.Scope#$适用 http://jimhoskins.com/2012/12/17/angularjs-and-apply.html

我已经为您提供了更好的理解指令中的不同范围方案以及在某些情况下需要$apply的原因。请看看这个插件。 http://plnkr.co/edit/96a646T6FuBhmjdLgJXq?p=preview