mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-05-16 02:28:03 +08:00
If enter -> leave -> enter -> leave occurs then the first leave animation will animate alongside the second. This causes the very first DOM node (the view in ngView for example) to animate at the same time as the most recent DOM node which ends up being an undesired effect. This fix takes care of this issue. Closes #5886
319 lines
9.0 KiB
JavaScript
Executable File
319 lines
9.0 KiB
JavaScript
Executable File
'use strict';
|
|
|
|
describe('ngIf', function () {
|
|
var $scope, $compile, element, $compileProvider;
|
|
|
|
beforeEach(module(function(_$compileProvider_) {
|
|
$compileProvider = _$compileProvider_;
|
|
}));
|
|
beforeEach(inject(function ($rootScope, _$compile_) {
|
|
$scope = $rootScope.$new();
|
|
$compile = _$compile_;
|
|
element = $compile('<div></div>')($scope);
|
|
}));
|
|
|
|
afterEach(function () {
|
|
dealoc(element);
|
|
});
|
|
|
|
function makeIf(expr) {
|
|
element.append($compile('<div class="my-class" ng-if="' + expr + '"><div>Hi</div></div>')($scope));
|
|
$scope.$apply();
|
|
}
|
|
|
|
it('should immediately remove element if condition is false', function () {
|
|
makeIf('false');
|
|
expect(element.children().length).toBe(0);
|
|
});
|
|
|
|
it('should leave the element if condition is true', function () {
|
|
makeIf('true');
|
|
expect(element.children().length).toBe(1);
|
|
});
|
|
|
|
it('should not add the element twice if the condition goes from true to true', function () {
|
|
$scope.hello = 'true1';
|
|
makeIf('hello');
|
|
expect(element.children().length).toBe(1);
|
|
$scope.$apply('hello = "true2"');
|
|
expect(element.children().length).toBe(1);
|
|
});
|
|
|
|
it('should not recreate the element if the condition goes from true to true', function () {
|
|
$scope.hello = 'true1';
|
|
makeIf('hello');
|
|
element.children().data('flag', true);
|
|
$scope.$apply('hello = "true2"');
|
|
expect(element.children().data('flag')).toBe(true);
|
|
});
|
|
|
|
it('should create then remove the element if condition changes', function () {
|
|
$scope.hello = true;
|
|
makeIf('hello');
|
|
expect(element.children().length).toBe(1);
|
|
$scope.$apply('hello = false');
|
|
expect(element.children().length).toBe(0);
|
|
});
|
|
|
|
it('should create a new scope every time the expression evaluates to true', function () {
|
|
$scope.$apply('value = true');
|
|
element.append($compile(
|
|
'<div ng-if="value"><span ng-init="value=false"></span></div>'
|
|
)($scope));
|
|
$scope.$apply();
|
|
expect(element.children('div').length).toBe(1);
|
|
});
|
|
|
|
it('should destroy the child scope every time the expression evaluates to false', function() {
|
|
$scope.value = true;
|
|
element.append($compile(
|
|
'<div ng-if="value"></div>'
|
|
)($scope));
|
|
$scope.$apply();
|
|
|
|
var childScope = element.children().scope();
|
|
var destroyed = false;
|
|
|
|
childScope.$on('$destroy', function() {
|
|
destroyed = true;
|
|
});
|
|
|
|
$scope.value = false;
|
|
$scope.$apply();
|
|
|
|
expect(destroyed).toBe(true);
|
|
});
|
|
|
|
it('should play nice with other elements beside it', function () {
|
|
$scope.values = [1, 2, 3, 4];
|
|
element.append($compile(
|
|
'<div ng-repeat="i in values"></div>' +
|
|
'<div ng-if="values.length==4"></div>' +
|
|
'<div ng-repeat="i in values"></div>'
|
|
)($scope));
|
|
$scope.$apply();
|
|
expect(element.children().length).toBe(9);
|
|
$scope.$apply('values.splice(0,1)');
|
|
expect(element.children().length).toBe(6);
|
|
$scope.$apply('values.push(1)');
|
|
expect(element.children().length).toBe(9);
|
|
});
|
|
|
|
it('should play nice with ngInclude on the same element', inject(function($templateCache) {
|
|
$templateCache.put('test.html', [200, '{{value}}', {}]);
|
|
|
|
$scope.value = 'first';
|
|
element.append($compile(
|
|
'<div ng-if="value==\'first\'" ng-include="\'test.html\'"></div>'
|
|
)($scope));
|
|
$scope.$apply();
|
|
expect(element.text()).toBe('first');
|
|
|
|
$scope.value = 'later';
|
|
$scope.$apply();
|
|
expect(element.text()).toBe('');
|
|
}));
|
|
|
|
it('should work with multiple elements', function() {
|
|
$scope.show = true;
|
|
$scope.things = [1, 2, 3];
|
|
element.append($compile(
|
|
'<div>before;</div>' +
|
|
'<div ng-if-start="show">start;</div>' +
|
|
'<div ng-repeat="thing in things">{{thing}};</div>' +
|
|
'<div ng-if-end>end;</div>' +
|
|
'<div>after;</div>'
|
|
)($scope));
|
|
$scope.$apply();
|
|
expect(element.text()).toBe('before;start;1;2;3;end;after;');
|
|
|
|
$scope.things.push(4);
|
|
$scope.$apply();
|
|
expect(element.text()).toBe('before;start;1;2;3;4;end;after;');
|
|
|
|
$scope.show = false;
|
|
$scope.$apply();
|
|
expect(element.text()).toBe('before;after;');
|
|
});
|
|
|
|
it('should restore the element to its compiled state', function() {
|
|
$scope.value = true;
|
|
makeIf('value');
|
|
expect(element.children().length).toBe(1);
|
|
jqLite(element.children()[0]).removeClass('my-class');
|
|
expect(element.children()[0].className).not.toContain('my-class');
|
|
$scope.$apply('value = false');
|
|
expect(element.children().length).toBe(0);
|
|
$scope.$apply('value = true');
|
|
expect(element.children().length).toBe(1);
|
|
expect(element.children()[0].className).toContain('my-class');
|
|
});
|
|
|
|
it('should work when combined with an ASYNC template that loads after the first digest', inject(function($httpBackend, $compile, $rootScope) {
|
|
$compileProvider.directive('test', function() {
|
|
return {
|
|
templateUrl: 'test.html'
|
|
};
|
|
});
|
|
$httpBackend.whenGET('test.html').respond('hello');
|
|
element.append('<div ng-if="show" test></div>');
|
|
$compile(element)($rootScope);
|
|
$rootScope.show = true;
|
|
$rootScope.$apply();
|
|
expect(element.text()).toBe('');
|
|
|
|
$httpBackend.flush();
|
|
expect(element.text()).toBe('hello');
|
|
|
|
$rootScope.show = false;
|
|
$rootScope.$apply();
|
|
// Note: there are still comments in element!
|
|
expect(element.children().length).toBe(0);
|
|
expect(element.text()).toBe('');
|
|
}));
|
|
});
|
|
|
|
describe('ngIf and transcludes', function() {
|
|
it('should allow access to directive controller from children when used in a replace template', function() {
|
|
var controller;
|
|
module(function($compileProvider) {
|
|
var directive = $compileProvider.directive;
|
|
directive('template', valueFn({
|
|
template: '<div ng-if="true"><span test></span></div>',
|
|
replace: true,
|
|
controller: function() {
|
|
this.flag = true;
|
|
}
|
|
}));
|
|
directive('test', valueFn({
|
|
require: '^template',
|
|
link: function(scope, el, attr, ctrl) {
|
|
controller = ctrl;
|
|
}
|
|
}));
|
|
});
|
|
inject(function($compile, $rootScope) {
|
|
var element = $compile('<div><div template></div></div>')($rootScope);
|
|
$rootScope.$apply();
|
|
expect(controller.flag).toBe(true);
|
|
dealoc(element);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('ngIf animations', function () {
|
|
var body, element, $rootElement;
|
|
|
|
function html(html) {
|
|
$rootElement.html(html);
|
|
element = $rootElement.children().eq(0);
|
|
return element;
|
|
}
|
|
|
|
beforeEach(module('ngAnimateMock'));
|
|
|
|
beforeEach(module(function() {
|
|
// we need to run animation on attached elements;
|
|
return function(_$rootElement_) {
|
|
$rootElement = _$rootElement_;
|
|
body = jqLite(document.body);
|
|
body.append($rootElement);
|
|
};
|
|
}));
|
|
|
|
afterEach(function(){
|
|
dealoc(body);
|
|
dealoc(element);
|
|
});
|
|
|
|
beforeEach(module(function($animateProvider, $provide) {
|
|
return function($animate) {
|
|
$animate.enabled(true);
|
|
};
|
|
}));
|
|
|
|
it('should fire off the enter animation',
|
|
inject(function($compile, $rootScope, $animate) {
|
|
var item;
|
|
var $scope = $rootScope.$new();
|
|
element = $compile(html(
|
|
'<div>' +
|
|
'<div ng-if="value"><div>Hi</div></div>' +
|
|
'</div>'
|
|
))($scope);
|
|
|
|
$rootScope.$digest();
|
|
$scope.$apply('value = true');
|
|
|
|
item = $animate.queue.shift();
|
|
expect(item.event).toBe('enter');
|
|
expect(item.element.text()).toBe('Hi');
|
|
|
|
expect(element.children().length).toBe(1);
|
|
}));
|
|
|
|
it('should fire off the leave animation',
|
|
inject(function ($compile, $rootScope, $animate) {
|
|
var item;
|
|
var $scope = $rootScope.$new();
|
|
element = $compile(html(
|
|
'<div>' +
|
|
'<div ng-if="value"><div>Hi</div></div>' +
|
|
'</div>'
|
|
))($scope);
|
|
$scope.$apply('value = true');
|
|
|
|
item = $animate.queue.shift();
|
|
expect(item.event).toBe('enter');
|
|
expect(item.element.text()).toBe('Hi');
|
|
|
|
expect(element.children().length).toBe(1);
|
|
$scope.$apply('value = false');
|
|
|
|
item = $animate.queue.shift();
|
|
expect(item.event).toBe('leave');
|
|
expect(item.element.text()).toBe('Hi');
|
|
|
|
expect(element.children().length).toBe(0);
|
|
}));
|
|
|
|
it('should destroy the previous leave animation if a new one takes place', function() {
|
|
module(function($provide) {
|
|
$provide.value('$animate', {
|
|
enabled : function() { return true; },
|
|
leave : function() {
|
|
//DOM operation left blank
|
|
},
|
|
enter : function(element, parent) {
|
|
parent.append(element);
|
|
}
|
|
});
|
|
});
|
|
inject(function ($compile, $rootScope, $animate) {
|
|
var item;
|
|
var $scope = $rootScope.$new();
|
|
element = $compile(html(
|
|
'<div>' +
|
|
'<div ng-if="value">Yo</div>' +
|
|
'</div>'
|
|
))($scope);
|
|
|
|
$scope.$apply('value = true');
|
|
|
|
var destroyed, inner = element.children(0);
|
|
inner.on('$destroy', function() {
|
|
destroyed = true;
|
|
});
|
|
|
|
$scope.$apply('value = false');
|
|
|
|
$scope.$apply('value = true');
|
|
|
|
$scope.$apply('value = false');
|
|
|
|
expect(destroyed).toBe(true);
|
|
});
|
|
});
|
|
|
|
});
|