简体   繁体   中英

Get the scope's element outside the directive

Is there a trick to get the element associated with the scope outside the directive that owns it?

I act on the premise that it has to be done in least favorable conditions (from the console or Greasemonkey script). Eg to get the element that has the scope

angular.element(document.querySelector('.ng-scope')).scope().$$childTail

without DOM traversing.

I guess it is possible to traverse all ng-scope and ng-isolate-scope DOM elements and map their scopes, yet I'm looking for more elegant solution (the map also needs to be kept up to date, and I'm trying to stay away from DOMSubtreeModified , also this won't work with debugInfoEnabled disabled).

Scopes (src) don't keep a reference to the element they're associated with. After all, scopes can exist without being associated with a specific element.

$compile (src) is the one responsible for associating elements with scopes.

Part of the compilation process augments the element, letting you go from element >> scope (eg angular.element("#something").scope() ). The same doesn't seem to happen with scopes.

So to go the other way, scope >> element, you have to map scope ids: Get DOM element by scope $id . That feature in Angular JS Batarang that lets you pick an element from the page and inspect the scope associated with it? This is how it's done. Batarang uses angular-hint. angular-hint iterates through all elements on the page with an ng-scope class and returns the one with a matching scope id (src: function findElt ) .

function findElt (scopeId) {
  var elts = document.querySelectorAll('.ng-scope');
  var elt, scope;

  for (var i = 0; i < elts.length; i++) {
    elt = angular.element(elts[i]);
    scope = elt.scope();
    if (scope.$id === scopeId) {
      return elt;
    }
  }
}

There are a few things you can do to get the element of a directive.

Element on event

If you need to pass the element on an event, you can create a callback which can pass the element back. If you do not need a reference to it all the time, this is the preferred method.

In you return object in the directive, Add something like

    scope:{
      elementclicked: "&"
    }

In the template of your directive, you can add

    <....... ng-click="ElementClicked(event)"........>

In your Directive Controller, you can now handle the click and Pass the results

$scope.ElementClicked = function ($event) {
    if ($scope.elementclicked != undefined) {
        elementclicked({ event: $event });
    }
}

Now you pass your callback like any other to the directive.

    <yourDirective   elementclicked="MyFunction(event)" ....>

Element when linked

If you need a reference at the time of creation, you can do that as well. If you Pass in a data structure such as settings you could set it in the linking event. When you do your linking in the directive, just set the element.

scope:{
        settings:"="
},
link:function(scope,element){
    scope.$watch('settings',function(){
        if(scope.settings!=undefined){
            scope.settings.element=element;
        }
}
}

This will watch for when the settings are bound and set the element property. The big disadvantage here is that you are appending a property to a passed object but if it is for a directive inside a directive or it is just your project, it should be fine.

Another way to do it would be to use the first method and create an elementlinked(element) callback and fire it after you link the scope.

What I have understood, you want to access scope's value outside the directive. I have made a small smaple, check it:

HTML Part:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.15/angular.js" data-semver="1.3.15"></script>

  <div id="outer" ng-app="plunker" ng-controller="MainCtrl">
    You are {{msg}}
</div>
<div onclick="change()">click me</div> 

Scipt part:

var app = angular.module('plunker', []);

    app.controller('MainCtrl', function($scope, $rootScope) {
     $scope.msg = "great";
        $rootScope.safeApply = function( fn ) {
            var phase = this.$root.$$phase;
            if(phase == '$apply' || phase == '$digest') {
                if(fn) {
                    fn();
                }
            } else {
                this.$apply(fn);
            }
        };
    });

//Custom java script

function change() {
    var scope = angular.element($("#outer")).scope();
    scope.safeApply(function(){
        scope.msg = 'Superhero';
    })
}

For Above code working Plunker Link is here: Plunker

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM