简体   繁体   中英

AngularJS Scope differences between 1.0.x and 1.2.x

As of the release of the next stable AngularJS, I am migrating my application from version 1.0.8 to 1.2 .

In AngularJS 1.0.8 it was possible to set up an isolated scope for directives like follow . The directive would then use its own test() function instead of the controller's test() function.

HTML

<my-dialog property="something">
    <button ng-click="test()">Load Test</button>
    Check out the test: "{{ testMessage }}"
</my-dialog>

Javascript

  .controller('Ctrl', function(scope) {
    scope.test = function () {
       scope.testMessage = 'CTRL Test loaded! Whooops.';
    }
  })

  .directive('myDialog', function() {
    return {
      restrict: 'E',
      scope: {
          property: '='
      },
      link: function(scope) {
          scope.test = function () {
            scope.testMessage = 'Isolated Test loaded. Yes!';
          }
      }
    };

In AngularJS 1.2 this behavior doesn't work anymore. Clicking the button fires the controller's test() function now.

See this jsFiddle comparison:

What exactly has changes and how can I reproduce the old behavior?

Note

I figured out I could place the directives template inside an extra HTML file or compile it as a string to get it working ( jsFiddle ) but it seems to be too much in my case, as the template is fixed and splitting the HTML over several partial HTML files is a hassle.

EDIT

@elclanr's answer works fine when there are no other properties to share. I updated the jsFiddle to pass some arbitrary property. How should I proceed now?

It looks like this is an intended result of the breaking change: github.com/angular/angular.js/commit/… Which was pulled in 1.2.0 (after rc3) ( https://github.com/angular/angular.js/blob/master/CHANGELOG.md - see the first breaking change for 1.2.0 - $compile):

Fixes issue with isolate scope leaking all over the place into other directives on the same element.

Isolate scope is now available only to the isolate directive that requested it and its template.

A non-isolate directive should not get the isolate scope of an isolate directive on the same element,instead they will receive the original scope (which is the parent scope of the newly created isolate scope).

Also check out this discussion: github.com/angular/angular.js/issues/4889

Notably: "The isolate scope is only applied to the template, but not to markup that was not contributed by the directive. Before 1.2 isolate scopes had a bug that caused this kind of leakage. The point of the isolate scope is that it only applies to the directive that declared it, and not to other directives or markup. " (from tbosch)

Previous to 1.2.0 everything on the same DOM element shared the same scope. So 1.2.0 makes a substantial change to how directives with isolate scopes work.

Setting scope: true should solve the issue. http://jsfiddle.net/rug3J/1 . I would also advise to follow convention and name it scope and not $scope when it's not dependency injected:

.directive('myDialog', function() {
  return {
    restrict: 'E',
    scope: true,
    link: function(scope) {
      scope.test = function () {
        scope.testMessage = 'Isolated Test loaded. Yes!';
      }
    }
  };

In order to combine normal markup with directive specific templates and function one need to make use of the transclude option like so:

See: jsFiddle

HTML

<div ng-app="myApp">
    <div ng-controller="Ctrl">
        <my-directive property="{{ something }}">
            <p>{{ text }}</p>
        </my-directive>
    </div>
</div>

Javascript

.controller('Ctrl', ['$scope', function($scope) {
    $scope.text = 'This is a controllers text.';
    $scope.something = 'This is another controllers text.';
}])
.directive('myDirective', function() {
    return {
        restrict: 'E',
        transclude: true,
        template: '<button ng-click="test()">Fire directives function</button><div ng-transclude></div><p>{{ property }}</p>',
        scope: {
            property: '@'
        },
        link: function(scope) {
            scope.test = function () {
                scope.property = 'Loaded directives text.';
            }
        }
    };
});

This works fine for me now but it should be noted that one can not override existing properties of the scope.

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