Skip to content

Commit 9bfffb6

Browse files
author
Cody Lundquist
committed
fix(uiView): Refactoring uiView directive to copy ngView logic
- Changed the structure of the uiView directive to work more like ngView. - Updated tests to work with new structure. - Fixes the issue with using ngIf in conjunction with uiView. - Added in extensive test for ngIf fix. Closes angular-ui#857
1 parent d9f7b89 commit 9bfffb6

File tree

2 files changed

+166
-110
lines changed

2 files changed

+166
-110
lines changed

src/viewDirective.js

+88-86
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@
115115
* <ui-view autoscroll='scopeVariable'/>
116116
* </pre>
117117
*/
118-
$ViewDirective.$inject = ['$state', '$compile', '$controller', '$injector', '$uiViewScroll', '$document'];
119-
function $ViewDirective( $state, $compile, $controller, $injector, $uiViewScroll, $document) {
118+
$ViewDirective.$inject = ['$state', '$injector', '$uiViewScroll'];
119+
function $ViewDirective( $state, $injector, $uiViewScroll) {
120120

121121
function getService() {
122122
return ($injector.has) ? function(service) {
@@ -135,135 +135,98 @@ function $ViewDirective( $state, $compile, $controller, $injector, $ui
135135
$animator = service('$animator'),
136136
$animate = service('$animate');
137137

138-
// Returns a set of DOM manipulation functions based on whether animation
139-
// should be performed
140-
function getRenderer(element, attrs, scope) {
138+
// Returns a set of DOM manipulation functions based on which Angular version
139+
// it should use
140+
function getRenderer(attrs, scope) {
141141
var statics = function() {
142142
return {
143-
leave: function (element) { element.remove(); },
144-
enter: function (element, parent, anchor) { anchor.after(element); }
143+
enter: function (element, target) { target.after(element); },
144+
leave: function (element) { element.remove(); }
145145
};
146146
};
147147

148148
if ($animate) {
149-
return function(shouldAnimate) {
150-
return !shouldAnimate ? statics() : {
151-
enter: function(element, parent, anchor) { $animate.enter(element, null, anchor); },
152-
leave: function(element) { $animate.leave(element, function() { element.remove(); }); }
153-
};
149+
return {
150+
enter: function(element, target) { $animate.enter(element, null, target); },
151+
leave: function(element) { $animate.leave(element); }
154152
};
155153
}
156154

157155
if ($animator) {
158156
var animate = $animator && $animator(scope, attrs);
159157

160-
return function(shouldAnimate) {
161-
return !shouldAnimate ? statics() : {
162-
enter: function(element, parent, anchor) { animate.enter(element, parent); },
163-
leave: function(element) { animate.leave(element.contents(), element); }
164-
};
158+
return {
159+
enter: function(element, target) { animate.enter(element, null, target); },
160+
leave: function(element) { animate.leave(element.contents(), element); }
165161
};
166162
}
167163

168-
return statics;
164+
return statics();
169165
}
170166

171167
var directive = {
172168
restrict: 'ECA',
173-
compile: function (element, attrs) {
174-
var initial = element.html(),
175-
isDefault = true,
176-
anchor = angular.element($document[0].createComment(' ui-view-anchor ')),
177-
parentEl = element.parent();
178-
179-
element.prepend(anchor);
180-
181-
return function ($scope) {
182-
var inherited = parentEl.inheritedData('$uiView');
183-
169+
terminal: true,
170+
priority: 400,
171+
transclude: 'element',
172+
compile: function (tElement, tAttrs, $transclude) {
173+
return function (scope, $element, attrs) {
184174
var currentScope, currentEl, viewLocals,
185-
name = attrs[directive.name] || attrs.name || '',
186-
onloadExp = attrs.onload || '',
175+
loaded = false,
176+
onloadExp = attrs.onload || '',
187177
autoscrollExp = attrs.autoscroll,
188-
renderer = getRenderer(element, attrs, $scope);
178+
renderer = getRenderer(attrs, scope),
179+
parentEl = $element.parent(),
180+
inherited = parentEl.inheritedData('$uiView'),
181+
name = attrs[directive.name] || attrs.name || '';
189182

190183
if (name.indexOf('@') < 0) name = name + '@' + (inherited ? inherited.state.name : '');
191-
var view = { name: name, state: null };
192184

193185
var eventHook = function () {
194186
if (viewIsUpdating) return;
187+
195188
viewIsUpdating = true;
196189

197-
try { updateView(true); } catch (e) {
198-
viewIsUpdating = false;
190+
try { updateView(); } catch (e) {
199191
throw e;
192+
} finally {
193+
viewIsUpdating = false;
200194
}
201-
viewIsUpdating = false;
202195
};
203196

204-
$scope.$on('$stateChangeSuccess', eventHook);
205-
$scope.$on('$viewContentLoading', eventHook);
206-
207-
updateView(false);
197+
scope.$on('$stateChangeSuccess', eventHook);
198+
scope.$on('$viewContentLoading', eventHook);
199+
updateView();
208200

209201
function cleanupLastView() {
210-
if (currentEl) {
211-
renderer(true).leave(currentEl);
212-
currentEl = null;
213-
}
214-
215202
if (currentScope) {
216203
currentScope.$destroy();
217204
currentScope = null;
218205
}
219-
}
220-
221-
function updateView(shouldAnimate) {
222-
var locals = $state.$current && $state.$current.locals[name];
223206

224-
if (isDefault) {
225-
isDefault = false;
226-
element.replaceWith(anchor);
227-
}
228-
229-
if (!locals) {
230-
cleanupLastView();
231-
currentEl = element.clone();
232-
currentEl.html(initial);
233-
renderer(shouldAnimate).enter(currentEl, parentEl, anchor);
234-
235-
currentScope = $scope.$new();
236-
$compile(currentEl.contents())(currentScope);
237-
return;
207+
if (currentEl) {
208+
renderer.leave(currentEl);
209+
currentEl = null;
238210
}
211+
}
239212

240-
if (locals === viewLocals) return; // nothing to do
241-
242-
cleanupLastView();
243-
244-
currentEl = element.clone();
245-
currentEl.html(locals.$template ? locals.$template : initial);
246-
renderer(true).enter(currentEl, parentEl, anchor);
213+
function updateView() {
214+
var newScope = scope.$new(),
215+
locals = $state.$current && $state.$current.locals[name];
247216

248-
currentEl.data('$uiView', view);
217+
if (loaded && locals === viewLocals) return; // nothing to do
249218

219+
loaded = true;
250220
viewLocals = locals;
251-
view.state = locals.$$state;
252221

253-
var link = $compile(currentEl.contents());
254-
255-
currentScope = $scope.$new();
256-
257-
if (locals.$$controller) {
258-
locals.$scope = currentScope;
259-
var controller = $controller(locals.$$controller, locals);
260-
if ($state.$current.controllerAs) {
261-
currentScope[$state.$current.controllerAs] = controller;
262-
}
263-
currentEl.children().data('$ngControllerController', controller);
264-
}
222+
var clone = $transclude(newScope, function(clone) {
223+
clone.data('$uiViewName', name);
224+
renderer.enter(clone, currentEl || $element);
225+
cleanupLastView();
226+
});
265227

266-
link(currentScope);
228+
currentEl = clone;
229+
currentScope = newScope;
267230

268231
/**
269232
* @ngdoc event
@@ -278,7 +241,7 @@ function $ViewDirective( $state, $compile, $controller, $injector, $ui
278241
currentScope.$emit('$viewContentLoaded');
279242
if (onloadExp) currentScope.$eval(onloadExp);
280243

281-
if (!angular.isDefined(autoscrollExp) || !autoscrollExp || $scope.$eval(autoscrollExp)) {
244+
if (!angular.isDefined(autoscrollExp) || !autoscrollExp || scope.$eval(autoscrollExp)) {
282245
$uiViewScroll(currentEl);
283246
}
284247
}
@@ -289,4 +252,43 @@ function $ViewDirective( $state, $compile, $controller, $injector, $ui
289252
return directive;
290253
}
291254

255+
$ViewDirectiveFill.$inject = ['$compile', '$controller', '$state'];
256+
function $ViewDirectiveFill ($compile, $controller, $state) {
257+
return {
258+
restrict: 'ECA',
259+
priority: -400,
260+
compile: function (tElement) {
261+
var initial = tElement.html();
262+
263+
return function (scope, $element) {
264+
var current = $state.$current,
265+
name = $element.data('$uiViewName'),
266+
locals = current && current.locals[name];
267+
268+
if (!locals) {
269+
return;
270+
}
271+
272+
$element.data('$uiView', { name: name, state: locals.$$state });
273+
$element.html(locals.$template ? locals.$template : initial);
274+
275+
var link = $compile($element.contents());
276+
277+
if (locals.$$controller) {
278+
locals.$scope = scope;
279+
var controller = $controller(locals.$$controller, locals);
280+
if (current.controllerAs) {
281+
scope[current.controllerAs] = controller;
282+
}
283+
$element.data('$ngControllerController', controller);
284+
$element.children().data('$ngControllerController', controller);
285+
}
286+
287+
link(scope);
288+
};
289+
}
290+
};
291+
}
292+
292293
angular.module('ui.router.state').directive('uiView', $ViewDirective);
294+
angular.module('ui.router.state').directive('uiView', $ViewDirectiveFill);

0 commit comments

Comments
 (0)