Skip to content

Commit

Permalink
[FEATURE routing-router-service-refresh] Add a refresh method to the …
Browse files Browse the repository at this point in the history
…router service

This adds the refresh method to the RouterService as described in RFC 631.

RFC PR: emberjs/rfcs#631
  • Loading branch information
Windvis committed Mar 25, 2021
1 parent b97e201 commit bff7766
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 0 deletions.
36 changes: 36 additions & 0 deletions packages/@ember/-internals/routing/lib/services/router.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { getOwner, Owner } from '@ember/-internals/owner';
import { Evented } from '@ember/-internals/runtime';
import { symbol } from '@ember/-internals/utils';
import { EMBER_ROUTING_ROUTER_SERVICE_REFRESH } from '@ember/canary-features';
import { assert } from '@ember/debug';
import { readOnly } from '@ember/object/computed';
import { assign } from '@ember/polyfills';
import Service from '@ember/service';
import { consumeTag, tagFor } from '@glimmer/validator';
import Route from '../system/route';
import EmberRouter, { QueryParam } from '../system/router';
import { extractRouteArgs, resemblesURL, shallowEqual } from '../utils';

Expand Down Expand Up @@ -474,6 +476,40 @@ export default class RouterService extends Service {
*/
}

if (EMBER_ROUTING_ROUTER_SERVICE_REFRESH) {
RouterService.reopen({
/**
* Refreshes all currently active routes, doing a full transition.
* If a route name is provided and refers to a currently active route,
* it will refresh only that route and its descendents.
* Returns a promise that will be resolved once the refresh is complete.
* All resetController, beforeModel, model, afterModel, redirect, and setupController
* hooks will be called again. You will get new data from the model hook.
*
* @method refresh
* @param {String} [routeName] the route to refresh (along with all child routes)
* @return Transition
* @category EMBER_ROUTING_ROUTER_SERVICE_REFRESH
* @public
*/
refresh(pivotRouteName?: string) {
if (!pivotRouteName) {
return this._router._routerMicrolib.refresh();
}

assert(`The route "${pivotRouteName}" was not found`, this._router.hasRoute(pivotRouteName));
assert(
`The route "${pivotRouteName}" is currently not active`,
this.isActive(pivotRouteName)
);

let pivotRoute = getOwner(this).lookup(`route:${pivotRouteName}`) as Route;

return this._router._routerMicrolib.refresh(pivotRoute);
},
});
}

RouterService.reopen(Evented, {
/**
Name of the current route.
Expand Down
4 changes: 4 additions & 0 deletions packages/@ember/canary-features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export const DEFAULT_FEATURES = {
EMBER_MODERNIZED_BUILT_IN_COMPONENTS: true,
EMBER_STRICT_MODE: true,
EMBER_DYNAMIC_HELPERS_AND_MODIFIERS: true,
EMBER_ROUTING_ROUTER_SERVICE_REFRESH: null,
};

/**
Expand Down Expand Up @@ -81,3 +82,6 @@ export const EMBER_STRICT_MODE = featureValue(FEATURES.EMBER_STRICT_MODE);
export const EMBER_DYNAMIC_HELPERS_AND_MODIFIERS = featureValue(
FEATURES.EMBER_DYNAMIC_HELPERS_AND_MODIFIERS
);
export const EMBER_ROUTING_ROUTER_SERVICE_REFRESH = featureValue(
FEATURES.EMBER_ROUTING_ROUTER_SERVICE_REFRESH
);
100 changes: 100 additions & 0 deletions packages/ember/tests/routing/router_service_test/refresh_test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Route } from '@ember/-internals/routing';
import { EMBER_ROUTING_ROUTER_SERVICE_REFRESH } from '@ember/canary-features';
import { RouterTestCase, moduleFor } from 'internal-test-helpers';

if (EMBER_ROUTING_ROUTER_SERVICE_REFRESH) {
moduleFor(
'Router Service - refresh',
class extends RouterTestCase {
async ['@test RouterService#refresh can be used to re-run the model hooks of active routes'](
assert
) {
let parentCounter = 0;
this.add(
'route:parent',
class extends Route {
model() {
++parentCounter;
}
}
);

let childCounter = 0;
this.add(
'route:parent.child',
class extends Route {
model() {
++childCounter;
}
}
);

let sisterCounter = 0;
this.add(
'route:parent.sister',
class extends Route {
model() {
++sisterCounter;
}
}
);

await this.visit('/');
assert.equal(parentCounter, 1);
assert.equal(childCounter, 0);
assert.equal(sisterCounter, 0);

await this.routerService.refresh();
assert.equal(parentCounter, 2);
assert.equal(childCounter, 0);
assert.equal(sisterCounter, 0);

await this.routerService.refresh('application');
assert.equal(parentCounter, 3);
assert.equal(childCounter, 0);
assert.equal(sisterCounter, 0);

await this.routerService.transitionTo('parent.child');
assert.equal(parentCounter, 3);
assert.equal(childCounter, 1);
assert.equal(sisterCounter, 0);

await this.routerService.refresh('parent.child');
assert.equal(parentCounter, 3);
assert.equal(childCounter, 2);
assert.equal(sisterCounter, 0);

await this.routerService.refresh('parent');
assert.equal(parentCounter, 4);
assert.equal(childCounter, 3);
assert.equal(sisterCounter, 0);

await this.routerService.transitionTo('parent.sister');
assert.equal(parentCounter, 4);
assert.equal(childCounter, 3);
assert.equal(sisterCounter, 1);

await this.routerService.refresh();
assert.equal(parentCounter, 5);
assert.equal(childCounter, 3);
assert.equal(sisterCounter, 2);
}

async ['@test RouterService#refresh verifies that the provided route exists']() {
await this.visit('/');

expectAssertion(() => {
this.routerService.refresh('this-route-does-not-exist');
}, 'The route "this-route-does-not-exist" was not found');
}

async ['@test RouterService#refresh verifies that the provided route is active']() {
await this.visit('/');

expectAssertion(() => {
this.routerService.refresh('parent.child');
}, 'The route "parent.child" is currently not active');
}
}
);
}

0 comments on commit bff7766

Please sign in to comment.