@angular-wave/angular.ts 0.0.22 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/angular-ts.esm.js +1 -1
- package/dist/angular-ts.umd.js +1 -1
- package/index.html +6 -2
- package/package.json +1 -1
- package/src/core/compile.js +2 -3
- package/src/core/parser/parse.js +2 -3
- package/src/filters/order-by.js +8 -8
- package/src/router/directives/{stateDirectives.js → state-directives.js} +1 -2
- package/src/router/directives/{viewDirective.js → view-directive.js} +4 -12
- package/src/router/globals.js +1 -1
- package/src/router/hooks/{ignoredTransition.js → ignored-transition.js} +1 -1
- package/src/router/hooks/{redirectTo.js → redirect-to.js} +1 -1
- package/src/router/hooks/resolve.js +1 -1
- package/src/router/index.js +6 -8
- package/src/router/params/{paramTypes.js → param-types.js} +3 -4
- package/src/router/params/param.js +1 -1
- package/src/router/path/{pathUtils.js → path-utils.js} +2 -2
- package/src/router/resolve/resolvable.js +2 -2
- package/src/router/resolve/{resolveContext.js → resolve-context.js} +1 -1
- package/src/router/router.js +8 -8
- package/src/router/services.js +3 -3
- package/src/router/state/{stateBuilder.js → state-builder.js} +2 -3
- package/src/router/state/{stateQueueManager.js → state-queue-manager.js} +2 -1
- package/src/router/state/{stateRegistry.js → state-registry.js} +3 -3
- package/src/router/state/{stateService.js → state-service.js} +7 -7
- package/src/router/state/views.js +1 -1
- package/src/router/{stateProvider.js → state-provider.js} +8 -0
- package/src/router/{templateFactory.js → template-factory.js} +93 -51
- package/src/router/transition/{hookBuilder.js → hook-builder.js} +3 -3
- package/src/router/transition/{transitionEventType.js → transition-event-type.js} +1 -1
- package/src/router/transition/{transitionHook.js → transition-hook.js} +2 -2
- package/src/router/transition/{transitionService.js → transition-service.js} +10 -10
- package/src/router/transition/transition.js +12 -9
- package/src/router/url/{urlConfig.js → url-config.js} +1 -1
- package/src/router/url/{urlMatcherFactory.js → url-matcher-factory.js} +1 -1
- package/src/router/url/{urlMatcher.js → url-matcher.js} +0 -2
- package/src/router/url/{urlRouter.js → url-router.js} +1 -1
- package/src/router/url/{urlRule.js → url-rule.js} +13 -5
- package/src/router/url/{urlRules.js → url-rules.js} +3 -3
- package/src/router/url/{urlService.js → url-service.js} +6 -6
- package/src/services/browser.js +3 -18
- package/src/shared/strings.js +2 -2
- package/test/router/ng-state-builder.spec.js +81 -0
- package/test/router/services.spec.js +0 -1
- package/test/router/state-directives.spec.js +867 -893
- package/test/router/template-factory.spec.js +146 -0
- package/test/router/url-matcher-factory.spec.js +1313 -0
- package/test/router/view-directive.spec.js +2013 -0
- package/test/router/view-hook.spec.js +217 -0
- package/test/router/view-scroll.spec.js +77 -0
- package/test/router/view.spec.js +117 -0
- package/test/test-utils.js +9 -0
- package/types/router/legacy/resolveService.d.ts +1 -1
- package/types/router/statebuilders/onEnterExitRetain.d.ts +1 -1
- package/types/router/statebuilders/views.d.ts +1 -2
- /package/src/router/hooks/{coreResolvables.js → core-resolvables.js} +0 -0
- /package/src/router/hooks/{invalidTransition.js → invalid-transition.js} +0 -0
- /package/src/router/hooks/{lazyLoad.js → lazy-load.js} +0 -0
- /package/src/router/hooks/{onEnterExitRetain.js → on-enter-exit-retain.js} +0 -0
- /package/src/router/hooks/{updateGlobals.js → update-globals.js} +0 -0
- /package/src/router/{locationServices.js → location-services.js} +0 -0
- /package/src/router/params/{paramType.js → param-type.js} +0 -0
- /package/src/router/params/{stateParams.js → state-params.js} +0 -0
- /package/src/router/path/{pathNode.js → path-node.js} +0 -0
- /package/src/router/state/{stateMatcher.js → state-matcher.js} +0 -0
- /package/src/router/state/{stateObject.js → state-object.js} +0 -0
- /package/src/router/state/{targetState.js → target-state.js} +0 -0
- /package/src/router/{stateFilters.js → state-filters.js} +0 -0
- /package/src/router/transition/{hookRegistry.js → hook-registry.js} +0 -0
- /package/src/router/transition/{rejectFactory.js → reject-factory.js} +0 -0
- /package/src/router/{viewScroll.js → view-scroll.js} +0 -0
|
@@ -0,0 +1,2013 @@
|
|
|
1
|
+
// function animateFlush($animate) {
|
|
2
|
+
// if ($animate && $animate.flush) {
|
|
3
|
+
// $animate.flush(); // 1.4
|
|
4
|
+
// } else if ($animate && $animate.triggerCallbacks) {
|
|
5
|
+
// $animate.triggerCallbacks(); // 1.2-1.3
|
|
6
|
+
// }
|
|
7
|
+
// }
|
|
8
|
+
|
|
9
|
+
import { dealoc, jqLite } from "../../src/jqLite";
|
|
10
|
+
import { Angular } from "../../src/loader";
|
|
11
|
+
import { publishExternalAPI } from "../../src/public";
|
|
12
|
+
import { wait } from "../test-utils";
|
|
13
|
+
|
|
14
|
+
describe("uiView", () => {
|
|
15
|
+
let $stateProvider,
|
|
16
|
+
scope,
|
|
17
|
+
$compile,
|
|
18
|
+
elem,
|
|
19
|
+
log,
|
|
20
|
+
app,
|
|
21
|
+
$injector,
|
|
22
|
+
$state,
|
|
23
|
+
$q,
|
|
24
|
+
$timeout,
|
|
25
|
+
$uiViewScroll;
|
|
26
|
+
|
|
27
|
+
const aState = {
|
|
28
|
+
name: "a",
|
|
29
|
+
template: "aState template",
|
|
30
|
+
},
|
|
31
|
+
bState = {
|
|
32
|
+
name: "b",
|
|
33
|
+
template: "bState template",
|
|
34
|
+
},
|
|
35
|
+
cState = {
|
|
36
|
+
name: "c",
|
|
37
|
+
views: {
|
|
38
|
+
cview: {
|
|
39
|
+
template: "cState cview template",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
dState = {
|
|
44
|
+
name: "d",
|
|
45
|
+
views: {
|
|
46
|
+
dview1: {
|
|
47
|
+
template: "dState dview1 template",
|
|
48
|
+
},
|
|
49
|
+
dview2: {
|
|
50
|
+
template: "dState dview2 template",
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
eState = {
|
|
55
|
+
name: "e",
|
|
56
|
+
template: '<div ui-view="eview" class="eview"></div>',
|
|
57
|
+
},
|
|
58
|
+
fState = {
|
|
59
|
+
name: "e.f",
|
|
60
|
+
views: {
|
|
61
|
+
eview: {
|
|
62
|
+
template: "fState eview template",
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
gState = {
|
|
67
|
+
name: "g",
|
|
68
|
+
template: '<div ui-view="inner"><span>{{content}}</span></div>',
|
|
69
|
+
},
|
|
70
|
+
hState = {
|
|
71
|
+
name: "g.h",
|
|
72
|
+
views: {
|
|
73
|
+
inner: {
|
|
74
|
+
template: "hState inner template",
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
iState = {
|
|
79
|
+
name: "i",
|
|
80
|
+
template:
|
|
81
|
+
"<div ui-view>" +
|
|
82
|
+
'<ul><li ng-repeat="item in items">{{item}}</li></ul>' +
|
|
83
|
+
"</div>",
|
|
84
|
+
},
|
|
85
|
+
jState = {
|
|
86
|
+
name: "j",
|
|
87
|
+
template: "jState",
|
|
88
|
+
},
|
|
89
|
+
kState = {
|
|
90
|
+
name: "k",
|
|
91
|
+
controller: function () {
|
|
92
|
+
this.someProperty = "value";
|
|
93
|
+
},
|
|
94
|
+
template: "{{vm.someProperty}}",
|
|
95
|
+
controllerAs: "vm",
|
|
96
|
+
},
|
|
97
|
+
lState = {
|
|
98
|
+
name: "l",
|
|
99
|
+
views: {
|
|
100
|
+
view1: {
|
|
101
|
+
template: "view1",
|
|
102
|
+
},
|
|
103
|
+
view2: {
|
|
104
|
+
template: "view2",
|
|
105
|
+
},
|
|
106
|
+
view3: {
|
|
107
|
+
template: "view3",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
mState = {
|
|
112
|
+
name: "m",
|
|
113
|
+
template: "mState",
|
|
114
|
+
controller: function ($scope, $element) {
|
|
115
|
+
$scope.elementId = $element.attr("id");
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
nState = {
|
|
119
|
+
name: "n",
|
|
120
|
+
template: "nState",
|
|
121
|
+
controller: function ($scope, $element) {
|
|
122
|
+
const data = $element.data("$uiViewAnim");
|
|
123
|
+
$scope.$on("$destroy", () => {
|
|
124
|
+
log += "destroy;";
|
|
125
|
+
});
|
|
126
|
+
data.$animEnter.then(() => {
|
|
127
|
+
log += "animEnter;";
|
|
128
|
+
});
|
|
129
|
+
data.$animLeave.then(() => {
|
|
130
|
+
log += "animLeave;";
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
beforeEach(() => {
|
|
136
|
+
dealoc(document.getElementById("dummy"));
|
|
137
|
+
window.angular = new Angular();
|
|
138
|
+
publishExternalAPI();
|
|
139
|
+
log = "";
|
|
140
|
+
app = window.angular
|
|
141
|
+
.module("defaultModule", ["ui.router"])
|
|
142
|
+
.config(($provide, _$stateProvider_) => {
|
|
143
|
+
$provide.decorator("$uiViewScroll", () => {
|
|
144
|
+
return jasmine.createSpy("$uiViewScroll");
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
_$stateProvider_
|
|
148
|
+
.state(aState)
|
|
149
|
+
.state(bState)
|
|
150
|
+
.state(cState)
|
|
151
|
+
.state(dState)
|
|
152
|
+
.state(eState)
|
|
153
|
+
.state(fState)
|
|
154
|
+
.state(gState)
|
|
155
|
+
.state(hState)
|
|
156
|
+
.state(iState)
|
|
157
|
+
.state(jState)
|
|
158
|
+
.state(kState)
|
|
159
|
+
.state(lState)
|
|
160
|
+
.state(mState)
|
|
161
|
+
.state(nState);
|
|
162
|
+
|
|
163
|
+
$stateProvider = _$stateProvider_;
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
$injector = window.angular.bootstrap(document.getElementById("dummy"), [
|
|
167
|
+
"defaultModule",
|
|
168
|
+
]);
|
|
169
|
+
|
|
170
|
+
$injector.invoke(
|
|
171
|
+
(_$state_, _$q_, _$timeout_, $rootScope, _$compile_, _$uiViewScroll_) => {
|
|
172
|
+
scope = $rootScope.$new();
|
|
173
|
+
$compile = _$compile_;
|
|
174
|
+
$state = _$state_;
|
|
175
|
+
$q = _$q_;
|
|
176
|
+
$timeout = _$timeout_;
|
|
177
|
+
elem = jqLite("<div>");
|
|
178
|
+
$uiViewScroll = _$uiViewScroll_;
|
|
179
|
+
},
|
|
180
|
+
);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe("linking ui-directive", () => {
|
|
184
|
+
it("anonymous ui-view should be replaced with the template of the current $state", async () => {
|
|
185
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
186
|
+
|
|
187
|
+
expect(elem.find("ui-view").text()).toBe("");
|
|
188
|
+
|
|
189
|
+
$state.transitionTo(aState);
|
|
190
|
+
await wait(10);
|
|
191
|
+
|
|
192
|
+
expect(elem.find("ui-view").text()).toBe(aState.template);
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("named ui-view should be replaced with the template of the current $state", async () => {
|
|
196
|
+
elem.append(
|
|
197
|
+
$compile('<div><ui-view name="cview"></ui-view></div>')(scope),
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
$state.transitionTo(cState);
|
|
201
|
+
await wait(10);
|
|
202
|
+
|
|
203
|
+
expect(elem.find("ui-view").text()).toBe(cState.views.cview.template);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
it("ui-view should be updated after transition to another state", async () => {
|
|
207
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
208
|
+
expect(elem.find("ui-view").text()).toBe("");
|
|
209
|
+
|
|
210
|
+
$state.transitionTo(aState);
|
|
211
|
+
await wait(10);
|
|
212
|
+
|
|
213
|
+
expect(elem.find("ui-view").text()).toBe(aState.template);
|
|
214
|
+
|
|
215
|
+
$state.transitionTo(bState);
|
|
216
|
+
await wait(10);
|
|
217
|
+
|
|
218
|
+
expect(elem.find("ui-view").text()).toBe(bState.template);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it("should handle NOT nested ui-views", async () => {
|
|
222
|
+
elem.append(
|
|
223
|
+
$compile(
|
|
224
|
+
'<div><ui-view name="dview1" class="dview1"></ui-view><ui-view name="dview2" class="dview2"></ui-view></div>',
|
|
225
|
+
)(scope),
|
|
226
|
+
);
|
|
227
|
+
expect(elem.find("ui-view").eq(0).text()).toBe("");
|
|
228
|
+
expect(elem.find("ui-view").eq(1).text()).toBe("");
|
|
229
|
+
|
|
230
|
+
$state.transitionTo(dState);
|
|
231
|
+
await wait(10);
|
|
232
|
+
|
|
233
|
+
expect(elem.find("ui-view").eq(0).text()).toBe(
|
|
234
|
+
dState.views.dview1.template,
|
|
235
|
+
);
|
|
236
|
+
expect(elem.find("ui-view").eq(1).text()).toBe(
|
|
237
|
+
dState.views.dview2.template,
|
|
238
|
+
);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("should handle nested ui-views (testing two levels deep)", async () => {
|
|
242
|
+
$compile(elem.append("<div><ui-view></ui-view></div>"))(scope);
|
|
243
|
+
expect(elem.find("ui-view").text()).toBe("");
|
|
244
|
+
|
|
245
|
+
$state.transitionTo(fState);
|
|
246
|
+
await wait(10);
|
|
247
|
+
|
|
248
|
+
expect(elem.find("ui-view").text()).toBe(fState.views.eview.template);
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe("handling initial view", () => {
|
|
253
|
+
it("initial view should be compiled if the view is empty", async () => {
|
|
254
|
+
const content = "inner content";
|
|
255
|
+
scope.content = content;
|
|
256
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
257
|
+
|
|
258
|
+
$state.transitionTo(gState);
|
|
259
|
+
await wait(10);
|
|
260
|
+
|
|
261
|
+
expect(elem.find("ui-view").text()).toBe(content);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it("initial view should be put back after removal of the view", async () => {
|
|
265
|
+
const content = "inner content";
|
|
266
|
+
scope.content = content;
|
|
267
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
268
|
+
|
|
269
|
+
$state.go(hState);
|
|
270
|
+
await wait(10);
|
|
271
|
+
|
|
272
|
+
expect(elem.find("ui-view").text()).toBe(hState.views.inner.template);
|
|
273
|
+
|
|
274
|
+
// going to the parent state which makes the inner view empty
|
|
275
|
+
$state.go(gState);
|
|
276
|
+
await wait(10);
|
|
277
|
+
|
|
278
|
+
expect(elem.find("ui-view").text()).toBe(content);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
// related to issue #435
|
|
282
|
+
it("initial view should be transcluded once to prevent breaking other directives", async () => {
|
|
283
|
+
scope.items = ["I", "am", "a", "list", "of", "items"];
|
|
284
|
+
|
|
285
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
286
|
+
|
|
287
|
+
// transition to state that has an initial view
|
|
288
|
+
$state.transitionTo(iState);
|
|
289
|
+
await wait(10);
|
|
290
|
+
|
|
291
|
+
// verify if ng-repeat has been compiled
|
|
292
|
+
expect(elem.find("li").length).toBe(scope.items.length);
|
|
293
|
+
|
|
294
|
+
// transition to another state that replace the initial content
|
|
295
|
+
$state.transitionTo(jState);
|
|
296
|
+
await wait(10);
|
|
297
|
+
|
|
298
|
+
expect(elem.find("ui-view").text()).toBe(jState.template);
|
|
299
|
+
|
|
300
|
+
// transition back to the state with empty subview and the initial view
|
|
301
|
+
$state.transitionTo(iState);
|
|
302
|
+
await wait(10);
|
|
303
|
+
|
|
304
|
+
// verify if the initial view is correct
|
|
305
|
+
expect(elem.find("li").length).toBe(scope.items.length);
|
|
306
|
+
|
|
307
|
+
// change scope properties
|
|
308
|
+
scope.$apply(() => {
|
|
309
|
+
scope.items.push(".", "Working?");
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// verify if the initial view has been updated
|
|
313
|
+
expect(elem.find("li").length).toBe(scope.items.length);
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
describe("autoscroll attribute", () => {
|
|
318
|
+
it("should NOT autoscroll when unspecified", async () => {
|
|
319
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
320
|
+
|
|
321
|
+
$state.transitionTo(aState);
|
|
322
|
+
await wait(10);
|
|
323
|
+
expect($uiViewScroll).not.toHaveBeenCalled();
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it("should autoscroll when expression is missing", async () => {
|
|
327
|
+
elem.append($compile("<div><ui-view autoscroll></ui-view></div>")(scope));
|
|
328
|
+
await $state.transitionTo(aState);
|
|
329
|
+
await wait(20);
|
|
330
|
+
|
|
331
|
+
// animateFlush($animate);
|
|
332
|
+
|
|
333
|
+
expect($uiViewScroll).toHaveBeenCalledWith(elem.find("ui-view"));
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it("should autoscroll based on expression", async () => {
|
|
337
|
+
scope.doScroll = false;
|
|
338
|
+
|
|
339
|
+
elem.append(
|
|
340
|
+
$compile('<div><ui-view autoscroll="doScroll"></ui-view></div>')(scope),
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
$state.transitionTo(aState);
|
|
344
|
+
await wait(10);
|
|
345
|
+
|
|
346
|
+
expect($uiViewScroll).not.toHaveBeenCalled();
|
|
347
|
+
|
|
348
|
+
scope.doScroll = true;
|
|
349
|
+
$state.transitionTo(bState);
|
|
350
|
+
await wait(100);
|
|
351
|
+
|
|
352
|
+
let target,
|
|
353
|
+
index = -1,
|
|
354
|
+
uiViews = elem.find("ui-view");
|
|
355
|
+
|
|
356
|
+
while (index++ < uiViews.length) {
|
|
357
|
+
const uiView = jqLite(uiViews[index]);
|
|
358
|
+
if (uiView.text() === bState.template) target = uiView;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
expect($uiViewScroll).toHaveBeenCalledWith(target);
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
it("should instantiate a controller with controllerAs", async () => {
|
|
366
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
367
|
+
await $state.transitionTo(kState);
|
|
368
|
+
expect(elem.text()).toBe("value");
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it("should instantiate a controller with both $scope and $element injections", async () => {
|
|
372
|
+
elem.append(
|
|
373
|
+
$compile('<div><ui-view id="mState">{{elementId}}</ui-view></div>')(
|
|
374
|
+
scope,
|
|
375
|
+
),
|
|
376
|
+
);
|
|
377
|
+
$state.transitionTo(mState);
|
|
378
|
+
await wait(10);
|
|
379
|
+
|
|
380
|
+
expect(elem.text()).toBe("mState");
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
describe("(resolved data)", () => {
|
|
384
|
+
let _scope;
|
|
385
|
+
function controller($scope) {
|
|
386
|
+
_scope = $scope;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
let _state = {
|
|
390
|
+
name: "resolve",
|
|
391
|
+
resolve: {
|
|
392
|
+
user: function () {
|
|
393
|
+
return $timeout(() => {
|
|
394
|
+
return "joeschmoe";
|
|
395
|
+
}, 100);
|
|
396
|
+
},
|
|
397
|
+
},
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
it("should put the resolved data on the controllerAs", async () => {
|
|
401
|
+
const state = Object.assign(_state, {
|
|
402
|
+
template: "{{$ctrl.$resolve.user}}",
|
|
403
|
+
controllerAs: "$ctrl",
|
|
404
|
+
controller: function ($scope) {
|
|
405
|
+
_scope = $scope;
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
$stateProvider.state(state);
|
|
409
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
410
|
+
|
|
411
|
+
await $state.transitionTo("resolve");
|
|
412
|
+
await wait(100);
|
|
413
|
+
|
|
414
|
+
expect(elem.text()).toBe("joeschmoe");
|
|
415
|
+
expect(_scope.$resolve).toBeDefined();
|
|
416
|
+
expect(_scope.$ctrl).toBeDefined();
|
|
417
|
+
expect(_scope.$ctrl.$resolve).toBeDefined();
|
|
418
|
+
expect(_scope.$ctrl.$resolve.user).toBe("joeschmoe");
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it("should provide the resolved data on the $scope", async () => {
|
|
422
|
+
const state = Object.assign(_state, {
|
|
423
|
+
template: "{{$resolve.user}}",
|
|
424
|
+
controller: controller,
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
$stateProvider.state(state);
|
|
428
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
429
|
+
|
|
430
|
+
await $state.transitionTo("resolve");
|
|
431
|
+
await wait(10);
|
|
432
|
+
|
|
433
|
+
expect(elem.text()).toBe("joeschmoe");
|
|
434
|
+
expect(_scope.$resolve).toBeDefined();
|
|
435
|
+
expect(_scope.$resolve.user).toBe("joeschmoe");
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
// Test for #2626
|
|
439
|
+
it("should provide the resolved data on the $scope even if there is no controller", async () => {
|
|
440
|
+
const state = Object.assign(_state, {
|
|
441
|
+
template: "{{$resolve.user}}",
|
|
442
|
+
});
|
|
443
|
+
$stateProvider.state(state);
|
|
444
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
445
|
+
expect(elem.text()).toBe("");
|
|
446
|
+
|
|
447
|
+
await $state.transitionTo("resolve");
|
|
448
|
+
await wait(10);
|
|
449
|
+
|
|
450
|
+
expect(elem.text()).toBe("joeschmoe");
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it("should put the resolved data on the resolveAs variable", async () => {
|
|
454
|
+
const state = Object.assign(_state, {
|
|
455
|
+
template: "{{$$$resolve.user}}",
|
|
456
|
+
resolveAs: "$$$resolve",
|
|
457
|
+
controller: controller,
|
|
458
|
+
});
|
|
459
|
+
$stateProvider.state(state);
|
|
460
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
461
|
+
|
|
462
|
+
await $state.transitionTo("resolve");
|
|
463
|
+
await wait(10);
|
|
464
|
+
|
|
465
|
+
expect(elem.text()).toBe("joeschmoe");
|
|
466
|
+
expect(_scope.$$$resolve).toBeDefined();
|
|
467
|
+
expect(_scope.$$$resolve.user).toBe("joeschmoe");
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it("should not allow both view-level resolveAs and state-level resolveAs on the same state", async () => {
|
|
471
|
+
const views = {
|
|
472
|
+
$default: {
|
|
473
|
+
controller: controller,
|
|
474
|
+
template: "{{$$$resolve.user}}",
|
|
475
|
+
resolveAs: "$$$resolve",
|
|
476
|
+
},
|
|
477
|
+
};
|
|
478
|
+
const state = Object.assign(_state, {
|
|
479
|
+
resolveAs: "foo",
|
|
480
|
+
views: views,
|
|
481
|
+
});
|
|
482
|
+
expect(() => $stateProvider.state(state)).toThrowError(/resolveAs/);
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
it("should call the existing $onInit after instantiating a controller", async () => {
|
|
487
|
+
const $onInit = jasmine.createSpy();
|
|
488
|
+
$stateProvider.state({
|
|
489
|
+
name: "onInit",
|
|
490
|
+
controller: function () {
|
|
491
|
+
this.$onInit = $onInit;
|
|
492
|
+
},
|
|
493
|
+
template: "hi",
|
|
494
|
+
controllerAs: "vm",
|
|
495
|
+
});
|
|
496
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
497
|
+
await $state.transitionTo("onInit");
|
|
498
|
+
await wait(10);
|
|
499
|
+
|
|
500
|
+
expect($onInit).toHaveBeenCalled();
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
// TargetNode not found error
|
|
504
|
+
xit("should default the template to a <ui-view>", async () => {
|
|
505
|
+
$stateProvider.state({ name: "abstract", abstract: true });
|
|
506
|
+
$stateProvider.state({ name: "abstract.foo", template: "hello" });
|
|
507
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
508
|
+
$state.transitionTo("abstract.foo");
|
|
509
|
+
await wait(10);
|
|
510
|
+
|
|
511
|
+
expect(elem.text()).toBe("hello");
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
describe("play nicely with other directives", () => {
|
|
515
|
+
// related to issue #857
|
|
516
|
+
it("should work with ngIf", async () => {
|
|
517
|
+
scope.someBoolean = false;
|
|
518
|
+
elem.append(
|
|
519
|
+
$compile('<div ng-if="someBoolean"><ui-view></ui-view></div>')(scope),
|
|
520
|
+
);
|
|
521
|
+
|
|
522
|
+
$state.transitionTo(aState);
|
|
523
|
+
await wait(10);
|
|
524
|
+
|
|
525
|
+
// Verify there is no ui-view in the DOM
|
|
526
|
+
expect(elem.find("ui-view").length).toBe(0);
|
|
527
|
+
|
|
528
|
+
// Turn on the div that holds the ui-view
|
|
529
|
+
scope.someBoolean = true;
|
|
530
|
+
scope.$digest();
|
|
531
|
+
|
|
532
|
+
// Verify that the ui-view is there and it has the correct content
|
|
533
|
+
expect(elem.find("ui-view").text()).toBe(aState.template);
|
|
534
|
+
|
|
535
|
+
// Turn off the ui-view
|
|
536
|
+
scope.someBoolean = false;
|
|
537
|
+
scope.$digest();
|
|
538
|
+
|
|
539
|
+
// Verify there is no ui-view in the DOM
|
|
540
|
+
expect(elem.find("ui-view").length).toBe(0);
|
|
541
|
+
|
|
542
|
+
// Turn on the div that holds the ui-view once again
|
|
543
|
+
scope.someBoolean = true;
|
|
544
|
+
scope.$digest();
|
|
545
|
+
|
|
546
|
+
// Verify that the ui-view is there and it has the correct content
|
|
547
|
+
expect(elem.find("ui-view").text()).toBe(aState.template);
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
it("should work with ngClass", async () => {
|
|
551
|
+
const classes = (elem) => Array.prototype.slice.call(elem[0].classList);
|
|
552
|
+
|
|
553
|
+
scope.showClass = false;
|
|
554
|
+
elem.append(
|
|
555
|
+
$compile(
|
|
556
|
+
"<div><ui-view ng-class=\"{'someClass': showClass}\"></ui-view></div>",
|
|
557
|
+
)(scope),
|
|
558
|
+
);
|
|
559
|
+
|
|
560
|
+
expect(classes(elem.find("ui-view"))).not.toContain("someClass");
|
|
561
|
+
|
|
562
|
+
scope.showClass = true;
|
|
563
|
+
scope.$digest();
|
|
564
|
+
|
|
565
|
+
expect(classes(elem.find("ui-view"))).toContain("someClass");
|
|
566
|
+
|
|
567
|
+
scope.showClass = false;
|
|
568
|
+
scope.$digest();
|
|
569
|
+
|
|
570
|
+
expect(classes(elem.find("ui-view"))).not.toContain("someClass");
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
describe("working with ngRepeat", () => {
|
|
574
|
+
it("should have correct number of uiViews", async () => {
|
|
575
|
+
elem.append(
|
|
576
|
+
$compile(
|
|
577
|
+
'<div><ui-view ng-repeat="view in views" name="{{view}}"></ui-view></div>',
|
|
578
|
+
)(scope),
|
|
579
|
+
);
|
|
580
|
+
|
|
581
|
+
// Should be no ui-views in DOM
|
|
582
|
+
expect(elem.find("ui-view").length).toBe(0);
|
|
583
|
+
|
|
584
|
+
// Lets add 3
|
|
585
|
+
scope.views = ["view1", "view2", "view3"];
|
|
586
|
+
scope.$digest();
|
|
587
|
+
|
|
588
|
+
// Should be 3 ui-views in the DOM
|
|
589
|
+
expect(elem.find("ui-view").length).toBe(scope.views.length);
|
|
590
|
+
|
|
591
|
+
// Lets add one more - yay two-way binding
|
|
592
|
+
scope.views.push("view4");
|
|
593
|
+
scope.$digest();
|
|
594
|
+
|
|
595
|
+
// Should have 4 ui-views
|
|
596
|
+
expect(elem.find("ui-view").length).toBe(scope.views.length);
|
|
597
|
+
|
|
598
|
+
// Lets remove 2 ui-views from the DOM
|
|
599
|
+
scope.views.pop();
|
|
600
|
+
scope.views.pop();
|
|
601
|
+
scope.$digest();
|
|
602
|
+
|
|
603
|
+
// Should have 2 ui-views
|
|
604
|
+
expect(elem.find("ui-view").length).toBe(scope.views.length);
|
|
605
|
+
});
|
|
606
|
+
|
|
607
|
+
it("should populate each view with content", async () => {
|
|
608
|
+
elem.append(
|
|
609
|
+
$compile(
|
|
610
|
+
'<div><ui-view ng-repeat="view in views" name="{{view}}">defaultcontent</ui-view></div>',
|
|
611
|
+
)(scope),
|
|
612
|
+
);
|
|
613
|
+
|
|
614
|
+
$state.transitionTo(lState);
|
|
615
|
+
await wait(10);
|
|
616
|
+
|
|
617
|
+
expect(elem.find("ui-view").length).toBe(0);
|
|
618
|
+
|
|
619
|
+
scope.views = ["view1", "view2"];
|
|
620
|
+
|
|
621
|
+
scope.$digest();
|
|
622
|
+
|
|
623
|
+
let uiViews = elem.find("ui-view");
|
|
624
|
+
|
|
625
|
+
expect(uiViews.eq(0).text()).toBe(lState.views.view1.template);
|
|
626
|
+
expect(uiViews.eq(1).text()).toBe(lState.views.view2.template);
|
|
627
|
+
expect(uiViews.eq(2).length).toBe(0);
|
|
628
|
+
|
|
629
|
+
scope.views.push("view3");
|
|
630
|
+
scope.$digest();
|
|
631
|
+
|
|
632
|
+
uiViews = elem.find("ui-view");
|
|
633
|
+
|
|
634
|
+
expect(uiViews.eq(0).text()).toBe(lState.views.view1.template);
|
|
635
|
+
expect(uiViews.eq(1).text()).toBe(lState.views.view2.template);
|
|
636
|
+
expect(uiViews.eq(2).text()).toBe(lState.views.view3.template);
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
it("should interpolate ui-view names", async () => {
|
|
640
|
+
elem.append(
|
|
641
|
+
$compile(
|
|
642
|
+
'<div ng-repeat="view in views">' +
|
|
643
|
+
'<ui-view name="view{{$index + 1}}">hallo</ui-view>' +
|
|
644
|
+
"</div>",
|
|
645
|
+
)(scope),
|
|
646
|
+
);
|
|
647
|
+
|
|
648
|
+
$state.transitionTo(lState);
|
|
649
|
+
await wait(10);
|
|
650
|
+
|
|
651
|
+
expect(elem.find("ui-view").length).toBe(0);
|
|
652
|
+
|
|
653
|
+
scope.views = ["view1", "view2"];
|
|
654
|
+
|
|
655
|
+
scope.$digest();
|
|
656
|
+
|
|
657
|
+
let uiViews = elem.find("ui-view");
|
|
658
|
+
|
|
659
|
+
expect(uiViews.eq(0).text()).toBe(lState.views.view1.template);
|
|
660
|
+
expect(uiViews.eq(1).text()).toBe(lState.views.view2.template);
|
|
661
|
+
expect(uiViews.eq(2).length).toBe(0);
|
|
662
|
+
|
|
663
|
+
scope.views.push("view3");
|
|
664
|
+
scope.$digest();
|
|
665
|
+
|
|
666
|
+
uiViews = elem.find("ui-view");
|
|
667
|
+
|
|
668
|
+
expect(uiViews.eq(0).text()).toBe(lState.views.view1.template);
|
|
669
|
+
expect(uiViews.eq(1).text()).toBe(lState.views.view2.template);
|
|
670
|
+
expect(uiViews.eq(2).text()).toBe(lState.views.view3.template);
|
|
671
|
+
});
|
|
672
|
+
});
|
|
673
|
+
});
|
|
674
|
+
|
|
675
|
+
// describe("AngularJS Animations", () => {
|
|
676
|
+
// it("should do transition animations", async () => {
|
|
677
|
+
// let content = "Initial Content",
|
|
678
|
+
// animation;
|
|
679
|
+
// elem.append(
|
|
680
|
+
// $compile("<div><ui-view>" + content + "</ui-view></div>")(scope),
|
|
681
|
+
// );
|
|
682
|
+
|
|
683
|
+
// // Enter Animation
|
|
684
|
+
// animation = $animate.queue.shift();
|
|
685
|
+
// expect(animation.event).toBe("enter");
|
|
686
|
+
// expect(animation.element.text() + "-1").toBe(content + "-1");
|
|
687
|
+
|
|
688
|
+
// $state.transitionTo(aState);
|
|
689
|
+
// await wait(10);
|
|
690
|
+
|
|
691
|
+
// // Enter Animation
|
|
692
|
+
// animation = $animate.queue.shift();
|
|
693
|
+
// expect(animation.event).toBe("enter");
|
|
694
|
+
// expect(animation.element.text() + "-2").toBe(aState.template + "-2");
|
|
695
|
+
// // Leave Animation
|
|
696
|
+
// animation = $animate.queue.shift();
|
|
697
|
+
// expect(animation.event).toBe("leave");
|
|
698
|
+
// expect(animation.element.text() + "-3").toBe(content + "-3");
|
|
699
|
+
|
|
700
|
+
// $state.transitionTo(bState);
|
|
701
|
+
// await wait(10);
|
|
702
|
+
|
|
703
|
+
// // Enter Animation
|
|
704
|
+
// animation = $animate.queue.shift();
|
|
705
|
+
// expect(animation.event).toBe("enter");
|
|
706
|
+
// expect(animation.element.text() + "-4").toBe(bState.template + "-4");
|
|
707
|
+
// // Leave Animation
|
|
708
|
+
// animation = $animate.queue.shift();
|
|
709
|
+
// expect(animation.event).toBe("leave");
|
|
710
|
+
// expect(animation.element.text() + "-5").toBe(aState.template + "-5");
|
|
711
|
+
|
|
712
|
+
// // No more animations
|
|
713
|
+
// expect($animate.queue.length).toBe(0);
|
|
714
|
+
// });
|
|
715
|
+
|
|
716
|
+
// it("should do ngClass animations", async () => {
|
|
717
|
+
// scope.classOn = false;
|
|
718
|
+
// let content = "Initial Content",
|
|
719
|
+
// className = "yay",
|
|
720
|
+
// animation;
|
|
721
|
+
// elem.append(
|
|
722
|
+
// $compile(
|
|
723
|
+
// "<div><ui-view ng-class=\"{'" +
|
|
724
|
+
// className +
|
|
725
|
+
// "': classOn}\">" +
|
|
726
|
+
// content +
|
|
727
|
+
// "</ui-view></div>",
|
|
728
|
+
// )(scope),
|
|
729
|
+
// );
|
|
730
|
+
// // Don't care about enter class
|
|
731
|
+
// $animate.queue.shift();
|
|
732
|
+
|
|
733
|
+
// scope.classOn = true;
|
|
734
|
+
// scope.$digest();
|
|
735
|
+
|
|
736
|
+
// animation = $animate.queue.shift();
|
|
737
|
+
// expect(animation.event).toBe("addClass");
|
|
738
|
+
// expect(animation.element.text()).toBe(content);
|
|
739
|
+
|
|
740
|
+
// scope.classOn = false;
|
|
741
|
+
// scope.$digest();
|
|
742
|
+
|
|
743
|
+
// animation = $animate.queue.shift();
|
|
744
|
+
// expect(animation.event).toBe("removeClass");
|
|
745
|
+
// expect(animation.element.text()).toBe(content);
|
|
746
|
+
|
|
747
|
+
// // No more animations
|
|
748
|
+
// expect($animate.queue.length).toBe(0);
|
|
749
|
+
// });
|
|
750
|
+
|
|
751
|
+
// it("should do ngIf animations", async () => {
|
|
752
|
+
// scope.shouldShow = false;
|
|
753
|
+
// let content = "Initial Content",
|
|
754
|
+
// animation;
|
|
755
|
+
// elem.append(
|
|
756
|
+
// $compile(
|
|
757
|
+
// '<div><ui-view ng-if="shouldShow">' + content + "</ui-view></div>",
|
|
758
|
+
// )(scope),
|
|
759
|
+
// );
|
|
760
|
+
|
|
761
|
+
// // No animations yet
|
|
762
|
+
// expect($animate.queue.length).toBe(0);
|
|
763
|
+
|
|
764
|
+
// scope.shouldShow = true;
|
|
765
|
+
// scope.$digest();
|
|
766
|
+
|
|
767
|
+
// // $ViewDirective enter animation - Basically it's just the <!-- uiView --> comment
|
|
768
|
+
// animation = $animate.queue.shift();
|
|
769
|
+
// expect(animation.event).toBe("enter");
|
|
770
|
+
// expect(animation.element.text()).toBe("");
|
|
771
|
+
|
|
772
|
+
// // $ViewDirectiveFill enter animation - The second uiView directive that files in the content
|
|
773
|
+
// animation = $animate.queue.shift();
|
|
774
|
+
// expect(animation.event).toBe("enter");
|
|
775
|
+
// expect(animation.element.text()).toBe(content);
|
|
776
|
+
|
|
777
|
+
// scope.shouldShow = false;
|
|
778
|
+
// scope.$digest();
|
|
779
|
+
|
|
780
|
+
// // uiView leave animation
|
|
781
|
+
// animation = $animate.queue.shift();
|
|
782
|
+
// expect(animation.event).toBe("leave");
|
|
783
|
+
// expect(animation.element.text()).toBe(content);
|
|
784
|
+
|
|
785
|
+
// // No more animations
|
|
786
|
+
// expect($animate.queue.length).toBe(0);
|
|
787
|
+
// });
|
|
788
|
+
|
|
789
|
+
// it("should expose animation promises to controllers", async () => {
|
|
790
|
+
// $transitions.onStart({}, function ($transition$) {
|
|
791
|
+
// log += "start:" + $transition$.to().name + ";";
|
|
792
|
+
// });
|
|
793
|
+
// $transitions.onFinish({}, function ($transition$) {
|
|
794
|
+
// log += "finish:" + $transition$.to().name + ";";
|
|
795
|
+
// });
|
|
796
|
+
// $transitions.onSuccess({}, function ($transition$) {
|
|
797
|
+
// log += "success:" + $transition$.to().name + ";";
|
|
798
|
+
// });
|
|
799
|
+
|
|
800
|
+
// const content = "Initial Content";
|
|
801
|
+
// elem.append(
|
|
802
|
+
// $compile("<div><ui-view>" + content + "</ui-view></div>")(scope),
|
|
803
|
+
// );
|
|
804
|
+
// $state.transitionTo("n");
|
|
805
|
+
// await wait(10);
|
|
806
|
+
|
|
807
|
+
// expect($state.current.name).toBe("n");
|
|
808
|
+
// expect(log).toBe("start:n;finish:n;success:n;");
|
|
809
|
+
|
|
810
|
+
// // animateFlush($animate);
|
|
811
|
+
// await wait(10);
|
|
812
|
+
// expect(log).toBe("start:n;finish:n;success:n;animEnter;");
|
|
813
|
+
|
|
814
|
+
// $state.transitionTo("a");
|
|
815
|
+
// await wait(10);
|
|
816
|
+
// expect($state.current.name).toBe("a");
|
|
817
|
+
// expect(log).toBe(
|
|
818
|
+
// "start:n;finish:n;success:n;animEnter;start:a;finish:a;destroy;success:a;",
|
|
819
|
+
// );
|
|
820
|
+
|
|
821
|
+
// // animateFlush($animate);
|
|
822
|
+
// await wait(10);
|
|
823
|
+
// expect(log).toBe(
|
|
824
|
+
// "start:n;finish:n;success:n;animEnter;start:a;finish:a;destroy;success:a;animLeave;",
|
|
825
|
+
// );
|
|
826
|
+
// });
|
|
827
|
+
// });
|
|
828
|
+
});
|
|
829
|
+
|
|
830
|
+
describe("UiView", () => {
|
|
831
|
+
let $stateProvider,
|
|
832
|
+
scope,
|
|
833
|
+
$compile,
|
|
834
|
+
elem,
|
|
835
|
+
log,
|
|
836
|
+
app,
|
|
837
|
+
$injector,
|
|
838
|
+
$state,
|
|
839
|
+
$q,
|
|
840
|
+
$timeout,
|
|
841
|
+
$rootScope,
|
|
842
|
+
$uiViewScroll;
|
|
843
|
+
|
|
844
|
+
beforeEach(() => {
|
|
845
|
+
dealoc(document.getElementById("dummy"));
|
|
846
|
+
window.angular = new Angular();
|
|
847
|
+
publishExternalAPI();
|
|
848
|
+
log = "";
|
|
849
|
+
app = window.angular
|
|
850
|
+
.module("defaultModule", ["ui.router"])
|
|
851
|
+
.config((_$stateProvider_) => {
|
|
852
|
+
$stateProvider = _$stateProvider_;
|
|
853
|
+
$stateProvider
|
|
854
|
+
.state({ name: "main", abstract: true, views: { main: {} } })
|
|
855
|
+
.state({
|
|
856
|
+
name: "main.home",
|
|
857
|
+
views: { content: { template: "HOME" } },
|
|
858
|
+
})
|
|
859
|
+
.state({ name: "test", views: { nest: { template: "TEST" } } });
|
|
860
|
+
});
|
|
861
|
+
|
|
862
|
+
$injector = window.angular.bootstrap(document.getElementById("dummy"), [
|
|
863
|
+
"defaultModule",
|
|
864
|
+
]);
|
|
865
|
+
|
|
866
|
+
$injector.invoke(
|
|
867
|
+
(
|
|
868
|
+
_$state_,
|
|
869
|
+
_$q_,
|
|
870
|
+
_$timeout_,
|
|
871
|
+
_$rootScope_,
|
|
872
|
+
_$compile_,
|
|
873
|
+
_$uiViewScroll_,
|
|
874
|
+
) => {
|
|
875
|
+
$rootScope = _$rootScope_;
|
|
876
|
+
scope = $rootScope.$new();
|
|
877
|
+
$compile = _$compile_;
|
|
878
|
+
$state = _$state_;
|
|
879
|
+
$q = _$q_;
|
|
880
|
+
$timeout = _$timeout_;
|
|
881
|
+
elem = jqLite("<div>");
|
|
882
|
+
$uiViewScroll = _$uiViewScroll_;
|
|
883
|
+
},
|
|
884
|
+
);
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
// TODO targetNode not found
|
|
888
|
+
xit("shouldn't puke on weird nested view setups", async () => {
|
|
889
|
+
$compile('<div ui-view="main"><div ui-view="content"></div></div>')(
|
|
890
|
+
$rootScope,
|
|
891
|
+
);
|
|
892
|
+
|
|
893
|
+
await $state.go("main.home");
|
|
894
|
+
await wait(10);
|
|
895
|
+
|
|
896
|
+
expect($state.current.name).toBe("main.home");
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
// Test for https://github.com/angular-ui/ui-router/issues/3355
|
|
900
|
+
it("should target weird nested view setups using the view's simple name", async () => {
|
|
901
|
+
const tpl = `
|
|
902
|
+
<div>
|
|
903
|
+
<div ui-view="main">
|
|
904
|
+
MAIN-DEFAULT-
|
|
905
|
+
<div ui-view="content">
|
|
906
|
+
<div ui-view="nest"></div>
|
|
907
|
+
</div>
|
|
908
|
+
</div>
|
|
909
|
+
</div>
|
|
910
|
+
`;
|
|
911
|
+
const el = $compile(tpl)($rootScope);
|
|
912
|
+
|
|
913
|
+
$state.go("test");
|
|
914
|
+
await wait(10);
|
|
915
|
+
|
|
916
|
+
expect($state.current.name).toBe("test");
|
|
917
|
+
expect(el.text().replace(/\s*/g, "")).toBe("MAIN-DEFAULT-TEST");
|
|
918
|
+
});
|
|
919
|
+
});
|
|
920
|
+
|
|
921
|
+
describe("uiView transclusion", () => {
|
|
922
|
+
let scope, $compile, elem, $injector, $rootScope, $state;
|
|
923
|
+
|
|
924
|
+
beforeEach(() => {
|
|
925
|
+
dealoc(document.getElementById("dummy"));
|
|
926
|
+
window.angular = new Angular();
|
|
927
|
+
publishExternalAPI();
|
|
928
|
+
window.angular
|
|
929
|
+
.module("defaultModule", ["ui.router"])
|
|
930
|
+
.directive("scopeObserver", () => {
|
|
931
|
+
return {
|
|
932
|
+
restrict: "E",
|
|
933
|
+
link: function (scope) {
|
|
934
|
+
scope.$emit("directiveCreated");
|
|
935
|
+
scope.$on("$destroy", () => {
|
|
936
|
+
scope.$emit("directiveDestroyed");
|
|
937
|
+
});
|
|
938
|
+
},
|
|
939
|
+
};
|
|
940
|
+
})
|
|
941
|
+
.config(function ($stateProvider) {
|
|
942
|
+
$stateProvider
|
|
943
|
+
.state({
|
|
944
|
+
name: "a",
|
|
945
|
+
template: "<ui-view><scope-observer></scope-observer></ui-view>",
|
|
946
|
+
})
|
|
947
|
+
.state({ name: "a.b", template: "anything" });
|
|
948
|
+
});
|
|
949
|
+
$injector = window.angular.bootstrap(document.getElementById("dummy"), [
|
|
950
|
+
"defaultModule",
|
|
951
|
+
]);
|
|
952
|
+
|
|
953
|
+
$injector.invoke(
|
|
954
|
+
(
|
|
955
|
+
_$state_,
|
|
956
|
+
_$q_,
|
|
957
|
+
_$timeout_,
|
|
958
|
+
_$rootScope_,
|
|
959
|
+
_$compile_,
|
|
960
|
+
_$uiViewScroll_,
|
|
961
|
+
) => {
|
|
962
|
+
$rootScope = _$rootScope_;
|
|
963
|
+
scope = $rootScope.$new();
|
|
964
|
+
$compile = _$compile_;
|
|
965
|
+
$state = _$state_;
|
|
966
|
+
elem = jqLite("<div>");
|
|
967
|
+
},
|
|
968
|
+
);
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
it("should not link the initial view and leave its scope undestroyed when a subview is activated", async () => {
|
|
972
|
+
let aliveCount = 0;
|
|
973
|
+
scope.$on("directiveCreated", () => {
|
|
974
|
+
aliveCount++;
|
|
975
|
+
});
|
|
976
|
+
scope.$on("directiveDestroyed", () => {
|
|
977
|
+
aliveCount--;
|
|
978
|
+
});
|
|
979
|
+
elem.append($compile("<div><ui-view></ui-view></div>")(scope));
|
|
980
|
+
$state.transitionTo("a.b");
|
|
981
|
+
await wait(10);
|
|
982
|
+
expect(aliveCount).toBe(0);
|
|
983
|
+
});
|
|
984
|
+
});
|
|
985
|
+
|
|
986
|
+
describe("uiView controllers or onEnter handlers", () => {
|
|
987
|
+
let el, template, scope, count, $rootScope, $compile, $state, elem;
|
|
988
|
+
|
|
989
|
+
beforeEach(() => {
|
|
990
|
+
dealoc(document.getElementById("dummy"));
|
|
991
|
+
window.angular = new Angular();
|
|
992
|
+
publishExternalAPI();
|
|
993
|
+
window.angular
|
|
994
|
+
.module("defaultModule", ["ui.router"])
|
|
995
|
+
.config(function ($stateProvider) {
|
|
996
|
+
count = 0;
|
|
997
|
+
$stateProvider
|
|
998
|
+
.state({
|
|
999
|
+
name: "aside",
|
|
1000
|
+
url: "/aside",
|
|
1001
|
+
template: '<div class="aside"></div>',
|
|
1002
|
+
})
|
|
1003
|
+
.state({
|
|
1004
|
+
name: "A",
|
|
1005
|
+
url: "/A",
|
|
1006
|
+
template: '<div class="A" ui-view="fwd"></div>',
|
|
1007
|
+
})
|
|
1008
|
+
.state({
|
|
1009
|
+
name: "A.fwd",
|
|
1010
|
+
url: "/fwd",
|
|
1011
|
+
views: {
|
|
1012
|
+
fwd: {
|
|
1013
|
+
template: '<div class="fwd" ui-view>',
|
|
1014
|
+
controller: function ($state) {
|
|
1015
|
+
if (count++ < 20 && $state.current.name == "A.fwd")
|
|
1016
|
+
$state.go(".nest");
|
|
1017
|
+
},
|
|
1018
|
+
},
|
|
1019
|
+
},
|
|
1020
|
+
})
|
|
1021
|
+
.state({
|
|
1022
|
+
name: "A.fwd.nest",
|
|
1023
|
+
url: "/nest",
|
|
1024
|
+
template: '<div class="nest"></div>',
|
|
1025
|
+
});
|
|
1026
|
+
});
|
|
1027
|
+
|
|
1028
|
+
let $injector = window.angular.bootstrap(document.getElementById("dummy"), [
|
|
1029
|
+
"defaultModule",
|
|
1030
|
+
]);
|
|
1031
|
+
|
|
1032
|
+
$injector.invoke(
|
|
1033
|
+
(
|
|
1034
|
+
_$state_,
|
|
1035
|
+
_$q_,
|
|
1036
|
+
_$timeout_,
|
|
1037
|
+
_$rootScope_,
|
|
1038
|
+
_$compile_,
|
|
1039
|
+
_$uiViewScroll_,
|
|
1040
|
+
) => {
|
|
1041
|
+
$rootScope = _$rootScope_;
|
|
1042
|
+
scope = $rootScope.$new();
|
|
1043
|
+
$compile = _$compile_;
|
|
1044
|
+
$state = _$state_;
|
|
1045
|
+
elem = jqLite("<div>");
|
|
1046
|
+
},
|
|
1047
|
+
);
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
it("should not go into an infinite loop when controller uses $state.go", async () => {
|
|
1051
|
+
el = jqLite("<div><ui-view></ui-view></div>");
|
|
1052
|
+
template = $compile(el)($rootScope);
|
|
1053
|
+
$rootScope.$digest();
|
|
1054
|
+
|
|
1055
|
+
await $state.transitionTo("aside");
|
|
1056
|
+
await wait(10);
|
|
1057
|
+
expect(template[0].querySelector(".aside")).toBeDefined();
|
|
1058
|
+
expect(template[0].querySelector(".fwd")).toBeNull();
|
|
1059
|
+
|
|
1060
|
+
await $state.transitionTo("A");
|
|
1061
|
+
await wait(10);
|
|
1062
|
+
expect(template[0].querySelector(".A")).not.toBeNull();
|
|
1063
|
+
expect(template[0].querySelector(".fwd")).toBeNull();
|
|
1064
|
+
|
|
1065
|
+
await $state.transitionTo("A.fwd");
|
|
1066
|
+
await wait(10);
|
|
1067
|
+
expect(template[0].querySelector(".A")).not.toBeNull();
|
|
1068
|
+
expect(template[0].querySelector(".fwd")).not.toBeNull();
|
|
1069
|
+
expect(template[0].querySelector(".nest")).not.toBeNull();
|
|
1070
|
+
expect(count).toBe(1);
|
|
1071
|
+
});
|
|
1072
|
+
});
|
|
1073
|
+
|
|
1074
|
+
describe("angular 1.5+ style .component()", () => {
|
|
1075
|
+
let el, app, scope, log, svcs, $stateProvider, $templateCache, $rootScope;
|
|
1076
|
+
|
|
1077
|
+
beforeEach(() => {
|
|
1078
|
+
dealoc(document.getElementById("dummy"));
|
|
1079
|
+
window.angular = new Angular();
|
|
1080
|
+
publishExternalAPI();
|
|
1081
|
+
window.angular
|
|
1082
|
+
.module("defaultModule", ["ui.router"])
|
|
1083
|
+
.directive("ng12Directive", () => {
|
|
1084
|
+
return {
|
|
1085
|
+
restrict: "E",
|
|
1086
|
+
scope: { data: "=" },
|
|
1087
|
+
templateUrl: "/comp_tpl.html",
|
|
1088
|
+
controller: function ($scope) {
|
|
1089
|
+
this.data = $scope.data;
|
|
1090
|
+
},
|
|
1091
|
+
controllerAs: "$ctrl",
|
|
1092
|
+
};
|
|
1093
|
+
})
|
|
1094
|
+
.directive("ng13Directive", () => {
|
|
1095
|
+
return {
|
|
1096
|
+
scope: { data: "=" },
|
|
1097
|
+
templateUrl: "/comp_tpl.html",
|
|
1098
|
+
controller: function () {
|
|
1099
|
+
this.$onInit = function () {
|
|
1100
|
+
log += "onInit;";
|
|
1101
|
+
};
|
|
1102
|
+
},
|
|
1103
|
+
bindToController: true,
|
|
1104
|
+
controllerAs: "$ctrl",
|
|
1105
|
+
};
|
|
1106
|
+
})
|
|
1107
|
+
.directive("ng12DynamicDirective", () => {
|
|
1108
|
+
return {
|
|
1109
|
+
restrict: "E",
|
|
1110
|
+
template: "dynamic directive",
|
|
1111
|
+
};
|
|
1112
|
+
})
|
|
1113
|
+
.component("ngComponent", {
|
|
1114
|
+
bindings: { data: "<", data2: "<" },
|
|
1115
|
+
templateUrl: "/comp_tpl.html",
|
|
1116
|
+
controller: function () {
|
|
1117
|
+
this.$onInit = function () {
|
|
1118
|
+
log += "onInit;";
|
|
1119
|
+
};
|
|
1120
|
+
},
|
|
1121
|
+
})
|
|
1122
|
+
.component("header", {
|
|
1123
|
+
bindings: { status: "<" },
|
|
1124
|
+
template: "#{{ $ctrl.status }}#",
|
|
1125
|
+
})
|
|
1126
|
+
.component("bindingTypes", {
|
|
1127
|
+
bindings: { oneway: "<oneway", twoway: "=", attribute: "@attr" },
|
|
1128
|
+
template:
|
|
1129
|
+
"-{{ $ctrl.oneway }},{{ $ctrl.twoway }},{{ $ctrl.attribute }}-",
|
|
1130
|
+
})
|
|
1131
|
+
.component("optionalBindingTypes", {
|
|
1132
|
+
bindings: { oneway: "<?oneway", twoway: "=?", attribute: "@?attr" },
|
|
1133
|
+
template:
|
|
1134
|
+
"-{{ $ctrl.oneway }},{{ $ctrl.twoway }},{{ $ctrl.attribute }}-",
|
|
1135
|
+
})
|
|
1136
|
+
.component("eventComponent", {
|
|
1137
|
+
bindings: { evt: "&" },
|
|
1138
|
+
template: "eventCmp",
|
|
1139
|
+
})
|
|
1140
|
+
.component("mydataComponent", {
|
|
1141
|
+
bindings: { dataUser: "<" },
|
|
1142
|
+
template: "-{{ $ctrl.dataUser }}-",
|
|
1143
|
+
})
|
|
1144
|
+
.component("dataComponent", {
|
|
1145
|
+
template: "DataComponent",
|
|
1146
|
+
})
|
|
1147
|
+
.component("parentCallbackComponent", {
|
|
1148
|
+
controller: function ($rootScope) {
|
|
1149
|
+
this.handleEvent = function (foo, bar) {
|
|
1150
|
+
$rootScope.log.push(foo);
|
|
1151
|
+
$rootScope.log.push(bar);
|
|
1152
|
+
};
|
|
1153
|
+
},
|
|
1154
|
+
template: `
|
|
1155
|
+
<h1>parentCmp</h1>
|
|
1156
|
+
<ui-view on-event="$ctrl.handleEvent(foo, bar)"></ui-view>
|
|
1157
|
+
`,
|
|
1158
|
+
})
|
|
1159
|
+
.component("childEventComponent", {
|
|
1160
|
+
bindings: { onEvent: "&" },
|
|
1161
|
+
template: `
|
|
1162
|
+
<h1>childCmp</h1>
|
|
1163
|
+
<button id="eventbtn" ng-click="$ctrl.onEvent({ foo: 123, bar: 456 })">Button</button>
|
|
1164
|
+
`,
|
|
1165
|
+
})
|
|
1166
|
+
.component("dynamicComponent", {
|
|
1167
|
+
template: "dynamicComponent {{ $ctrl.param }}",
|
|
1168
|
+
controller: function () {
|
|
1169
|
+
this.uiOnParamsChanged = function (params) {
|
|
1170
|
+
this.param = params.param;
|
|
1171
|
+
};
|
|
1172
|
+
},
|
|
1173
|
+
})
|
|
1174
|
+
.config(function (_$stateProvider_) {
|
|
1175
|
+
$stateProvider = _$stateProvider_;
|
|
1176
|
+
});
|
|
1177
|
+
|
|
1178
|
+
let $injector = window.angular.bootstrap(document.getElementById("dummy"), [
|
|
1179
|
+
"defaultModule",
|
|
1180
|
+
]);
|
|
1181
|
+
|
|
1182
|
+
$injector.invoke(
|
|
1183
|
+
(
|
|
1184
|
+
_$rootScope_,
|
|
1185
|
+
_$httpBackend_,
|
|
1186
|
+
_$compile_,
|
|
1187
|
+
_$state_,
|
|
1188
|
+
_$q_,
|
|
1189
|
+
_$templateCache_,
|
|
1190
|
+
) => {
|
|
1191
|
+
svcs = {
|
|
1192
|
+
$httpBackend: _$httpBackend_,
|
|
1193
|
+
$compile: _$compile_,
|
|
1194
|
+
$state: _$state_,
|
|
1195
|
+
$q: _$q_,
|
|
1196
|
+
};
|
|
1197
|
+
$rootScope = _$rootScope_;
|
|
1198
|
+
scope = $rootScope.$new();
|
|
1199
|
+
log = "";
|
|
1200
|
+
el = jqLite("<div><ui-view></ui-view></div>");
|
|
1201
|
+
svcs.$compile(el)(scope);
|
|
1202
|
+
$templateCache = _$templateCache_;
|
|
1203
|
+
},
|
|
1204
|
+
);
|
|
1205
|
+
});
|
|
1206
|
+
|
|
1207
|
+
describe("routing using component templates", () => {
|
|
1208
|
+
beforeEach(() => {
|
|
1209
|
+
$stateProvider.state({
|
|
1210
|
+
name: "cmp_tpl",
|
|
1211
|
+
url: "/cmp_tpl",
|
|
1212
|
+
templateUrl: "/state_tpl.html",
|
|
1213
|
+
controller: function () {},
|
|
1214
|
+
resolve: {
|
|
1215
|
+
data: function () {
|
|
1216
|
+
return "DATA!";
|
|
1217
|
+
},
|
|
1218
|
+
},
|
|
1219
|
+
});
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
it("should work with directives which themselves have templateUrls", async () => {
|
|
1223
|
+
const $state = svcs.$state;
|
|
1224
|
+
|
|
1225
|
+
$templateCache.put(
|
|
1226
|
+
"/state_tpl.html",
|
|
1227
|
+
'x<ng12-directive data="$resolve.data"></ng12-directive>x',
|
|
1228
|
+
);
|
|
1229
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1230
|
+
|
|
1231
|
+
await $state.transitionTo("cmp_tpl");
|
|
1232
|
+
|
|
1233
|
+
expect($state.current.name).toBe("cmp_tpl");
|
|
1234
|
+
expect(el[0].querySelector("ui-view").innerHTML).toEqual(
|
|
1235
|
+
'x<ng12-directive data="$resolve.data">-DATA!-</ng12-directive>x',
|
|
1236
|
+
);
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1239
|
+
it("should work with bindToController directives", async () => {
|
|
1240
|
+
const $state = svcs.$state;
|
|
1241
|
+
|
|
1242
|
+
$templateCache.put(
|
|
1243
|
+
"/state_tpl.html",
|
|
1244
|
+
'x<ng13-directive data="$resolve.data"></ng13-directive>x',
|
|
1245
|
+
);
|
|
1246
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1247
|
+
|
|
1248
|
+
await $state.transitionTo("cmp_tpl");
|
|
1249
|
+
await wait(10);
|
|
1250
|
+
|
|
1251
|
+
expect($state.current.name).toBe("cmp_tpl");
|
|
1252
|
+
expect(el[0].querySelector("ui-view").innerHTML).toEqual(
|
|
1253
|
+
'x<ng13-directive data="$resolve.data">-DATA!-</ng13-directive>x',
|
|
1254
|
+
);
|
|
1255
|
+
});
|
|
1256
|
+
|
|
1257
|
+
it("should work with .component()s", async () => {
|
|
1258
|
+
const $state = svcs.$state;
|
|
1259
|
+
|
|
1260
|
+
$templateCache.put(
|
|
1261
|
+
"/state_tpl.html",
|
|
1262
|
+
'x<ng-component data="$resolve.data"></ng-component>x',
|
|
1263
|
+
);
|
|
1264
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1265
|
+
|
|
1266
|
+
$state.transitionTo("cmp_tpl");
|
|
1267
|
+
await wait(10);
|
|
1268
|
+
|
|
1269
|
+
expect($state.current.name).toBe("cmp_tpl");
|
|
1270
|
+
expect(el[0].querySelector("ui-view").innerHTML).toEqual(
|
|
1271
|
+
'x<ng-component data="$resolve.data">-DATA!-</ng-component>x',
|
|
1272
|
+
);
|
|
1273
|
+
});
|
|
1274
|
+
});
|
|
1275
|
+
|
|
1276
|
+
describe("+ component: declaration", () => {
|
|
1277
|
+
it("should disallow controller/template configuration", () => {
|
|
1278
|
+
const stateDef = {
|
|
1279
|
+
name: "route2cmp",
|
|
1280
|
+
url: "/route2cmp",
|
|
1281
|
+
component: "ng12Directive",
|
|
1282
|
+
resolve: {
|
|
1283
|
+
data: function () {
|
|
1284
|
+
return "DATA!";
|
|
1285
|
+
},
|
|
1286
|
+
},
|
|
1287
|
+
};
|
|
1288
|
+
|
|
1289
|
+
expect(() => {
|
|
1290
|
+
$stateProvider.state(
|
|
1291
|
+
Object.assign({ name: "route2cmp", template: "fail" }, stateDef),
|
|
1292
|
+
);
|
|
1293
|
+
}).toThrow();
|
|
1294
|
+
expect(() => {
|
|
1295
|
+
$stateProvider.state(
|
|
1296
|
+
Object.assign(
|
|
1297
|
+
{ name: "route2cmp", templateUrl: "fail.html" },
|
|
1298
|
+
stateDef,
|
|
1299
|
+
),
|
|
1300
|
+
);
|
|
1301
|
+
}).toThrow();
|
|
1302
|
+
expect(() => {
|
|
1303
|
+
$stateProvider.state(
|
|
1304
|
+
Object.assign(
|
|
1305
|
+
{ name: "route2cmp", templateProvider: () => {} },
|
|
1306
|
+
stateDef,
|
|
1307
|
+
),
|
|
1308
|
+
);
|
|
1309
|
+
}).toThrow();
|
|
1310
|
+
expect(() => {
|
|
1311
|
+
$stateProvider.state(
|
|
1312
|
+
Object.assign({ name: "route2cmp", controllerAs: "fail" }, stateDef),
|
|
1313
|
+
);
|
|
1314
|
+
}).toThrow();
|
|
1315
|
+
expect(() => {
|
|
1316
|
+
$stateProvider.state(
|
|
1317
|
+
Object.assign(
|
|
1318
|
+
{ name: "route2cmp", controller: "FailCtrl" },
|
|
1319
|
+
stateDef,
|
|
1320
|
+
),
|
|
1321
|
+
);
|
|
1322
|
+
}).toThrow();
|
|
1323
|
+
expect(() => {
|
|
1324
|
+
$stateProvider.state(
|
|
1325
|
+
Object.assign(
|
|
1326
|
+
{ name: "route2cmp", controllerProvider: function () {} },
|
|
1327
|
+
stateDef,
|
|
1328
|
+
),
|
|
1329
|
+
);
|
|
1330
|
+
}).toThrow();
|
|
1331
|
+
|
|
1332
|
+
expect(() => {
|
|
1333
|
+
$stateProvider.state(stateDef);
|
|
1334
|
+
}).not.toThrow();
|
|
1335
|
+
});
|
|
1336
|
+
|
|
1337
|
+
it("should work with angular 1.2+ directives", async () => {
|
|
1338
|
+
$stateProvider.state({
|
|
1339
|
+
name: "route2cmp",
|
|
1340
|
+
url: "/route2cmp",
|
|
1341
|
+
component: "ng12Directive",
|
|
1342
|
+
resolve: {
|
|
1343
|
+
data: () => {
|
|
1344
|
+
return "DATA!";
|
|
1345
|
+
},
|
|
1346
|
+
},
|
|
1347
|
+
});
|
|
1348
|
+
|
|
1349
|
+
const $state = svcs.$state;
|
|
1350
|
+
|
|
1351
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1352
|
+
$state.transitionTo("route2cmp");
|
|
1353
|
+
await wait(10);
|
|
1354
|
+
|
|
1355
|
+
const directiveEl = el[0].querySelector("div ui-view ng12-directive");
|
|
1356
|
+
expect(directiveEl).toBeDefined();
|
|
1357
|
+
expect($state.current.name).toBe("route2cmp");
|
|
1358
|
+
expect(el.text()).toBe("-DATA!-");
|
|
1359
|
+
});
|
|
1360
|
+
|
|
1361
|
+
it("should work with angular 1.3+ bindToComponent directives", async () => {
|
|
1362
|
+
$stateProvider.state({
|
|
1363
|
+
name: "route2cmp",
|
|
1364
|
+
url: "/route2cmp",
|
|
1365
|
+
component: "ng13Directive",
|
|
1366
|
+
resolve: {
|
|
1367
|
+
data: () => {
|
|
1368
|
+
return "DATA!";
|
|
1369
|
+
},
|
|
1370
|
+
},
|
|
1371
|
+
});
|
|
1372
|
+
|
|
1373
|
+
const $state = svcs.$state,
|
|
1374
|
+
$httpBackend = svcs.$httpBackend,
|
|
1375
|
+
$q = svcs.$q;
|
|
1376
|
+
|
|
1377
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1378
|
+
$state.transitionTo("route2cmp");
|
|
1379
|
+
await wait(10);
|
|
1380
|
+
|
|
1381
|
+
const directiveEl = el[0].querySelector("div ui-view ng13-directive");
|
|
1382
|
+
expect(directiveEl).toBeDefined();
|
|
1383
|
+
expect($state.current.name).toBe("route2cmp");
|
|
1384
|
+
expect(el.text()).toBe("-DATA!-");
|
|
1385
|
+
});
|
|
1386
|
+
|
|
1387
|
+
it("should call $onInit() once", async () => {
|
|
1388
|
+
$stateProvider.state({
|
|
1389
|
+
name: "route2cmp",
|
|
1390
|
+
url: "/route2cmp",
|
|
1391
|
+
component: "ng13Directive",
|
|
1392
|
+
resolve: {
|
|
1393
|
+
data: () => {
|
|
1394
|
+
return "DATA!";
|
|
1395
|
+
},
|
|
1396
|
+
},
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
const $state = svcs.$state;
|
|
1400
|
+
|
|
1401
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1402
|
+
$state.transitionTo("route2cmp");
|
|
1403
|
+
await wait(10);
|
|
1404
|
+
|
|
1405
|
+
expect(log).toBe("onInit;");
|
|
1406
|
+
});
|
|
1407
|
+
|
|
1408
|
+
it("should work with angular 1.5+ .component()s", async () => {
|
|
1409
|
+
$stateProvider.state({
|
|
1410
|
+
name: "route2cmp",
|
|
1411
|
+
url: "/route2cmp",
|
|
1412
|
+
component: "ngComponent",
|
|
1413
|
+
resolve: {
|
|
1414
|
+
data: () => {
|
|
1415
|
+
return "DATA!";
|
|
1416
|
+
},
|
|
1417
|
+
},
|
|
1418
|
+
});
|
|
1419
|
+
|
|
1420
|
+
const $state = svcs.$state,
|
|
1421
|
+
$httpBackend = svcs.$httpBackend,
|
|
1422
|
+
$q = svcs.$q;
|
|
1423
|
+
|
|
1424
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1425
|
+
$state.transitionTo("route2cmp");
|
|
1426
|
+
await wait(10);
|
|
1427
|
+
|
|
1428
|
+
const directiveEl = el[0].querySelector("div ui-view ng-component");
|
|
1429
|
+
expect(directiveEl).toBeDefined();
|
|
1430
|
+
expect($state.current.name).toBe("route2cmp");
|
|
1431
|
+
expect(el.text()).toBe("-DATA!-");
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
it("should only call $onInit() once", async () => {
|
|
1435
|
+
$stateProvider.state({
|
|
1436
|
+
name: "route2cmp",
|
|
1437
|
+
component: "ngComponent",
|
|
1438
|
+
resolve: {
|
|
1439
|
+
data: () => {
|
|
1440
|
+
return "DATA!";
|
|
1441
|
+
},
|
|
1442
|
+
},
|
|
1443
|
+
});
|
|
1444
|
+
|
|
1445
|
+
const $state = svcs.$state,
|
|
1446
|
+
$httpBackend = svcs.$httpBackend,
|
|
1447
|
+
$q = svcs.$q;
|
|
1448
|
+
|
|
1449
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1450
|
+
$state.transitionTo("route2cmp");
|
|
1451
|
+
await wait(10);
|
|
1452
|
+
|
|
1453
|
+
expect(log).toBe("onInit;");
|
|
1454
|
+
});
|
|
1455
|
+
|
|
1456
|
+
it("should only call $onInit() once with componentProvider", async () => {
|
|
1457
|
+
$stateProvider.state({
|
|
1458
|
+
name: "route2cmp",
|
|
1459
|
+
componentProvider: () => "ngComponent",
|
|
1460
|
+
resolve: {
|
|
1461
|
+
data: () => {
|
|
1462
|
+
return "DATA!";
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1465
|
+
});
|
|
1466
|
+
|
|
1467
|
+
const $state = svcs.$state,
|
|
1468
|
+
$httpBackend = svcs.$httpBackend,
|
|
1469
|
+
$q = svcs.$q;
|
|
1470
|
+
|
|
1471
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1472
|
+
$state.transitionTo("route2cmp");
|
|
1473
|
+
await wait(10);
|
|
1474
|
+
|
|
1475
|
+
expect(log).toBe("onInit;");
|
|
1476
|
+
});
|
|
1477
|
+
|
|
1478
|
+
it('should supply resolve data to "<", "=", "@" bindings', async () => {
|
|
1479
|
+
$stateProvider.state({
|
|
1480
|
+
name: "bindingtypes",
|
|
1481
|
+
component: "bindingTypes",
|
|
1482
|
+
resolve: {
|
|
1483
|
+
oneway: () => {
|
|
1484
|
+
return "ONEWAY";
|
|
1485
|
+
},
|
|
1486
|
+
twoway: () => {
|
|
1487
|
+
return "TWOWAY";
|
|
1488
|
+
},
|
|
1489
|
+
attribute: () => {
|
|
1490
|
+
return "ATTRIBUTE";
|
|
1491
|
+
},
|
|
1492
|
+
},
|
|
1493
|
+
bindings: { attr: "attribute" },
|
|
1494
|
+
});
|
|
1495
|
+
|
|
1496
|
+
const $state = svcs.$state,
|
|
1497
|
+
$httpBackend = svcs.$httpBackend,
|
|
1498
|
+
$q = svcs.$q;
|
|
1499
|
+
|
|
1500
|
+
$state.transitionTo("bindingtypes");
|
|
1501
|
+
await wait(10);
|
|
1502
|
+
|
|
1503
|
+
expect(el.text()).toBe("-ONEWAY,TWOWAY,ATTRIBUTE-");
|
|
1504
|
+
});
|
|
1505
|
+
|
|
1506
|
+
it('should supply resolve data to optional "<?", "=?", "@?" bindings', async () => {
|
|
1507
|
+
$stateProvider.state({
|
|
1508
|
+
name: "optionalbindingtypes",
|
|
1509
|
+
component: "optionalBindingTypes",
|
|
1510
|
+
resolve: {
|
|
1511
|
+
oneway: () => {
|
|
1512
|
+
return "ONEWAY";
|
|
1513
|
+
},
|
|
1514
|
+
twoway: () => {
|
|
1515
|
+
return "TWOWAY";
|
|
1516
|
+
},
|
|
1517
|
+
attribute: () => {
|
|
1518
|
+
return "ATTRIBUTE";
|
|
1519
|
+
},
|
|
1520
|
+
},
|
|
1521
|
+
bindings: { attr: "attribute" },
|
|
1522
|
+
});
|
|
1523
|
+
|
|
1524
|
+
const $state = svcs.$state;
|
|
1525
|
+
|
|
1526
|
+
$state.transitionTo("optionalbindingtypes");
|
|
1527
|
+
await wait(10);
|
|
1528
|
+
|
|
1529
|
+
expect(el.text()).toBe("-ONEWAY,TWOWAY,ATTRIBUTE-");
|
|
1530
|
+
});
|
|
1531
|
+
|
|
1532
|
+
// Test for #3099
|
|
1533
|
+
it('should not throw when routing to a component with output "&" binding', async () => {
|
|
1534
|
+
$stateProvider.state({
|
|
1535
|
+
name: "nothrow",
|
|
1536
|
+
component: "eventComponent",
|
|
1537
|
+
});
|
|
1538
|
+
|
|
1539
|
+
const $state = svcs.$state;
|
|
1540
|
+
$state.transitionTo("nothrow");
|
|
1541
|
+
await wait(10);
|
|
1542
|
+
|
|
1543
|
+
expect(el.text()).toBe("eventCmp");
|
|
1544
|
+
});
|
|
1545
|
+
|
|
1546
|
+
// Test for #3276
|
|
1547
|
+
it('should route to a component that is prefixed with "data"', async () => {
|
|
1548
|
+
$stateProvider.state({
|
|
1549
|
+
name: "data",
|
|
1550
|
+
component: "dataComponent",
|
|
1551
|
+
});
|
|
1552
|
+
|
|
1553
|
+
const $state = svcs.$state,
|
|
1554
|
+
$q = svcs.$q;
|
|
1555
|
+
$state.transitionTo("data");
|
|
1556
|
+
await wait(10);
|
|
1557
|
+
|
|
1558
|
+
expect(el.text()).toBe("DataComponent");
|
|
1559
|
+
});
|
|
1560
|
+
|
|
1561
|
+
// Test for #3276
|
|
1562
|
+
it('should bind a resolve that is prefixed with "data"', async () => {
|
|
1563
|
+
$stateProvider.state({
|
|
1564
|
+
name: "data",
|
|
1565
|
+
component: "mydataComponent",
|
|
1566
|
+
resolve: { dataUser: () => "user" },
|
|
1567
|
+
});
|
|
1568
|
+
|
|
1569
|
+
const $state = svcs.$state,
|
|
1570
|
+
$q = svcs.$q;
|
|
1571
|
+
$state.transitionTo("data");
|
|
1572
|
+
await wait(10);
|
|
1573
|
+
|
|
1574
|
+
expect(el.text()).toBe("-user-");
|
|
1575
|
+
});
|
|
1576
|
+
|
|
1577
|
+
// Test for #3239
|
|
1578
|
+
it("should pass any bindings (wired from a parent component template via the ui-view) through to the child", async () => {
|
|
1579
|
+
const $state = svcs.$state,
|
|
1580
|
+
$q = svcs.$q;
|
|
1581
|
+
|
|
1582
|
+
$stateProvider.state({
|
|
1583
|
+
name: "parent",
|
|
1584
|
+
template:
|
|
1585
|
+
'<ui-view oneway="data1w" twoway="data2w" attr="attrval"></ui-view>',
|
|
1586
|
+
controller: function ($scope) {
|
|
1587
|
+
$scope.data1w = "1w";
|
|
1588
|
+
$scope.data2w = "2w";
|
|
1589
|
+
},
|
|
1590
|
+
});
|
|
1591
|
+
|
|
1592
|
+
$stateProvider.state({
|
|
1593
|
+
name: "parent.child",
|
|
1594
|
+
component: "bindingTypes",
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
$state.transitionTo("parent.child");
|
|
1598
|
+
await wait(10);
|
|
1599
|
+
expect(el.text()).toEqual("-1w,2w,attrval-");
|
|
1600
|
+
});
|
|
1601
|
+
|
|
1602
|
+
// Test for #3239
|
|
1603
|
+
it("should prefer ui-view bindings over resolve data", async () => {
|
|
1604
|
+
const $state = svcs.$state,
|
|
1605
|
+
$q = svcs.$q;
|
|
1606
|
+
|
|
1607
|
+
$stateProvider.state({
|
|
1608
|
+
name: "parent",
|
|
1609
|
+
template:
|
|
1610
|
+
'<ui-view oneway="data1w" twoway="data2w" attr="attrval"></ui-view>',
|
|
1611
|
+
resolve: {
|
|
1612
|
+
oneway: () => "asfasfd",
|
|
1613
|
+
twoway: () => "asfasfd",
|
|
1614
|
+
attr: () => "asfasfd",
|
|
1615
|
+
},
|
|
1616
|
+
controller: function ($scope) {
|
|
1617
|
+
$scope.data1w = "1w";
|
|
1618
|
+
$scope.data2w = "2w";
|
|
1619
|
+
},
|
|
1620
|
+
});
|
|
1621
|
+
|
|
1622
|
+
$stateProvider.state({
|
|
1623
|
+
name: "parent.child",
|
|
1624
|
+
component: "bindingTypes",
|
|
1625
|
+
});
|
|
1626
|
+
|
|
1627
|
+
$state.transitionTo("parent.child");
|
|
1628
|
+
await wait(10);
|
|
1629
|
+
expect(el.text()).toEqual("-1w,2w,attrval-");
|
|
1630
|
+
});
|
|
1631
|
+
|
|
1632
|
+
// Test for #3239
|
|
1633
|
+
it("should prefer ui-view bindings over resolve data unless a bindings exists", async () => {
|
|
1634
|
+
const $state = svcs.$state,
|
|
1635
|
+
$q = svcs.$q;
|
|
1636
|
+
|
|
1637
|
+
$stateProvider.state({
|
|
1638
|
+
name: "parent",
|
|
1639
|
+
template:
|
|
1640
|
+
'<ui-view oneway="data1w" twoway="data2w" attr="attrval"></ui-view>',
|
|
1641
|
+
resolve: {
|
|
1642
|
+
oneway: () => "asfasfd",
|
|
1643
|
+
twoway: () => "asfasfd",
|
|
1644
|
+
attr: () => "asfasfd",
|
|
1645
|
+
},
|
|
1646
|
+
controller: function ($scope) {
|
|
1647
|
+
$scope.data1w = "1w";
|
|
1648
|
+
$scope.data2w = "2w";
|
|
1649
|
+
},
|
|
1650
|
+
});
|
|
1651
|
+
|
|
1652
|
+
$stateProvider.state({
|
|
1653
|
+
name: "parent.child",
|
|
1654
|
+
component: "bindingTypes",
|
|
1655
|
+
bindings: { oneway: "oneway" },
|
|
1656
|
+
});
|
|
1657
|
+
|
|
1658
|
+
$state.transitionTo("parent.child");
|
|
1659
|
+
await wait(10);
|
|
1660
|
+
expect(el.text()).toEqual("-asfasfd,2w,attrval-");
|
|
1661
|
+
});
|
|
1662
|
+
|
|
1663
|
+
// Test for #3239
|
|
1664
|
+
it("should pass & bindings (wired from a parent component via the ui-view) through to the child", async () => {
|
|
1665
|
+
const $state = svcs.$state,
|
|
1666
|
+
$q = svcs.$q;
|
|
1667
|
+
$rootScope.log = [];
|
|
1668
|
+
|
|
1669
|
+
$stateProvider.state({
|
|
1670
|
+
name: "parent",
|
|
1671
|
+
component: "parentCallbackComponent",
|
|
1672
|
+
});
|
|
1673
|
+
|
|
1674
|
+
$stateProvider.state({
|
|
1675
|
+
name: "parent.child",
|
|
1676
|
+
component: "childEventComponent",
|
|
1677
|
+
});
|
|
1678
|
+
|
|
1679
|
+
$state.transitionTo("parent.child");
|
|
1680
|
+
await wait(10);
|
|
1681
|
+
expect($rootScope.log).toEqual([]);
|
|
1682
|
+
expect(
|
|
1683
|
+
el
|
|
1684
|
+
.text()
|
|
1685
|
+
.split(/\s+/)
|
|
1686
|
+
.filter((x) => x),
|
|
1687
|
+
).toEqual(["parentCmp", "childCmp", "Button"]);
|
|
1688
|
+
|
|
1689
|
+
// - Click button
|
|
1690
|
+
// - ng-click handler calls $ctrl.onEvent({ foo: 123, bar: 456 })
|
|
1691
|
+
// - on-event is bound to $ctrl.handleEvent(foo, bar) on parentCallbackComponent
|
|
1692
|
+
// - handleEvent pushes param values to the log
|
|
1693
|
+
el.find("button")[0].click();
|
|
1694
|
+
expect($rootScope.log).toEqual([123, 456]);
|
|
1695
|
+
});
|
|
1696
|
+
|
|
1697
|
+
// Test for #3111
|
|
1698
|
+
it("should bind & bindings to a resolve that returns a function", async () => {
|
|
1699
|
+
const $state = svcs.$state,
|
|
1700
|
+
$q = svcs.$q,
|
|
1701
|
+
log = [];
|
|
1702
|
+
|
|
1703
|
+
$stateProvider.state({
|
|
1704
|
+
name: "resolve",
|
|
1705
|
+
component: "childEventComponent",
|
|
1706
|
+
resolve: {
|
|
1707
|
+
onEvent: () => (foo, bar) => {
|
|
1708
|
+
log.push(foo);
|
|
1709
|
+
log.push(bar);
|
|
1710
|
+
},
|
|
1711
|
+
},
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
$state.transitionTo("resolve");
|
|
1715
|
+
await wait(10);
|
|
1716
|
+
expect(log).toEqual([]);
|
|
1717
|
+
el.find("button")[0].click();
|
|
1718
|
+
expect(log).toEqual([123, 456]);
|
|
1719
|
+
});
|
|
1720
|
+
|
|
1721
|
+
// Test for #3111
|
|
1722
|
+
it("should bind & bindings to a resolve that returns an array-style function", async () => {
|
|
1723
|
+
const $state = svcs.$state,
|
|
1724
|
+
$q = svcs.$q,
|
|
1725
|
+
log = [];
|
|
1726
|
+
|
|
1727
|
+
$stateProvider.state({
|
|
1728
|
+
name: "resolve",
|
|
1729
|
+
component: "childEventComponent",
|
|
1730
|
+
resolve: {
|
|
1731
|
+
onEvent: () => [
|
|
1732
|
+
"foo",
|
|
1733
|
+
"bar",
|
|
1734
|
+
(foo, bar) => {
|
|
1735
|
+
log.push(foo);
|
|
1736
|
+
log.push(bar);
|
|
1737
|
+
},
|
|
1738
|
+
],
|
|
1739
|
+
},
|
|
1740
|
+
});
|
|
1741
|
+
|
|
1742
|
+
$state.transitionTo("resolve");
|
|
1743
|
+
await wait(10);
|
|
1744
|
+
expect(log).toEqual([]);
|
|
1745
|
+
el.find("button")[0].click();
|
|
1746
|
+
expect(log).toEqual([123, 456]);
|
|
1747
|
+
});
|
|
1748
|
+
});
|
|
1749
|
+
|
|
1750
|
+
describe("+ named views with component: declaration", () => {
|
|
1751
|
+
let stateDef;
|
|
1752
|
+
beforeEach(() => {
|
|
1753
|
+
stateDef = {
|
|
1754
|
+
name: "route2cmp",
|
|
1755
|
+
url: "/route2cmp",
|
|
1756
|
+
views: {
|
|
1757
|
+
header: { component: "header" },
|
|
1758
|
+
content: { component: "ngComponent" },
|
|
1759
|
+
},
|
|
1760
|
+
resolve: {
|
|
1761
|
+
status: () => {
|
|
1762
|
+
return "awesome";
|
|
1763
|
+
},
|
|
1764
|
+
data: () => {
|
|
1765
|
+
return "DATA!";
|
|
1766
|
+
},
|
|
1767
|
+
},
|
|
1768
|
+
};
|
|
1769
|
+
|
|
1770
|
+
el = jqLite(
|
|
1771
|
+
'<div><div ui-view="header"></div><div ui-view="content"</div>',
|
|
1772
|
+
);
|
|
1773
|
+
svcs.$compile(el)(scope);
|
|
1774
|
+
});
|
|
1775
|
+
|
|
1776
|
+
it("should disallow controller/template configuration in the view", () => {
|
|
1777
|
+
expect(() => {
|
|
1778
|
+
$stateProvider.state(stateDef);
|
|
1779
|
+
}).not.toThrow();
|
|
1780
|
+
expect(() => {
|
|
1781
|
+
const state = Object.assign({}, stateDef);
|
|
1782
|
+
state.views.header.template = "fails";
|
|
1783
|
+
$stateProvider.state(state);
|
|
1784
|
+
}).toThrow();
|
|
1785
|
+
});
|
|
1786
|
+
|
|
1787
|
+
it("should render components as views", async () => {
|
|
1788
|
+
$stateProvider.state(stateDef);
|
|
1789
|
+
const $state = svcs.$state;
|
|
1790
|
+
|
|
1791
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1792
|
+
$state.transitionTo("route2cmp");
|
|
1793
|
+
await wait(10);
|
|
1794
|
+
|
|
1795
|
+
const header = el[0].querySelector("[ui-view=header]");
|
|
1796
|
+
const content = el[0].querySelector("[ui-view=content]");
|
|
1797
|
+
|
|
1798
|
+
expect(header.textContent).toBe("#awesome#");
|
|
1799
|
+
expect(content.textContent).toBe("-DATA!-");
|
|
1800
|
+
});
|
|
1801
|
+
|
|
1802
|
+
it("should allow a component view declaration to use a string as a shorthand", async () => {
|
|
1803
|
+
stateDef = {
|
|
1804
|
+
name: "route2cmp",
|
|
1805
|
+
url: "/route2cmp",
|
|
1806
|
+
views: { header: "header", content: "ngComponent" },
|
|
1807
|
+
resolve: {
|
|
1808
|
+
status: () => {
|
|
1809
|
+
return "awesome";
|
|
1810
|
+
},
|
|
1811
|
+
data: () => {
|
|
1812
|
+
return "DATA!";
|
|
1813
|
+
},
|
|
1814
|
+
},
|
|
1815
|
+
};
|
|
1816
|
+
$stateProvider.state(stateDef);
|
|
1817
|
+
const $state = svcs.$state,
|
|
1818
|
+
$httpBackend = svcs.$httpBackend,
|
|
1819
|
+
$q = svcs.$q;
|
|
1820
|
+
|
|
1821
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1822
|
+
$state.transitionTo("route2cmp");
|
|
1823
|
+
await wait(10);
|
|
1824
|
+
|
|
1825
|
+
const header = el[0].querySelector("[ui-view=header]");
|
|
1826
|
+
const content = el[0].querySelector("[ui-view=content]");
|
|
1827
|
+
|
|
1828
|
+
expect(header.textContent).toBe("#awesome#");
|
|
1829
|
+
expect(content.textContent).toBe("-DATA!-");
|
|
1830
|
+
});
|
|
1831
|
+
|
|
1832
|
+
// Test for https://github.com/angular-ui/ui-router/issues/3353
|
|
1833
|
+
it("should allow different states to reuse view declaration", () => {
|
|
1834
|
+
const views = {
|
|
1835
|
+
header: { component: "header" },
|
|
1836
|
+
content: { component: "ngComponent" },
|
|
1837
|
+
};
|
|
1838
|
+
|
|
1839
|
+
const stateDef1 = { name: "def1", url: "/def1", views: views };
|
|
1840
|
+
const stateDef2 = { name: "def2", url: "/def2", views: views };
|
|
1841
|
+
|
|
1842
|
+
$stateProvider.state(stateDef1);
|
|
1843
|
+
$stateProvider.state(stateDef2);
|
|
1844
|
+
});
|
|
1845
|
+
});
|
|
1846
|
+
|
|
1847
|
+
describe("+ bindings: declaration", () => {
|
|
1848
|
+
it("should provide the named component binding with data from the named resolve", async () => {
|
|
1849
|
+
$stateProvider.state({
|
|
1850
|
+
name: "route2cmp",
|
|
1851
|
+
url: "/route2cmp",
|
|
1852
|
+
component: "ng12Directive",
|
|
1853
|
+
bindings: { data: "foo" },
|
|
1854
|
+
resolve: {
|
|
1855
|
+
foo: () => {
|
|
1856
|
+
return "DATA!";
|
|
1857
|
+
},
|
|
1858
|
+
},
|
|
1859
|
+
});
|
|
1860
|
+
|
|
1861
|
+
const $state = svcs.$state;
|
|
1862
|
+
|
|
1863
|
+
$templateCache.put("/comp_tpl.html", "-{{ $ctrl.data }}-");
|
|
1864
|
+
$state.transitionTo("route2cmp");
|
|
1865
|
+
await wait(10);
|
|
1866
|
+
|
|
1867
|
+
const directiveEl = el[0].querySelector("div ui-view ng12-directive");
|
|
1868
|
+
expect(directiveEl).toBeDefined();
|
|
1869
|
+
expect($state.current.name).toBe("route2cmp");
|
|
1870
|
+
expect(el.text()).toBe("-DATA!-");
|
|
1871
|
+
});
|
|
1872
|
+
|
|
1873
|
+
it("should provide default bindings for any component bindings omitted in the state.bindings map", async () => {
|
|
1874
|
+
$stateProvider.state({
|
|
1875
|
+
name: "route2cmp",
|
|
1876
|
+
url: "/route2cmp",
|
|
1877
|
+
component: "ngComponent",
|
|
1878
|
+
bindings: { data: "foo" },
|
|
1879
|
+
resolve: {
|
|
1880
|
+
foo: () => {
|
|
1881
|
+
return "DATA!";
|
|
1882
|
+
},
|
|
1883
|
+
data2: () => {
|
|
1884
|
+
return "DATA2!";
|
|
1885
|
+
},
|
|
1886
|
+
},
|
|
1887
|
+
});
|
|
1888
|
+
|
|
1889
|
+
const $state = svcs.$state,
|
|
1890
|
+
$httpBackend = svcs.$httpBackend,
|
|
1891
|
+
$q = svcs.$q;
|
|
1892
|
+
|
|
1893
|
+
$templateCache.put(
|
|
1894
|
+
"/comp_tpl.html",
|
|
1895
|
+
"-{{ $ctrl.data }}.{{ $ctrl.data2 }}-",
|
|
1896
|
+
);
|
|
1897
|
+
$state.transitionTo("route2cmp");
|
|
1898
|
+
await wait(10);
|
|
1899
|
+
|
|
1900
|
+
const directiveEl = el[0].querySelector("div ui-view ng-component");
|
|
1901
|
+
expect(directiveEl).toBeDefined();
|
|
1902
|
+
expect($state.current.name).toBe("route2cmp");
|
|
1903
|
+
expect(el.text()).toBe("-DATA!.DATA2!-");
|
|
1904
|
+
});
|
|
1905
|
+
});
|
|
1906
|
+
|
|
1907
|
+
describe("componentProvider", () => {
|
|
1908
|
+
it("should work with angular 1.2+ directives", async () => {
|
|
1909
|
+
$stateProvider.state({
|
|
1910
|
+
name: "ng12-dynamic-directive",
|
|
1911
|
+
url: "/ng12dynamicDirective/:type",
|
|
1912
|
+
componentProvider: [
|
|
1913
|
+
"$stateParams",
|
|
1914
|
+
function ($stateParams) {
|
|
1915
|
+
return $stateParams.type;
|
|
1916
|
+
},
|
|
1917
|
+
],
|
|
1918
|
+
});
|
|
1919
|
+
|
|
1920
|
+
const $state = svcs.$state,
|
|
1921
|
+
$q = svcs.$q;
|
|
1922
|
+
|
|
1923
|
+
$state.transitionTo("ng12-dynamic-directive", {
|
|
1924
|
+
type: "ng12DynamicDirective",
|
|
1925
|
+
});
|
|
1926
|
+
await wait(10);
|
|
1927
|
+
|
|
1928
|
+
const directiveEl = el[0].querySelector(
|
|
1929
|
+
"div ui-view ng12-dynamic-directive",
|
|
1930
|
+
);
|
|
1931
|
+
expect(directiveEl).toBeDefined();
|
|
1932
|
+
expect($state.current.name).toBe("ng12-dynamic-directive");
|
|
1933
|
+
expect(el.text()).toBe("dynamic directive");
|
|
1934
|
+
});
|
|
1935
|
+
|
|
1936
|
+
// TODO Invalid transition
|
|
1937
|
+
xit("should load correct component when using componentProvider", async () => {
|
|
1938
|
+
$stateProvider.state({
|
|
1939
|
+
name: "dynamicComponent",
|
|
1940
|
+
url: "/dynamicComponent/:type",
|
|
1941
|
+
componentProvider: [
|
|
1942
|
+
"$stateParams",
|
|
1943
|
+
function ($stateParams) {
|
|
1944
|
+
return $stateParams.type;
|
|
1945
|
+
},
|
|
1946
|
+
],
|
|
1947
|
+
});
|
|
1948
|
+
|
|
1949
|
+
const $state = svcs.$state;
|
|
1950
|
+
|
|
1951
|
+
await $state.transitionTo({
|
|
1952
|
+
name: "dynamicComponent",
|
|
1953
|
+
type: "dynamicComponent",
|
|
1954
|
+
});
|
|
1955
|
+
await wait(10);
|
|
1956
|
+
|
|
1957
|
+
const directiveEl = el[0].querySelector("div ui-view dynamic-component");
|
|
1958
|
+
expect(directiveEl).toBeDefined();
|
|
1959
|
+
expect($state.current.name).toBe("dynamicComponent");
|
|
1960
|
+
expect(el.text().trim()).toBe("dynamicComponent");
|
|
1961
|
+
});
|
|
1962
|
+
});
|
|
1963
|
+
|
|
1964
|
+
describe("uiOnParamsChanged()", () => {
|
|
1965
|
+
let param;
|
|
1966
|
+
|
|
1967
|
+
beforeEach(() => {
|
|
1968
|
+
param = null;
|
|
1969
|
+
|
|
1970
|
+
$stateProvider.state({
|
|
1971
|
+
name: "dynamic",
|
|
1972
|
+
url: "/dynamic/:param",
|
|
1973
|
+
component: "dynamicComponent",
|
|
1974
|
+
params: { param: { dynamic: true } },
|
|
1975
|
+
});
|
|
1976
|
+
|
|
1977
|
+
$stateProvider.state({
|
|
1978
|
+
name: "dynamic2",
|
|
1979
|
+
url: "/dynamic2/:param",
|
|
1980
|
+
componentProvider: () => "dynamicComponent",
|
|
1981
|
+
params: { param: { dynamic: true } },
|
|
1982
|
+
});
|
|
1983
|
+
});
|
|
1984
|
+
|
|
1985
|
+
it("should not be called on the initial transition", async () => {
|
|
1986
|
+
const $state = svcs.$state;
|
|
1987
|
+
$state.go("dynamic", { param: "abc" });
|
|
1988
|
+
await wait(10);
|
|
1989
|
+
expect(el.text().trim()).toBe("dynamicComponent");
|
|
1990
|
+
});
|
|
1991
|
+
|
|
1992
|
+
it("should be called when dynamic parameters change", async () => {
|
|
1993
|
+
const $state = svcs.$state;
|
|
1994
|
+
$state.go("dynamic", { param: "abc" });
|
|
1995
|
+
await wait(10);
|
|
1996
|
+
$state.go("dynamic", { param: "def" });
|
|
1997
|
+
await wait(10);
|
|
1998
|
+
|
|
1999
|
+
expect(el.text().trim()).toBe("dynamicComponent def");
|
|
2000
|
+
});
|
|
2001
|
+
|
|
2002
|
+
it("should work with componentProvider", async () => {
|
|
2003
|
+
const $state = svcs.$state,
|
|
2004
|
+
$q = svcs.$q;
|
|
2005
|
+
$state.go("dynamic2", { param: "abc" });
|
|
2006
|
+
await wait(10);
|
|
2007
|
+
$state.go("dynamic2", { param: "def" });
|
|
2008
|
+
await wait(10);
|
|
2009
|
+
|
|
2010
|
+
expect(el.text().trim()).toBe("dynamicComponent def");
|
|
2011
|
+
});
|
|
2012
|
+
});
|
|
2013
|
+
});
|