Skip to content

Commit e7a841b

Browse files
committed
First-pass refactor to support Angular 1.2 animation.
1 parent 7ef4d77 commit e7a841b

File tree

3 files changed

+89
-46
lines changed

3 files changed

+89
-46
lines changed

src/stateDirectives.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ function $StateRefDirective($state, $timeout) {
9090
if ((button === 0 || button == 1) && !e.ctrlKey && !e.metaKey && !e.shiftKey && !element.attr('target')) {
9191
// HACK: This is to allow ng-clicks to be processed before the transition is initiated:
9292
$timeout(function() {
93-
$state.go(ref.state, params, { relative: base });
93+
$state.go(ref.state, params, { relative: base });
9494
});
9595
e.preventDefault();
9696
}

src/viewDirective.js

+41-27
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,46 @@
1717
*/
1818
$ViewDirective.$inject = ['$state', '$compile', '$controller', '$injector', '$uiViewScroll'];
1919
function $ViewDirective( $state, $compile, $controller, $injector, $uiViewScroll) {
20-
var $animator = $injector.has('$animator') ? $injector.get('$animator') : false;
21-
var viewIsUpdating = false;
20+
21+
function getService() {
22+
return ($injector.has) ? function(service) {
23+
return $injector.has(service) ? $injector.get(service) : null;
24+
} : function(service) {
25+
try {
26+
return $injector.get(service);
27+
} catch (e) {
28+
return null;
29+
}
30+
};
31+
}
32+
33+
var viewIsUpdating = false, service = getService(),
34+
$animator = service('$animator'), $animate = service('$animate'),
35+
hasAnimator = !!($animator || $animate);
36+
37+
// Returns a set of DOM manipulation functions based on whether animation
38+
// should be performed
39+
var renderer = function(shouldAnimate) {
40+
return (hasAnimator && shouldAnimate) ? {
41+
remove: function(element) { $animate.leave(element.contents()); },
42+
// remove: function(element) { animate.leave(element.contents(), element); },
43+
restore: function(compiled, element) { $animate.enter(compiled, element); },
44+
// restore: function(compiled, element) { animate.enter(compiled, element); },
45+
populate: function(template, element) {
46+
var contents = angular.element('<div></div>').html(template).contents();
47+
// animate.enter(contents, element);
48+
$animate.enter(contents, element);
49+
return contents;
50+
}
51+
} : {
52+
remove: function(element) { element.html(''); },
53+
restore: function(compiled, element) { element.append(compiled); },
54+
populate: function(template, element) {
55+
element.html(template);
56+
return element.contents();
57+
}
58+
};
59+
};
2260

2361
var directive = {
2462
restrict: 'ECA',
@@ -34,30 +72,6 @@ function $ViewDirective( $state, $compile, $controller, $injector, $ui
3472
animate = $animator && $animator(scope, attr),
3573
initialView = transclude(scope);
3674

37-
// Returns a set of DOM manipulation functions based on whether animation
38-
// should be performed
39-
var renderer = function(doAnimate) {
40-
return ({
41-
"true": {
42-
remove: function(element) { animate.leave(element.contents(), element); },
43-
restore: function(compiled, element) { animate.enter(compiled, element); },
44-
populate: function(template, element) {
45-
var contents = angular.element('<div></div>').html(template).contents();
46-
animate.enter(contents, element);
47-
return contents;
48-
}
49-
},
50-
"false": {
51-
remove: function(element) { element.html(''); },
52-
restore: function(compiled, element) { element.append(compiled); },
53-
populate: function(template, element) {
54-
element.html(template);
55-
return element.contents();
56-
}
57-
}
58-
})[doAnimate.toString()];
59-
};
60-
6175
// Put back the compiled initial view
6276
element.append(initialView);
6377

@@ -87,7 +101,7 @@ function $ViewDirective( $state, $compile, $controller, $injector, $ui
87101
function updateView(doAnimate) {
88102
var locals = $state.$current && $state.$current.locals[name];
89103
if (locals === viewLocals) return; // nothing to do
90-
var render = renderer(animate && doAnimate);
104+
var render = renderer(doAnimate);
91105

92106
// Remove existing content
93107
render.remove(element);

test/viewDirectiveSpec.js

+47-18
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ describe('uiView', function () {
1515

1616
var scope, $compile, elem;
1717

18-
beforeEach(module('ui.router'));
18+
beforeEach(function() {
19+
angular.module('ui.router.test', ['ui.router', 'ngAnimate']);
20+
module('ui.router.test');
21+
module('mock.animate');
22+
});
1923

2024
beforeEach(module(function ($provide) {
2125
$provide.decorator('$uiViewScroll', function ($delegate) {
@@ -96,60 +100,72 @@ describe('uiView', function () {
96100
}));
97101

98102
describe('linking ui-directive', function () {
99-
it('anonymous ui-view should be replaced with the template of the current $state', inject(function ($state, $q) {
103+
it('anonymous ui-view should be replaced with the template of the current $state', inject(function ($state, $q, $animate) {
100104
elem.append($compile('<div ui-view></div>')(scope));
101105

102106
$state.transitionTo(aState);
103107
$q.flush();
104108

105-
expect(elem.text()).toBe(aState.template);
109+
expect($animate.flushNext('leave').element.text()).toBe('');
110+
expect($animate.flushNext('enter').element.text()).toBe(aState.template);
106111
}));
107112

108-
it('named ui-view should be replaced with the template of the current $state', inject(function ($state, $q) {
113+
it('named ui-view should be replaced with the template of the current $state', inject(function ($state, $q, $animate) {
109114
elem.append($compile('<div ui-view="cview"></div>')(scope));
110115

111116
$state.transitionTo(cState);
112117
$q.flush();
113118

114-
expect(elem.text()).toBe(cState.views.cview.template);
119+
expect($animate.flushNext('leave').element.text()).toBe('');
120+
expect($animate.flushNext('enter').element.text()).toBe(cState.views.cview.template);
115121
}));
116122

117-
it('ui-view should be updated after transition to another state', inject(function ($state, $q) {
123+
it('ui-view should be updated after transition to another state', inject(function ($state, $q, $animate) {
118124
elem.append($compile('<div ui-view></div>')(scope));
119125

120126
$state.transitionTo(aState);
121127
$q.flush();
122128

123-
expect(elem.text()).toBe(aState.template);
129+
expect($animate.flushNext('leave').element.text()).toBe('');
130+
expect($animate.flushNext('enter').element.text()).toBe(aState.template);
124131

125132
$state.transitionTo(bState);
126133
$q.flush();
127134

128-
expect(elem.text()).toBe(bState.template);
135+
expect($animate.flushNext('leave').element.text()).toBe(aState.template);
136+
expect($animate.flushNext('enter').element.text()).toBe(bState.template);
129137
}));
130138

131-
it('should handle NOT nested ui-views', inject(function ($state, $q) {
139+
it('should handle NOT nested ui-views', inject(function ($state, $q, $animate) {
132140
elem.append($compile('<div ui-view="dview1" class="dview1"></div><div ui-view="dview2" class="dview2"></div>')(scope));
133141

134142
$state.transitionTo(dState);
135143
$q.flush();
136144

137-
expect(innerText(elem[0].querySelector('.dview1'))).toBe(dState.views.dview1.template);
138-
expect(innerText(elem[0].querySelector('.dview2'))).toBe(dState.views.dview2.template);
145+
// expect(innerText(elem[0].querySelector('.dview1'))).toBe(dState.views.dview1.template);
146+
// expect(innerText(elem[0].querySelector('.dview2'))).toBe(dState.views.dview2.template);
147+
148+
expect($animate.flushNext('leave').element.html()).toBeUndefined();
149+
expect($animate.flushNext('enter').element.html()).toBe(dState.views.dview1.template);
150+
expect($animate.flushNext('leave').element.html()).toBeUndefined();
151+
expect($animate.flushNext('enter').element.html()).toBe(dState.views.dview2.template);
139152
}));
140153

141-
it('should handle nested ui-views (testing two levels deep)', inject(function ($state, $q) {
154+
it('should handle nested ui-views (testing two levels deep)', inject(function ($state, $q, $animate) {
142155
elem.append($compile('<div ui-view class="view"></div>')(scope));
143156

144157
$state.transitionTo(fState);
145158
$q.flush();
146159

147-
expect(innerText(elem[0].querySelector('.view').querySelector('.eview'))).toBe(fState.views.eview.template);
160+
// expect(innerText(elem[0].querySelector('.view').querySelector('.eview'))).toBe(fState.views.eview.template);
161+
162+
expect($animate.flushNext('leave').element.text()).toBe('');
163+
expect($animate.flushNext('enter').element.parent().parent()[0].querySelector('.view').querySelector('.eview').innerText).toBe(fState.views.eview.template);
148164
}));
149165
});
150166

151167
describe('handling initial view', function () {
152-
it('initial view should be compiled if the view is empty', inject(function ($state, $q) {
168+
it('initial view should be compiled if the view is empty', inject(function ($state, $q, $animate) {
153169
var content = 'inner content';
154170

155171
elem.append($compile('<div ui-view></div>')(scope));
@@ -158,10 +174,16 @@ describe('uiView', function () {
158174
$state.transitionTo(gState);
159175
$q.flush();
160176

161-
expect(innerText(elem[0].querySelector('.test'))).toBe(content);
177+
// expect(innerText(elem[0].querySelector('.test'))).toBe(content);
178+
179+
expect($animate.flushNext('leave').element.text()).toBe("");
180+
expect($animate.flushNext('enter').element.text()).toBe(content);
181+
182+
// For some reason the ng-class expression is no longer evaluated
183+
expect($animate.flushNext('addClass').element.parent()[0].querySelector('.test').innerText).toBe(content);
162184
}));
163185

164-
it('initial view should be put back after removal of the view', inject(function ($state, $q) {
186+
it('initial view should be put back after removal of the view', inject(function ($state, $q, $animate) {
165187
var content = 'inner content';
166188

167189
elem.append($compile('<div ui-view></div>')(scope));
@@ -170,13 +192,20 @@ describe('uiView', function () {
170192
$state.transitionTo(hState);
171193
$q.flush();
172194

173-
expect(elem.text()).toBe(hState.views.inner.template);
195+
expect($animate.flushNext('leave').element.text()).toBe('');
196+
expect($animate.flushNext('enter').element.text()).toBe(hState.views.inner.template);
197+
198+
expect($animate.flushNext('addClass').element.text()).toBe(hState.views.inner.template);
199+
expect($animate.flushNext('addClass').element.text()).toBe(hState.views.inner.template);
174200

175201
// going to the parent state which makes the inner view empty
176202
$state.transitionTo(gState);
177203
$q.flush();
178204

179-
expect(innerText(elem[0].querySelector('.test'))).toBe(content);
205+
// expect(innerText(elem[0].querySelector('.test'))).toBe(content);
206+
207+
expect($animate.flushNext('leave').element.text()).toBe(hState.views.inner.template);
208+
expect($animate.flushNext('enter').element.text()).toBe(content);
180209
}));
181210

182211
// related to issue #435

0 commit comments

Comments
 (0)