-
Notifications
You must be signed in to change notification settings - Fork 3k
Need ability to get updated resolve values in uiOnParamsChanged() #3210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
This proposal has been brought up previously. It's a pretty dramatic departure from the core workings of ui-router. Especially with your desire to only re-fetch "some of the resolves". I've given it some thought over the last year and my conclusion is that this change would be very intrusive to the code, and would be a huge paradigm shift for users (although it could potentially be made opt-in only) I also think that Observables are a great existing solution for this approach. In a resolve, return an Observable which fetches data based on a dynamic parameter. When the parameter changes, the observable emits a new object. The Observable is resolved once, and your component can respond to the changes. If a different (non-dynamic) parameter value changes, the entire state can still be reloaded and all other resolves re-fetched. There's one key piece missing (which is easy to add yourself): the parameter values themselves should be exposed as an observable in a top-level resolve. I've started working on this rx integration. The ng2 version currently has this code embedded, but I will be publishing this as a Plugin at http://github.com/ui-router/rx by the time ui-router-ng2 is released as 1.0. To use this you'd have a state something like: .state('mystate', {
resolve: {
userObs: ($transition$, UserService) => {
let params$ = $transition$.router.globals.params$;
return params$.map(x => x.userId)
.distinctUntilChanged()
.map(id => UserService.get(id))
}
},
component: 'user'
} .component('user', {
bindings: { 'userObs': < },
template: '<h2>{{ $ctrl.user.name }}</h2>',
controller: function($scope) {
this.$onInit = () => {
this.userObs.subscribe((user) => this.user = user);
$scope.$on("$destroy", () => this.userObs.unsubscribe());
}
} |
Thank you, @christopherthielen, for your help! However, the main feature I'm searching for is managing complex resolve trees, when one resolve depends on the results of other resolves, like in my example PS. For me, it would be perfectly ok, if ALL of the resolves got re-evaluated (not just "some of them", as you have mentioned in your comment). |
There is not currently a way, without also reloading the views. This is because resolve data has generally been injected into controllers which happens when the views are loaded. It's theoretically possible to wire ui-router to retain views for views that are reloading and probably a way to tell the views about new resolve data. However, this is out of scope for main codebase. If you want to take a shot at implementing something like this, I can guide you. However, you will have to dig into the ui-router architecture quite a bit and customize the interactions. |
As a starting point, I think it would be enough if the user simply had an opportunity to manually fire the resolve process and get the new resolve values without affecting other parts of the application (no view/controllers reloads). Passing the new resolve values into uiOnParamsChanged might be a next step. I'd like to try to implement that and I'd be really grateful for your guidance. Where should I start from? |
You can manually invoke resolves yourself using a combination of let's say you want to invoke all resolves for the path of states let $state = $uiRouter.stateService;
let $registry = $uiRouter.stateRegistry;
let barstate = $state.get('home.foo.bar').$$state();
let pathAsNodes = barstate.path.map(x => new PathNode(x));
let resolveContext = new ResolveContext(pathAsNodes);
resolveContext.injector().getAsync('barData').then(data => {
console.log("Got this bar data: " + data)
});
// or tell all resolves in the path to load:
resolveContext.resolvePath().then(results => {
console.log("I got this resolve data: ", results);
console.table(results);
}); plunker: http://plnkr.co/edit/Unc2X8uBftBlCAwRip81?p=preview |
Thank you @christopherthielen! I've finally achieved what I needed. In case someone is looking for how to implement it, here is my code inside the controller (in Typescript):
Now it seems to be quite easy to use, so I doubt if there is any sense in simplifying this somehow. Closing this issue for now. |
Another issue has appeared regarding this. This dynamic state has got a child state, which needs to access the actual value of one of the parent state's resolves. However if I add a uiOnParamsChanged member to the child controller, it never gets fired. Please note that the scope are not inherited, so just grabbing the actual value from $scope.folders is not an option. Any ideas on how to fix this and/or let the child controller get the actual value of a parent controller's resolve? |
note: I believe the uiOnParamsChanged callback for the child should get invoked |
This issue has been automatically marked as stale because it has not had This does not mean that the issue is invalid. Valid issues Thank you for your contributions. |
My state definition goes like this:
Now, inside my
ProjectsViewController
, I setWhen a
folderId
state param value changes, the url gets updated, the controller doesn't get reloaded anduiOnParamsChanged
is called, which is all perfect!But, inside the
uiOnParamsChanged
function,breadcrumbs
value is not the new updated value but instead it is just the same value it was before the folderId change. This might be exactly what everyone expects in most cases, but it would be really great if we could somehow trigger the state resolves to be re-resolved (perhaps only some of them) and passed to uiOnParamsChanged.Please note that my resolve system is quite complex (e.g.,
folderActiveFn
resolve depends onfolderBreadcrumbs
value), and I wouldn't really want to move all of the resolves into the controller, given that ui-router already has an excellent resolve managing infrastructure that only needs to be exposed somehow.I'm using v1.0.0-beta.3
The text was updated successfully, but these errors were encountered: