angularjs give all html elements of a specific type their own scope

爱⌒轻易说出口 提交于 2019-12-25 05:46:09

问题


I need to do this to make use of the <dialog> tag in HTML5, I want every <dialog> on my site to have its own unique scope accessible using the controller and controllerAs syntax.

Here is what I thought would work.

Javascript

\\Dialog Controller 

function dialog () {
    return {
        scope: {},
        controller: function () {
            this.test = 'Dialog Test';
        },
        controllerAs: 'Dialog',
        bindToController: true
    }
} 

angular.module('app',[]).directive('dialog', dialog);

HTML

<!-- Dialog HTML Example Case -->
<body ng-app='app'>
    <dialog id='test'>{{Dialog.test}}</dialog>
</body>

I would expect that when the dialog was activated Dialog.test would evaluate to Dialog Test. What happens instead is that it evaluates to an empty string. What's more is that if I add a controller to the body, the dialog has access to its scope. It is as though the isolate scope definition in my directive is completely ignored.

Plunk

Note that I have modified the plunk to use <span> instead of <dialog> due to the lack of support in most browsers.

http://plnkr.co/edit/eXtUq7BxCajOZAp8BpVe?p=preview


回答1:


You are creating isolated scope, thats good thing. But after AngularJS1.2 version, they have done some breaking changes, where isolated scope will be completely isolated.

So Span directive's scope will be visible to template of that directive(Span) only.

And inner html of that directive will get only parent/current scope only instead of directive isolated scope(As Isolated Scope will be visible to template only). To print value of Span.test, you have to create template and refer that template in your directive as below:

   var app = angular.module('test', []);
   function mainCtrl() {
       this.test = 'test';
   };
   function spanCtrl() {
       this.test = 'Span Test';
   }
   function span () {
       return {
           scope: {},
           controller: spanCtrl,
           controllerAs: 'Span',
           template: '{{Span.test}}'
       }
   }

    app.controller('mainCtrl', mainCtrl);
    app.directive('span', span);

You can checkout two awesome blog for more detail Component In AngularJS and Transclude In AngularJS




回答2:


Contents of an element do not "see" the isolate scope of a directive. The fact that the scope is "isolate" means that it is separate from the scope of the View where both the directive and contents of its hosting element reside.

To link the contents against the internal scope, you'd need to transclude them - the transclude function allows you to link it against any scope:

function dialog () {
    return {
        scope: {},
        controller: function () {
            this.test = 'Dialog Test';
        },
        controllerAs: 'Dialog',
        bindToController: true
        transclude: true.
        link: function(scope, element, attrs, ctrls, transclude){

           // scope here is the isolate scope of the directive
           transclude(scope, function cloneAttachFn(contentsClone){
             element.append(contentsClone);
           });
        }
    }
} 

The above would work, but it's still important to understand why the "default" behavior makes sense. Consider that to a user of your directive, the directive's internal (i.e. isolate) functionality (and thus scope variables) ought to be invisible. If it wasn't, the user of your directive would need to know about "special" scope variables, like Dialog, in your case. So, someone who reads your HTML would have no idea where Dialog came from without knowing how the directive operates.




回答3:


There is a mistake in original assertion: the contents of dialog directive node

<dialog id='test'>{{Dialog.test}}</dialog>

belong to parent's scope, not to directive's scope. Therefore, it interpolates Dialog.test from parent controller (or root scope if there is none).

It is possible to achieve the behaviour that was expected with something like this:

app.directive('dialog', function ($interpolate) {
  return {
    scope: {},
    controller: function ($scope) {
      this.test = 'test';
    },
    controllerAs: 'Dialog',
    compile: function (element) {
      var template = element.text();

      return function (scope, element) {
        element.text($interpolate(template)(scope));
      }
    }
  };
});

But it can hardly be called a promoted way to use Angular. Let the directive handle its template.



来源:https://stackoverflow.com/questions/32060208/angularjs-give-all-html-elements-of-a-specific-type-their-own-scope

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!