Skip to content
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

1.0 - how can we register hooks in a controller? #2523

Closed
jpodpro opened this issue Feb 4, 2016 · 8 comments
Closed

1.0 - how can we register hooks in a controller? #2523

jpodpro opened this issue Feb 4, 2016 · 8 comments
Labels

Comments

@jpodpro
Copy link

jpodpro commented Feb 4, 2016

i think i understand that hooks are ideally registered in a module's config section by $transitionsProvider.

however, what happens when the hook handler function requires access to controller functions or properties? in this case, using $transitions to register a hook in the controller, the hook is registered for each load of the controller and ends up firing the same handler multiple times.

can someone explain how to register a hook whose handler has access to a controller?

@christopherthielen
Copy link
Contributor

I'd like to hear about your specific use case. What hook do you want to register, that has access to the controller code? Is it a "can the state be deactivated" type of hook, or something else?

I've been pondering solutions for "can deactivate"


In the sample app, I used a resolve object which acts as an API bridge between the hooks and the controllers (note: each state can have multiple views/controllers), but I'm not happy with the implementation. We've got a checklist item in #2223 to provide an exit hook integrated with the controller before beta.

https://github.com/ui-router/sample-app/blob/master/app/mymessages/compose.state.js#L16-L26

https://github.com/ui-router/sample-app/blob/master/app/mymessages/compose.component.js#L38-L41

@jpodpro
Copy link
Author

jpodpro commented Feb 5, 2016

in my case i have a menu directive. in the old version of ui-router, i listened for state changes in the directive's controller in order to call a controller function that would update the active menu item. using 1.0 i cannot put the onSuccess hook in the controller because every time i load another page using this menu directive the hook is registered again and proceeds to call the controller function multiple times - one for every time a page using this directive is loaded. however, no where else has access to the setMenuState controller function.

$transitions.onSuccess( { to: 'profilePage.*.*' }, function( $state, $transition$ )
{
    console.log( 'new menu state: ', $transition$.to().name );
    setMenuState( $transition$.to().name );
});

@jpodpro
Copy link
Author

jpodpro commented Feb 7, 2016

if i'm understanding this incorrectly please let me know. but i find it extremely surprising/confusing that 1.0 essentially breaks the ability to properly capture state changes in controllers. isn't this the only place to listen for them using the current event-based architecture? please help me understand how hooks are able to replace listening for state change events because i don't see any viable connection that doesn't have the repeating hook registration problem.

@christopherthielen
Copy link
Contributor

It looks like you are reimplementing ui-sref-active in a custom menu directive?


I felt this pain as well when implementing ui-sref-active in 1.0. The one nice thing that the state events had going for them was auto deregistration when scope destroys. In all other ways they were inferior.

The return value of a hook registration is a deregistration function. You can use this and $destroy event to deregister like I'm doing in ui-sref. Not ideal, agreed.
https://github.com/angular-ui/ui-router/blob/feature-1.0/src/ng1/stateDirectives.ts#L333-L335

Feel free to use stateEvents.js or make your own event (register a global hook that listens for onsuccess and broadcasts the custom event).

@jpodpro
Copy link
Author

jpodpro commented Feb 7, 2016

this menu has custom behavior that requires controller code to run on state transition. it behaves as a styled dropdown so whatever sub-item is selected is shown at the top.

at any rate i've come to the fairly simple and painless solution of de-registering the hook when the controller scope is destroyed. thanks for the guidance.

$scope.$on( '$destroy', function()
{
    // ensure transition hook is de-registered
    if( deregisterTransitionHook )
    {
        deregisterTransitionHook();
    }
});

@jpodpro jpodpro closed this as completed Feb 7, 2016
@christopherthielen
Copy link
Contributor

@jpodpro I appreciate your feedback. 1.0 is still in alpha. I need to hear from people where the API pain points are and what use cases they are trying to implement.

@Milananas
Copy link

Any news on this issue? I'm experiencing a very specific case in which this causes problems as well. The deregister method is an option, however not the ideal way to go I'd say.

@christopherthielen
Copy link
Contributor

@Milananas depending on what kind of hook you are writing, maybe you can use uiCanExit.

It's called whenever the state that owns the component is being exited, and the hook is registered/deregistered automatically.

Otherwise, an easy way to deregister is like so:

function myHook(transition) {
...
}

$scope.$on('$destroy', $transitions.onStart({}, myHook));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants