-
Notifications
You must be signed in to change notification settings - Fork 27.4k
feat($route): add support for the reloadOnUrl
configuration option
#15002
Conversation
I am not super happy with the API ( reloadOnChange: {
hash: true/false,
search: true/false,
url: true/false
} But at this point I figured it is better to (a) keep consistent with the existing API and (b) not introduce multiple way to do the same thing. But we might want to consider deprecating the existing way and introducing a different API in a future version. |
Btw, in the future we might want to make this more flexible by allowing the user to specify a function (or service) for determining whether to reload or not. This would allow to have a default value for the route, but overwrite it in specific cases. |
Both features where the original reason for @davidreher and me to choose the now deprecated ngComponentRouter. We would love to see see these features added to ngRoute! |
Also, considering that Angular 2's latest router re-uses components by default (afaik), it might be a good idea to re-use components by default as well (for 1.6 or 1.7). |
So this PR is basically a sub-set of the old problem where you wan't to change the location but not let Angular do anything (like change / reload a route).
If the route never reloads on url change, if you do /thing/5678, then it also doesn't change the route, and you'd have to manually do work in the routeUpdate event (e.g. fetching data), instead of relying on resolves. So I think we either need a $location function that doesn't trigger route change (don't really like that, though) or a dynamic way to decide if a route should be reloaded. Another idea is to keep the template / DOM and re-run the resolves, and push the new data to the scope, so any components could handle data changes via onChanges or similar. This might be too much for vanilla ngRoute though. |
This doesn't indeed cover #3789 (in a convenient way), but that sounds better handled with a redirection tbh. Regarding #1699, I think this PR covers their exact usecase: You are on --
Taking (2) one step further, we could introduce a new --
In general, I believe |
748cb40
to
4f54a92
Compare
Any updates on this? |
@miwillhite No, not at the moment. Btw, does ui-router have this functionality? |
4f54a92
to
96c71b0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few smaller things.
The avanced API outlined in the PR would have been nice, but I assume that most people use uiRouter anyway at this point.
src/ngRoute/route.js
Outdated
* If the option is set to `false` and the URL in the browser changes, then a `$routeUpdate` | ||
* event is broadcasted on the root scope (without reloading the route). | ||
* | ||
* **Note:** This option has no effect if `reloadOnUrl` is set to false. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be more prominent, i.e. wrap it into a note block
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrapped.
src/ngRoute/route.js
Outdated
@@ -544,8 +556,9 @@ function $RouteProvider() { | |||
* @name $route#$routeUpdate | |||
* @eventType broadcast on root scope | |||
* @description | |||
* The `reloadOnSearch` property has been set to false, and we are reusing the same | |||
* instance of the Controller. | |||
* Any of the `reloadOnSearch` and `reloadOnUrl` properties has been set to false and we are |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would change this to something like `This event is fired if we are reusing the same instance ... because any of ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rephrased.
src/ngRoute/route.js
Outdated
preparedRouteIsUpdateOnly = preparedRoute && lastRoute && preparedRoute.$$route === lastRoute.$$route | ||
&& angular.equals(preparedRoute.pathParams, lastRoute.pathParams) | ||
&& !preparedRoute.reloadOnSearch && !forceReload; | ||
preparedRouteIsUpdateOnly = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be even more readable if it was in a separate fnction
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Functionized.
test/ngRoute/routeSpec.js
Outdated
}); | ||
}); | ||
|
||
|
||
describe('reload', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this describe be a bit more explicit? There's already a top-level describe with this name. How about with reload()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see a top-level describe
with the same name 😕.
But I agree the descriptions are not great (I copied them from the existing reloadOnSearch
tests 😳).
I've updated both to with `$route.reload()`
(since they are testing how the configs work in conjuction with $route.reload()
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I didn't see the reload() block was in reloadOnSearch
test/ngRoute/routeSpec.js
Outdated
it('should reload a route when reloadOnSearch is enabled and .search() changes', function() { | ||
var reloaded = jasmine.createSpy('route reload'); | ||
describe('reloadOnUrl', function() { | ||
it('should reload a route when `reloadOnUrl` is enabled and `.url()` changes', function() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The wording is inconsistent in the changes - mostly it's enabled
but further below it's true
(I prefer the latter).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made consistent.
Thx, @Narretz! |
I think you forgot to push the changes @gkalpak 👀 |
96c71b0
to
daec562
Compare
Ooops 😳 Definitely pushed now 😃 |
LGTM - maybe @petebacondarwin should take another look? |
$httpBackend.when('GET', 'bar.html').respond('bar'); | ||
$httpBackend.when('GET', 'baz.html').respond('baz'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this change have any effect?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No afaict 😁
(Except for ordering definitions in proper foo-bar-baz order, which is as great an effect as a change can have 😇)
|
||
inject(function($location, $rootScope, $routeParams) { | ||
$rootScope.$on('$routeChangeStart', routeChange); | ||
$rootScope.$on('$routeChangeSuccess', routeChange); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: if we care to test that both these are being triggered then they should have different spies. Otherwise we don't know that only one of the events is being triggered twice rather than each being triggered only once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have other tests to verify that these are called correctly on route change.
Here we mainly want to verify that the routeChangeStart/Success
combo is emitted and routeUpdate
isn't.
expect(routeChangeSuccess).toHaveBeenCalledOnce(); | ||
expect($log.debug.logs).toEqual([['initialized']]); | ||
|
||
$log.reset(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed
expect($log.debug.logs).toEqual([['initialized']]); | ||
expect($routeParams).toEqual({param: 'bar'}); | ||
|
||
$log.reset(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, these calls are needed, because there is an afterEach()
call that asserts the log is empty:
$log.assertEmpty(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Weird because I thought there are other tests that do not call $log.reset()
at the end but do cause logging...
By calling reset we are preventing the afterEach
from checking that other logs were not posted. In any case this is a bit counter-intuitive. Perhaps we should have a helper that checks the log and then removes that item?
test/ngRoute/routeSpec.js
Outdated
); | ||
|
||
|
||
it('should reload when `reloadOnSearch` is true and url differs only in route path param', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'should reload when reloadOnSearch
is true false and ...' ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Few minor nits but OLGTM
Enables users to specify that a particular route should not be reloaded after a URL change (including a change in `$location.path()`), if the new URL maps to the same route. The default behavior is still to always load the matched route when any part of the URL changes. Related to angular#1699, angular#5860, angular#14999 (potentially closing the first two). Fixes angular#7925
daec562
to
956c727
Compare
Fixed up and rebased. |
956c727
to
a9b6b21
Compare
Enables users to specify that a particular route should not be reloaded after a URL change (including a change in `$location.path()`), if the new URL maps to the same route. The default behavior is still to always load the matched route when any part of the URL changes. Related to #1699, #5860, #14999 (potentially closing the first two). Fixes #7925 Closes #15002
What kind of change does this PR introduce? (Bug fix, feature, docs update, ...)
Feature.
What is the current behavior? (You can also link to an open issue here)
When the path changes and the new URL maps to the current route, the route is reloaded.
See #14999 (and some of the issues mentioned there).
What is the new behavior (if this is a feature change)?
The user can determine that specific routes should not get reloaded, when the path changes and the new URL maps to the current route.
Does this PR introduce a breaking change?
No.
Please check if the PR fulfills these requirements
Other information:
Enables users to specify that a particular route should not be reloaded after a URL change
(including a change in
$location.path()
), if the new URL maps to the same route.The default behavior is still to always load the matched route when any part of the URL changes.
Related to #1699, #5860, #14999 (potentially closing the first two).
Fixes #7925.