mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
feat(jqLite): expose isolateScope() getter similar to scope()
See doc update in the diff for more info. BREAKING CHANGE: jqLite#scope() does not return the isolate scope on the element that triggered directive with isolate scope. Use jqLite#isolateScope() instead.
This commit is contained in:
parent
b5af198f0d
commit
27e9340b3c
5 changed files with 178 additions and 6 deletions
|
|
@ -1244,6 +1244,7 @@ function bindJQuery() {
|
|||
jqLite = jQuery;
|
||||
extend(jQuery.fn, {
|
||||
scope: JQLitePrototype.scope,
|
||||
isolateScope: JQLitePrototype.isolateScope,
|
||||
controller: JQLitePrototype.controller,
|
||||
injector: JQLitePrototype.injector,
|
||||
inheritedData: JQLitePrototype.inheritedData
|
||||
|
|
|
|||
|
|
@ -85,6 +85,9 @@
|
|||
* - `injector()` - retrieves the injector of the current element or its parent.
|
||||
* - `scope()` - retrieves the {@link api/ng.$rootScope.Scope scope} of the current
|
||||
* element or its parent.
|
||||
* - `isolateScope()` - retrieves an isolate {@link api/ng.$rootScope.Scope scope} if one is attached directly to the
|
||||
* current element. This getter should be used only on elements that contain a directive which starts a new isolate
|
||||
* scope. Calling `scope()` on this element always returns the original non-isolate scope.
|
||||
* - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
|
||||
* parent element is reached.
|
||||
*
|
||||
|
|
@ -344,9 +347,13 @@ function jqLiteInheritedData(element, name, value) {
|
|||
if(element[0].nodeType == 9) {
|
||||
element = element.find('html');
|
||||
}
|
||||
var names = isArray(name) ? name : [name];
|
||||
|
||||
while (element.length) {
|
||||
if ((value = element.data(name)) !== undefined) return value;
|
||||
|
||||
for (var i = 0, ii = names.length; i < ii; i++) {
|
||||
if ((value = element.data(names[i])) !== undefined) return value;
|
||||
}
|
||||
element = element.parent();
|
||||
}
|
||||
}
|
||||
|
|
@ -418,7 +425,13 @@ forEach({
|
|||
inheritedData: jqLiteInheritedData,
|
||||
|
||||
scope: function(element) {
|
||||
return jqLiteInheritedData(element, '$scope');
|
||||
// Can't use jqLiteData here directly so we stay compatible with jQuery!
|
||||
return jqLite(element).data('$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
|
||||
},
|
||||
|
||||
isolateScope: function(element) {
|
||||
// Can't use jqLiteData here directly so we stay compatible with jQuery!
|
||||
return jqLite(element).data('$isolateScope') || jqLite(element).data('$isolateScopeNoTemplate');
|
||||
},
|
||||
|
||||
controller: jqLiteController ,
|
||||
|
|
|
|||
|
|
@ -1368,7 +1368,15 @@ function $CompileProvider($provide) {
|
|||
var $linkNode = jqLite(linkNode);
|
||||
|
||||
isolateScope = scope.$new(true);
|
||||
$linkNode.data('$isolateScope', isolateScope);
|
||||
|
||||
if (templateDirective && (templateDirective === newIsolateScopeDirective.$$originalDirective)) {
|
||||
$linkNode.data('$isolateScope', isolateScope) ;
|
||||
} else {
|
||||
$linkNode.data('$isolateScopeNoTemplate', isolateScope);
|
||||
}
|
||||
|
||||
|
||||
|
||||
safeAddClass($linkNode, 'ng-isolate-scope');
|
||||
|
||||
forEach(newIsolateScopeDirective.scope, function(definition, scopeName) {
|
||||
|
|
@ -1600,7 +1608,7 @@ function $CompileProvider($provide) {
|
|||
origAsyncDirective = directives.shift(),
|
||||
// The fact that we have to copy and patch the directive seems wrong!
|
||||
derivedSyncDirective = extend({}, origAsyncDirective, {
|
||||
templateUrl: null, transclude: null, replace: null
|
||||
templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
|
||||
}),
|
||||
templateUrl = (isFunction(origAsyncDirective.templateUrl))
|
||||
? origAsyncDirective.templateUrl($compileNode, tAttrs)
|
||||
|
|
|
|||
|
|
@ -151,6 +151,13 @@ describe('jqLite', function() {
|
|||
dealoc(element);
|
||||
});
|
||||
|
||||
it('should retrieve isolate scope attached to the current element', function() {
|
||||
var element = jqLite('<i>foo</i>');
|
||||
element.data('$isolateScope', scope);
|
||||
expect(element.isolateScope()).toBe(scope);
|
||||
dealoc(element);
|
||||
});
|
||||
|
||||
it('should retrieve scope attached to the html element if its requested on the document',
|
||||
function() {
|
||||
var doc = jqLite(document),
|
||||
|
|
@ -182,6 +189,33 @@ describe('jqLite', function() {
|
|||
});
|
||||
|
||||
|
||||
describe('isolateScope', function() {
|
||||
|
||||
it('should retrieve isolate scope attached to the current element', function() {
|
||||
var element = jqLite('<i>foo</i>');
|
||||
element.data('$isolateScope', scope);
|
||||
expect(element.isolateScope()).toBe(scope);
|
||||
dealoc(element);
|
||||
});
|
||||
|
||||
|
||||
it('should not walk up the dom to find scope', function() {
|
||||
var element = jqLite('<ul><li><p><b>deep deep</b><p></li></ul>');
|
||||
var deepChild = jqLite(element[0].getElementsByTagName('b')[0]);
|
||||
element.data('$isolateScope', scope);
|
||||
expect(deepChild.isolateScope()).toBeUndefined();
|
||||
dealoc(element);
|
||||
});
|
||||
|
||||
|
||||
it('should return undefined when no scope was found', function() {
|
||||
var element = jqLite('<div></div>');
|
||||
expect(element.isolateScope()).toBeFalsy();
|
||||
dealoc(element);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('injector', function() {
|
||||
it('should retrieve injector attached to the current element or its parent', function() {
|
||||
var template = jqLite('<div><span></span></div>'),
|
||||
|
|
|
|||
|
|
@ -1375,7 +1375,7 @@ describe('$compile', function() {
|
|||
return function (scope, element) {
|
||||
iscope = scope;
|
||||
log(scope.$id);
|
||||
expect(element.data('$isolateScope')).toBe(scope);
|
||||
expect(element.data('$isolateScopeNoTemplate')).toBe(scope);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
@ -1522,7 +1522,7 @@ describe('$compile', function() {
|
|||
);
|
||||
|
||||
|
||||
it('should allow more one new scope directives per element, but directives should share' +
|
||||
it('should allow more than one new scope directives per element, but directives should share' +
|
||||
'the scope', inject(
|
||||
function($rootScope, $compile, log) {
|
||||
element = $compile('<div class="scope-a; scope-b"></div>')($rootScope);
|
||||
|
|
@ -1554,6 +1554,120 @@ describe('$compile', function() {
|
|||
expect(log).toEqual('002');
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
describe('scope()/isolate() scope getters', function() {
|
||||
|
||||
describe('with no directives', function() {
|
||||
|
||||
it('should return the scope of the parent node', inject(
|
||||
function($rootScope, $compile) {
|
||||
element = $compile('<div></div>')($rootScope);
|
||||
expect(element.scope()).toBe($rootScope);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
describe('with new scope directives', function() {
|
||||
|
||||
it('should return the new scope at the directive element', inject(
|
||||
function($rootScope, $compile) {
|
||||
element = $compile('<div scope></div>')($rootScope);
|
||||
expect(element.scope().$parent).toBe($rootScope);
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should return the new scope for children in the original template', inject(
|
||||
function($rootScope, $compile) {
|
||||
element = $compile('<div scope><a></a></div>')($rootScope);
|
||||
expect(element.find('a').scope().$parent).toBe($rootScope);
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should return the new scope for children in the directive template', inject(
|
||||
function($rootScope, $compile, $httpBackend) {
|
||||
$httpBackend.expect('GET', 'tscope.html').respond('<a></a>');
|
||||
element = $compile('<div tscope></div>')($rootScope);
|
||||
$httpBackend.flush();
|
||||
expect(element.find('a').scope().$parent).toBe($rootScope);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
describe('with isolate scope directives', function() {
|
||||
|
||||
it('should return the root scope for directives at the root element', inject(
|
||||
function($rootScope, $compile) {
|
||||
element = $compile('<div iscope></div>')($rootScope);
|
||||
expect(element.scope()).toBe($rootScope);
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should return the non-isolate scope at the directive element', inject(
|
||||
function($rootScope, $compile) {
|
||||
var directiveElement;
|
||||
element = $compile('<div><div iscope></div></div>')($rootScope);
|
||||
directiveElement = element.children();
|
||||
expect(directiveElement.scope()).toBe($rootScope);
|
||||
expect(directiveElement.isolateScope().$parent).toBe($rootScope);
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should return the isolate scope for children in the original template', inject(
|
||||
function($rootScope, $compile) {
|
||||
element = $compile('<div iscope><a></a></div>')($rootScope);
|
||||
expect(element.find('a').scope()).toBe($rootScope); //xx
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should return the isolate scope for children in directive template', inject(
|
||||
function($rootScope, $compile, $httpBackend) {
|
||||
$httpBackend.expect('GET', 'tiscope.html').respond('<a></a>');
|
||||
element = $compile('<div tiscope></div>')($rootScope);
|
||||
expect(element.isolateScope()).toBeUndefined(); // this is the current behavior, not desired feature
|
||||
$httpBackend.flush();
|
||||
expect(element.find('a').scope()).toBe(element.isolateScope());
|
||||
expect(element.isolateScope()).not.toBe($rootScope);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
describe('with isolate scope directives and directives that manually create a new scope', function() {
|
||||
|
||||
it('should return the new scope at the directive element', inject(
|
||||
function($rootScope, $compile) {
|
||||
var directiveElement;
|
||||
element = $compile('<div><a ng-if="true" iscope></a></div>')($rootScope);
|
||||
$rootScope.$apply();
|
||||
directiveElement = element.find('a');
|
||||
expect(directiveElement.scope().$parent).toBe($rootScope);
|
||||
expect(directiveElement.scope()).not.toBe(directiveElement.isolateScope());
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
it('should return the isolate scope for child elements', inject(
|
||||
function($rootScope, $compile, $httpBackend) {
|
||||
var directiveElement, child;
|
||||
$httpBackend.expect('GET', 'tiscope.html').respond('<span></span>');
|
||||
element = $compile('<div><a ng-if="true" tiscope></a></div>')($rootScope);
|
||||
$rootScope.$apply();
|
||||
$httpBackend.flush();
|
||||
directiveElement = element.find('a');
|
||||
child = directiveElement.find('span');
|
||||
expect(child.scope()).toBe(directiveElement.isolateScope());
|
||||
})
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -2121,6 +2235,7 @@ describe('$compile', function() {
|
|||
});
|
||||
}));
|
||||
|
||||
|
||||
it('should give other directives the parent scope', inject(function($rootScope) {
|
||||
compile('<div><input type="text" my-component store-scope ng-model="value"></div>');
|
||||
$rootScope.$apply(function() {
|
||||
|
|
@ -2131,6 +2246,7 @@ describe('$compile', function() {
|
|||
expect(componentScope.$parent).toBe(regularScope)
|
||||
}));
|
||||
|
||||
|
||||
it('should not give the isolate scope to other directive template', function() {
|
||||
module(function() {
|
||||
directive('otherTplDir', function() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue