ember-source 4.3.0-alpha.4 → 4.3.0-beta.1

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +6 -2
  2. package/build-metadata.json +3 -3
  3. package/dist/dependencies/router_js.js +66 -31
  4. package/dist/ember-template-compiler.js +16 -13
  5. package/dist/ember-template-compiler.map +1 -1
  6. package/dist/ember-testing.js +1 -1
  7. package/dist/ember-testing.map +1 -1
  8. package/dist/ember.debug.js +669 -1204
  9. package/dist/ember.debug.map +1 -1
  10. package/dist/header/license.js +1 -1
  11. package/dist/packages/@ember/-internals/container/index.js +14 -10
  12. package/dist/packages/@ember/-internals/glimmer/index.js +60 -45
  13. package/dist/packages/@ember/-internals/meta/lib/meta.js +8 -9
  14. package/dist/packages/@ember/-internals/metal/index.js +44 -45
  15. package/dist/packages/@ember/-internals/routing/lib/ext/controller.js +10 -8
  16. package/dist/packages/@ember/-internals/routing/lib/services/router.js +153 -191
  17. package/dist/packages/@ember/-internals/routing/lib/system/route-info.js +2 -2
  18. package/dist/packages/@ember/-internals/routing/lib/system/route.js +95 -374
  19. package/dist/packages/@ember/-internals/routing/lib/system/router.js +60 -33
  20. package/dist/packages/@ember/-internals/routing/lib/utils.js +31 -20
  21. package/dist/packages/@ember/-internals/runtime/lib/mixins/action_handler.js +32 -32
  22. package/dist/packages/@ember/-internals/utils/index.js +2 -0
  23. package/dist/packages/@ember/-internals/views/lib/system/utils.js +1 -0
  24. package/dist/packages/@ember/canary-features/index.js +2 -2
  25. package/dist/packages/@ember/controller/index.js +3 -54
  26. package/dist/packages/@ember/instrumentation/index.js +9 -13
  27. package/dist/packages/@ember/routing/router-service.js +1 -0
  28. package/dist/packages/@ember/service/index.js +6 -73
  29. package/dist/packages/ember/version.js +1 -1
  30. package/docs/data.json +412 -344
  31. package/package.json +4 -4
@@ -20,47 +20,6 @@ import { calculateCacheKey, deprecateTransitionMethods, normalizeControllerQuery
20
20
  import generateController from './generate_controller';
21
21
  export const ROUTE_CONNECTIONS = new WeakMap();
22
22
  const RENDER = symbol('render');
23
- export function defaultSerialize(model, params) {
24
- if (params.length < 1 || !model) {
25
- return;
26
- }
27
-
28
- let object = {};
29
-
30
- if (params.length === 1) {
31
- let [name] = params;
32
-
33
- if (name in model) {
34
- object[name] = get(model, name);
35
- } else if (/_id$/.test(name)) {
36
- object[name] = get(model, 'id');
37
- } else if (isProxy(model)) {
38
- object[name] = get(model, name);
39
- }
40
- } else {
41
- object = getProperties(model, params);
42
- }
43
-
44
- return object;
45
- }
46
- export function hasDefaultSerialize(route) {
47
- return route.serialize === defaultSerialize;
48
- }
49
- /**
50
- @module @ember/routing
51
- */
52
-
53
- /**
54
- The `Route` class is used to define individual routes. Refer to
55
- the [routing guide](https://guides.emberjs.com/release/routing/) for documentation.
56
-
57
- @class Route
58
- @extends EmberObject
59
- @uses ActionHandler
60
- @uses Evented
61
- @since 1.0.0
62
- @public
63
- */
64
23
 
65
24
  class Route extends EmberObject.extend(ActionHandler, Evented) {
66
25
  constructor(owner) {
@@ -77,6 +36,68 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
77
36
  this._environment = owner.lookup('-environment:main');
78
37
  }
79
38
  }
39
+ /**
40
+ A hook you can implement to convert the route's model into parameters
41
+ for the URL.
42
+ ```app/router.js
43
+ // ...
44
+ Router.map(function() {
45
+ this.route('post', { path: '/posts/:post_id' });
46
+ });
47
+ ```
48
+ ```app/routes/post.js
49
+ import Route from '@ember/routing/route';
50
+ export default class PostRoute extends Route {
51
+ model({ post_id }) {
52
+ // the server returns `{ id: 12 }`
53
+ return fetch(`/posts/${post_id}`;
54
+ }
55
+ serialize(model) {
56
+ // this will make the URL `/posts/12`
57
+ return { post_id: model.id };
58
+ }
59
+ }
60
+ ```
61
+ The default `serialize` method will insert the model's `id` into the
62
+ route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'.
63
+ If the route has multiple dynamic segments or does not contain '_id', `serialize`
64
+ will return `getProperties(model, params)`
65
+ This method is called when `transitionTo` is called with a context
66
+ in order to populate the URL.
67
+ @method serialize
68
+ @param {Object} model the routes model
69
+ @param {Array} params an Array of parameter names for the current
70
+ route (in the example, `['post_id']`.
71
+ @return {Object} the serialized parameters
72
+ @since 1.0.0
73
+ @public
74
+ */
75
+
76
+
77
+ serialize(model, params) {
78
+ if (params.length < 1 || !model) {
79
+ return;
80
+ }
81
+
82
+ let object = {};
83
+
84
+ if (params.length === 1) {
85
+ let [name] = params;
86
+ assert('has name', name);
87
+
88
+ if (name in model) {
89
+ object[name] = get(model, name);
90
+ } else if (/_id$/.test(name)) {
91
+ object[name] = get(model, 'id');
92
+ } else if (isProxy(model)) {
93
+ object[name] = get(model, name);
94
+ }
95
+ } else {
96
+ object = getProperties(model, params);
97
+ }
98
+
99
+ return object;
100
+ }
80
101
  /**
81
102
  Sets the name for this route, including a fully resolved name for routes
82
103
  inside engines.
@@ -118,9 +139,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
118
139
  namePaths[a] = `${routeInfo.name}.${names[a]}`;
119
140
  }
120
141
 
121
- for (let i = 0; i < qps.length; ++i) {
122
- let qp = qps[i];
123
-
142
+ for (let qp of qps) {
124
143
  if (qp.scope === 'model') {
125
144
  qp.parts = namePaths;
126
145
  }
@@ -203,9 +222,9 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
203
222
  let fullName = route.fullRouteName;
204
223
  let params = Object.assign({}, state.params[fullName]);
205
224
  let queryParams = getQueryParamsFor(route, state);
206
- return Object.keys(queryParams).reduce((params, key) => {
225
+ return Object.entries(queryParams).reduce((params, [key, value]) => {
207
226
  assert(`The route '${this.routeName}' has both a dynamic segment and query param with name '${key}'. Please rename one to avoid collisions.`, !params[key]);
208
- params[key] = queryParams[key];
227
+ params[key] = value;
209
228
  return params;
210
229
  }, params);
211
230
  }
@@ -322,148 +341,6 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
322
341
  this.activate(transition);
323
342
  this.trigger('activate', transition);
324
343
  }
325
- /**
326
- The `willTransition` action is fired at the beginning of any
327
- attempted transition with a `Transition` object as the sole
328
- argument. This action can be used for aborting, redirecting,
329
- or decorating the transition from the currently active routes.
330
- A good example is preventing navigation when a form is
331
- half-filled out:
332
- ```app/routes/contact-form.js
333
- import Route from '@ember/routing/route';
334
- import { action } from '@ember/object';
335
- export default class ContactFormRoute extends Route {
336
- @action
337
- willTransition(transition) {
338
- if (this.controller.get('userHasEnteredData')) {
339
- this.controller.displayNavigationConfirm();
340
- transition.abort();
341
- }
342
- }
343
- }
344
- ```
345
- You can also redirect elsewhere by calling
346
- `this.transitionTo('elsewhere')` from within `willTransition`.
347
- Note that `willTransition` will not be fired for the
348
- redirecting `transitionTo`, since `willTransition` doesn't
349
- fire when there is already a transition underway. If you want
350
- subsequent `willTransition` actions to fire for the redirecting
351
- transition, you must first explicitly call
352
- `transition.abort()`.
353
- To allow the `willTransition` event to continue bubbling to the parent
354
- route, use `return true;`. When the `willTransition` method has a
355
- return value of `true` then the parent route's `willTransition` method
356
- will be fired, enabling "bubbling" behavior for the event.
357
- @event willTransition
358
- @param {Transition} transition
359
- @since 1.0.0
360
- @public
361
- */
362
-
363
- /**
364
- The `didTransition` action is fired after a transition has
365
- successfully been completed. This occurs after the normal model
366
- hooks (`beforeModel`, `model`, `afterModel`, `setupController`)
367
- have resolved. The `didTransition` action has no arguments,
368
- however, it can be useful for tracking page views or resetting
369
- state on the controller.
370
- ```app/routes/login.js
371
- import Route from '@ember/routing/route';
372
- import { action } from '@ember/object';
373
- export default class LoginRoute extends Route {
374
- @action
375
- didTransition() {
376
- this.controller.get('errors.base').clear();
377
- return true; // Bubble the didTransition event
378
- }
379
- }
380
- ```
381
- @event didTransition
382
- @since 1.2.0
383
- @public
384
- */
385
-
386
- /**
387
- The `loading` action is fired on the route when a route's `model`
388
- hook returns a promise that is not already resolved. The current
389
- `Transition` object is the first parameter and the route that
390
- triggered the loading event is the second parameter.
391
- ```app/routes/application.js
392
- import Route from '@ember/routing/route';
393
- import { action } from '@ember/object';
394
- export default class ApplicationRoute extends Route {
395
- @action
396
- loading(transition, route) {
397
- let controller = this.controllerFor('foo');
398
- // The controller may not be instantiated when initially loading
399
- if (controller) {
400
- controller.currentlyLoading = true;
401
- transition.finally(function() {
402
- controller.currentlyLoading = false;
403
- });
404
- }
405
- }
406
- }
407
- ```
408
- @event loading
409
- @param {Transition} transition
410
- @param {Route} route The route that triggered the loading event
411
- @since 1.2.0
412
- @public
413
- */
414
-
415
- /**
416
- When attempting to transition into a route, any of the hooks
417
- may return a promise that rejects, at which point an `error`
418
- action will be fired on the partially-entered routes, allowing
419
- for per-route error handling logic, or shared error handling
420
- logic defined on a parent route.
421
- Here is an example of an error handler that will be invoked
422
- for rejected promises from the various hooks on the route,
423
- as well as any unhandled errors from child routes:
424
- ```app/routes/admin.js
425
- import { reject } from 'rsvp';
426
- import Route from '@ember/routing/route';
427
- import { action } from '@ember/object';
428
- export default class AdminRoute extends Route {
429
- beforeModel() {
430
- return reject('bad things!');
431
- }
432
- @action
433
- error(error, transition) {
434
- // Assuming we got here due to the error in `beforeModel`,
435
- // we can expect that error === "bad things!",
436
- // but a promise model rejecting would also
437
- // call this hook, as would any errors encountered
438
- // in `afterModel`.
439
- // The `error` hook is also provided the failed
440
- // `transition`, which can be stored and later
441
- // `.retry()`d if desired.
442
- this.transitionTo('login');
443
- }
444
- }
445
- ```
446
- `error` actions that bubble up all the way to `ApplicationRoute`
447
- will fire a default error handler that logs the error. You can
448
- specify your own global default error handler by overriding the
449
- `error` handler on `ApplicationRoute`:
450
- ```app/routes/application.js
451
- import Route from '@ember/routing/route';
452
- import { action } from '@ember/object';
453
- export default class ApplicationRoute extends Route {
454
- @action
455
- error(error, transition) {
456
- this.controllerFor('banner').displayError(error.message);
457
- }
458
- }
459
- ```
460
- @event error
461
- @param {Error} error
462
- @param {Transition} transition
463
- @since 1.0.0
464
- @public
465
- */
466
-
467
344
  /**
468
345
  This event is triggered when the router enters the route. It is
469
346
  not executed when the model for the route changes.
@@ -774,14 +651,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
774
651
  setup(context, transition) {
775
652
  let controllerName = this.controllerName || this.routeName;
776
653
  let definedController = this.controllerFor(controllerName, true);
777
- let controller;
778
-
779
- if (definedController) {
780
- controller = definedController;
781
- } else {
782
- controller = this.generateController(controllerName);
783
- } // SAFETY: Since `_qp` is protected we can't infer the type
784
-
654
+ let controller = definedController !== null && definedController !== void 0 ? definedController : this.generateController(controllerName); // SAFETY: Since `_qp` is protected we can't infer the type
785
655
 
786
656
  let queryParams = get(this, '_qp'); // Assign the route's controller so that it can more easily be
787
657
  // referenced in action handlers. Side effects. Side effects everywhere.
@@ -803,6 +673,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
803
673
  let allParams = queryParams.propertyNames;
804
674
  allParams.forEach(prop => {
805
675
  let aQp = queryParams.map[prop];
676
+ assert('expected aQp', aQp);
806
677
  aQp.values = params;
807
678
  let cacheKey = calculateCacheKey(aQp.route.fullRouteName, aQp.parts, aQp.values);
808
679
  let value = cache.lookup(cacheKey, prop, aQp.undecoratedDefaultValue);
@@ -839,71 +710,10 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
839
710
  let cacheKey = calculateCacheKey(qp.route.fullRouteName, qp.parts, qp.values);
840
711
  cache.stash(cacheKey, prop, value);
841
712
  }
842
- /**
843
- This hook is the first of the route entry validation hooks
844
- called when an attempt is made to transition into a route
845
- or one of its children. It is called before `model` and
846
- `afterModel`, and is appropriate for cases when:
847
- 1) A decision can be made to redirect elsewhere without
848
- needing to resolve the model first.
849
- 2) Any async operations need to occur first before the
850
- model is attempted to be resolved.
851
- This hook is provided the current `transition` attempt
852
- as a parameter, which can be used to `.abort()` the transition,
853
- save it for a later `.retry()`, or retrieve values set
854
- on it from a previous hook. You can also just call
855
- `this.transitionTo` to another route to implicitly
856
- abort the `transition`.
857
- You can return a promise from this hook to pause the
858
- transition until the promise resolves (or rejects). This could
859
- be useful, for instance, for retrieving async code from
860
- the server that is required to enter a route.
861
- @method beforeModel
862
- @param {Transition} transition
863
- @return {any | Promise<any>} if the value returned from this hook is
864
- a promise, the transition will pause until the transition
865
- resolves. Otherwise, non-promise return values are not
866
- utilized in any way.
867
- @since 1.0.0
868
- @public
869
- */
870
713
 
714
+ beforeModel(_transition) {}
871
715
 
872
- beforeModel() {}
873
- /**
874
- This hook is called after this route's model has resolved.
875
- It follows identical async/promise semantics to `beforeModel`
876
- but is provided the route's resolved model in addition to
877
- the `transition`, and is therefore suited to performing
878
- logic that can only take place after the model has already
879
- resolved.
880
- ```app/routes/posts.js
881
- import Route from '@ember/routing/route';
882
- export default class PostsRoute extends Route {
883
- afterModel(posts, transition) {
884
- if (posts.get('length') === 1) {
885
- this.transitionTo('post.show', posts.get('firstObject'));
886
- }
887
- }
888
- }
889
- ```
890
- Refer to documentation for `beforeModel` for a description
891
- of transition-pausing semantics when a promise is returned
892
- from this hook.
893
- @method afterModel
894
- @param {Object} resolvedModel the value returned from `model`,
895
- or its resolved value if it was a promise
896
- @param {Transition} transition
897
- @return {any | Promise<any>} if the value returned from this hook is
898
- a promise, the transition will pause until the transition
899
- resolves. Otherwise, non-promise return values are not
900
- utilized in any way.
901
- @since 1.0.0
902
- @public
903
- */
904
-
905
-
906
- afterModel() {}
716
+ afterModel(_resolvedModel, _transition) {}
907
717
  /**
908
718
  A hook you can implement to optionally redirect to another route.
909
719
  Calling `this.transitionTo` from inside of the `redirect` hook will
@@ -926,7 +736,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
926
736
  */
927
737
 
928
738
 
929
- redirect() {}
739
+ redirect(_model, _transition) {}
930
740
  /**
931
741
  Called when the context is changed by router.js.
932
742
  @private
@@ -1021,11 +831,14 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1021
831
 
1022
832
  if (!name) {
1023
833
  if (sawParams) {
834
+ // SAFETY: This should be equivalent
1024
835
  return Object.assign({}, params);
1025
836
  } else {
1026
837
  if (transition.resolveIndex < 1) {
1027
838
  return;
1028
- }
839
+ } // SAFETY: These return types should be equivalent but router.js doesn't have enough
840
+ // generics to infer it.
841
+
1029
842
 
1030
843
  return transition[STATE_SYMBOL].routeInfos[transition.resolveIndex - 1].context;
1031
844
  }
@@ -1116,29 +929,8 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1116
929
  set(controller, 'model', context);
1117
930
  }
1118
931
  }
1119
- /**
1120
- Returns the controller of the current route, or a parent (or any ancestor)
1121
- route in a route hierarchy.
1122
- The controller instance must already have been created, either through entering the
1123
- associated route or using `generateController`.
1124
- ```app/routes/post.js
1125
- import Route from '@ember/routing/route';
1126
- export default class PostRoute extends Route {
1127
- setupController(controller, post) {
1128
- super.setupController(controller, post);
1129
- this.controllerFor('posts').set('currentPost', post);
1130
- }
1131
- }
1132
- ```
1133
- @method controllerFor
1134
- @param {String} name the name of the route or controller
1135
- @return {Controller}
1136
- @since 1.0.0
1137
- @public
1138
- */
1139
-
1140
932
 
1141
- controllerFor(name, _skipAssert) {
933
+ controllerFor(name, _skipAssert = false) {
1142
934
  let owner = getOwner(this);
1143
935
  assert('Route is unexpectedly missing an owner', owner);
1144
936
  let route = owner.lookup(`route:${name}`);
@@ -1237,7 +1029,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1237
1029
  }
1238
1030
  }
1239
1031
 
1240
- return route && route.currentModel;
1032
+ return route === null || route === void 0 ? void 0 : route.currentModel;
1241
1033
  }
1242
1034
  /**
1243
1035
  `this[RENDER]` is used to render a template into a region of another template
@@ -1280,39 +1072,6 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1280
1072
  once(this._router, '_setOutlets');
1281
1073
  }
1282
1074
  }
1283
- /**
1284
- Allows you to produce custom metadata for the route.
1285
- The return value of this method will be attached to
1286
- its corresponding RouteInfoWithAttributes object.
1287
- Example
1288
- ```app/routes/posts/index.js
1289
- import Route from '@ember/routing/route';
1290
- export default class PostsIndexRoute extends Route {
1291
- buildRouteInfoMetadata() {
1292
- return { title: 'Posts Page' }
1293
- }
1294
- }
1295
- ```
1296
- ```app/routes/application.js
1297
- import Route from '@ember/routing/route';
1298
- import { service } from '@ember/service';
1299
- export default class ApplicationRoute extends Route {
1300
- @service router
1301
- constructor() {
1302
- super(...arguments);
1303
- this.router.on('routeDidChange', transition => {
1304
- document.title = transition.to.metadata.title;
1305
- // would update document's title to "Posts Page"
1306
- });
1307
- }
1308
- }
1309
- ```
1310
- @method buildRouteInfoMetadata
1311
- @return any
1312
- @since 3.10.0
1313
- @public
1314
- */
1315
-
1316
1075
 
1317
1076
  buildRouteInfoMetadata() {}
1318
1077
 
@@ -1381,7 +1140,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1381
1140
  // this route find its query params and normalize their object shape them
1382
1141
  // merge in the query params for the route. As a mergedProperty,
1383
1142
  // Route#queryParams is always at least `{}`
1384
- let controllerDefinedQueryParameterConfiguration = get(controller, 'queryParams') || {};
1143
+ let controllerDefinedQueryParameterConfiguration = get(controller, 'queryParams') || [];
1385
1144
  let normalizedControllerQueryParameterConfiguration = normalizeControllerQueryParams(controllerDefinedQueryParameterConfiguration);
1386
1145
  combinedQueryParameterConfiguration = mergeEachQueryParams(normalizedControllerQueryParameterConfiguration, queryParameterConfiguraton);
1387
1146
  } else if (hasRouterDefinedQueryParams) {
@@ -1453,6 +1212,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1453
1212
  */
1454
1213
  inactive: (prop, value) => {
1455
1214
  let qp = map[prop];
1215
+ assert('expected inactive callback to only be called for registered qps', qp);
1456
1216
 
1457
1217
  this._qpChanged(prop, value, qp);
1458
1218
  },
@@ -1464,6 +1224,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1464
1224
  */
1465
1225
  active: (prop, value) => {
1466
1226
  let qp = map[prop];
1227
+ assert('expected active callback to only be called for registered qps', qp);
1467
1228
 
1468
1229
  this._qpChanged(prop, value, qp);
1469
1230
 
@@ -1476,6 +1237,7 @@ class Route extends EmberObject.extend(ActionHandler, Evented) {
1476
1237
  */
1477
1238
  allowOverrides: (prop, value) => {
1478
1239
  let qp = map[prop];
1240
+ assert('expected allowOverrides callback to only be called for registered qps', qp);
1479
1241
 
1480
1242
  this._qpChanged(prop, value, qp);
1481
1243
 
@@ -1506,7 +1268,9 @@ function routeInfoFor(route, routeInfos, offset = 0) {
1506
1268
  let current;
1507
1269
 
1508
1270
  for (let i = 0; i < routeInfos.length; i++) {
1509
- current = routeInfos[i].route;
1271
+ let routeInfo = routeInfos[i];
1272
+ assert('has current routeInfo', routeInfo);
1273
+ current = routeInfo.route;
1510
1274
 
1511
1275
  if (current === route) {
1512
1276
  return routeInfos[i + offset];
@@ -1628,9 +1392,10 @@ export function getFullQueryParams(router, state) {
1628
1392
  function getQueryParamsFor(route, state) {
1629
1393
  state.queryParamsFor = state.queryParamsFor || {};
1630
1394
  let name = route.fullRouteName;
1395
+ let existing = state.queryParamsFor[name];
1631
1396
 
1632
- if (state.queryParamsFor[name]) {
1633
- return state.queryParamsFor[name];
1397
+ if (existing) {
1398
+ return existing;
1634
1399
  }
1635
1400
 
1636
1401
  let fullQueryParams = getFullQueryParams(route._router, state);
@@ -1639,9 +1404,8 @@ function getQueryParamsFor(route, state) {
1639
1404
 
1640
1405
  let qps = get(route, '_qp').qps;
1641
1406
 
1642
- for (let i = 0; i < qps.length; ++i) {
1407
+ for (let qp of qps) {
1643
1408
  // Put deserialized qp on params hash.
1644
- let qp = qps[i];
1645
1409
  let qpValueWasPassedIn = (qp.prop in fullQueryParams);
1646
1410
  params[qp.prop] = qpValueWasPassedIn ? fullQueryParams[qp.prop] : copyDefaultValue(qp.defaultValue);
1647
1411
  }
@@ -1732,54 +1496,12 @@ function getEngineRouteName(engine, routeName) {
1732
1496
 
1733
1497
  return routeName;
1734
1498
  }
1735
- /**
1736
- A hook you can implement to convert the route's model into parameters
1737
- for the URL.
1738
-
1739
- ```app/router.js
1740
- // ...
1741
-
1742
- Router.map(function() {
1743
- this.route('post', { path: '/posts/:post_id' });
1744
- });
1745
-
1746
- ```
1747
-
1748
- ```app/routes/post.js
1749
- import Route from '@ember/routing/route';
1750
-
1751
- export default class PostRoute extends Route {
1752
- model({ post_id }) {
1753
- // the server returns `{ id: 12 }`
1754
- return fetch(`/posts/${post_id}`;
1755
- }
1756
-
1757
- serialize(model) {
1758
- // this will make the URL `/posts/12`
1759
- return { post_id: model.id };
1760
- }
1761
- }
1762
- ```
1763
-
1764
- The default `serialize` method will insert the model's `id` into the
1765
- route's dynamic segment (in this case, `:post_id`) if the segment contains '_id'.
1766
- If the route has multiple dynamic segments or does not contain '_id', `serialize`
1767
- will return `getProperties(model, params)`
1768
1499
 
1769
- This method is called when `transitionTo` is called with a context
1770
- in order to populate the URL.
1771
-
1772
- @method serialize
1773
- @param {Object} model the routes model
1774
- @param {Array} params an Array of parameter names for the current
1775
- route (in the example, `['post_id']`.
1776
- @return {Object} the serialized parameters
1777
- @since 1.0.0
1778
- @public
1779
- */
1780
-
1781
-
1782
- Route.prototype.serialize = defaultSerialize; // Set these here so they can be overridden with extend
1500
+ const defaultSerialize = Route.prototype.serialize;
1501
+ export { defaultSerialize };
1502
+ export function hasDefaultSerialize(route) {
1503
+ return route.serialize === defaultSerialize;
1504
+ } // Set these here so they can be overridden with extend
1783
1505
 
1784
1506
  Route.reopen({
1785
1507
  mergedProperties: ['queryParams'],
@@ -1842,8 +1564,8 @@ Route.reopen({
1842
1564
  let qpMap = get(this, '_qp').map;
1843
1565
  let totalChanged = Object.keys(changed).concat(Object.keys(removed));
1844
1566
 
1845
- for (let i = 0; i < totalChanged.length; ++i) {
1846
- let qp = qpMap[totalChanged[i]];
1567
+ for (let change of totalChanged) {
1568
+ let qp = qpMap[change];
1847
1569
 
1848
1570
  if (qp) {
1849
1571
  let options = this._optionsForQueryParam(qp);
@@ -1880,8 +1602,7 @@ Route.reopen({
1880
1602
  let replaceUrl;
1881
1603
  stashParamNames(router, routeInfos);
1882
1604
 
1883
- for (let i = 0; i < qpMeta.qps.length; ++i) {
1884
- let qp = qpMeta.qps[i];
1605
+ for (let qp of qpMeta.qps) {
1885
1606
  let route = qp.route;
1886
1607
  let controller = route.controller;
1887
1608
  let presentKey = qp.urlKey in params && qp.urlKey; // Do a reverse lookup to see if the changed query