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

Feature request - Controller registration (load) callback #574

Closed
lb- opened this issue Aug 17, 2022 · 6 comments
Closed

Feature request - Controller registration (load) callback #574

lb- opened this issue Aug 17, 2022 · 6 comments

Comments

@lb-
Copy link
Contributor

lb- commented Aug 17, 2022

Summary

When a controller is registered (aka loaded), it would be helpful to provide the ability for the controller (class) to be able to provide a callback to know it has been registered and with what identifier.

Details

  • There are cases where the controller may want to cause some side effects (mutate DOM, load some expensive JS, check something in the application) once it has been registered. Without having to wait for the first 'connect' instance method bring called.
  • The shoudLoad static get method can kind of serve this purpose but this has no access to the application instance, nor the identifier string that the controller has been registered with.
  • This becomes very useful when providing controllers as a standalone package - the controller will not be able to know the application (schema, logger, Dom element attached to) nor the identifier name used. Nor will the controller really be able to know that an instance of it will ever be created, but may want to do some setup or logic once registered.
  • Long term, an unregister static method could also be supported.
  • I am happy to work on implementation of this feature if it seems useful to others.

Example usage - adding support for the controller to bootstrap its own usage for classes triggering

  • Provide a way to trigger some behaviour once the controller has been registered with an application.
  • In the case below we want to find any legacy usage of classes that do not yet have the new data controller code and attach a controller.
  • We also need to know the application's controller attribute name so that this code can work for any custom schema
class SpinnerButton extends Controller {
  static register(identifier, application) {
    // Add check for Dom state ready ...
   document.querySelctor('.button.spinner').forEach(elem => {
    elem.setAttribute(application.schema.controllerAttribute, identifier);
   });
  }
}

Example usage - side effects before DOM is ready

  • A controller may have some behaviour that is associated with it but must be set before the Dom is ready for a better user experience
  • This is an example of a dark mode toggle controller where it will run some code as soon as possible once registered.
  • it also relies on the identifier to prepare a usage specific session storage key
class DarkModeToggleButton extends Controller {
  static register(identifier, application) {
     // do not check for DOM ready - as we do not want a flash of content
     const savedThemeMode = localStorage.getItem(`${identifier}-theme');
    const prefersDarkMode = window.matchMedia(
      "(prefers-color-scheme:dark)"
    ).matches;
    console.log('apply saved or preferred dark mode');
  }

  constructor() {
    this.storageKey = `${this.identifier}-theme';
  }

  toggle() {
     document.body.class = ''; 
     // Toggle dark mode' class & update session storage. 
  }
}

Alternative approaches

  • Do nothing, the controller should not have any knowledge of itself outside of an instance attached to an element.
  • Libraries should document a different approach and maybe a function that you pass in the identifier and application and get back a controller class to be registered.
  • Put these side effects in the module definition - when the module is imported - it will run what it needs to.then. However, you won't have any access to the application or identifier.
  • Use shouldLoad for side effects - it's good enough for this and works today - except you won't have access to identifier or application.
@lb-
Copy link
Contributor Author

lb- commented Aug 19, 2022

Updated with another example encountered today for a dark mode button. We need to ensure some code runs as soon as possible (before DOM ready) once we know the identifier used.

Also added some 'alternative' work around or approaches.

@marcoroth
Copy link
Member

Thank you for opening this feature request!

I kinda like the idea of having a static register() controller built into Stimulus.

@lb-
Copy link
Contributor Author

lb- commented Aug 19, 2022

Maybe afterLoad or beforeLoad (depending on code flow) should be the name.

Kind of aligns with the existing name shouldLoad a bit better and is a bit clearer.

@lb- lb- changed the title Feature request - Controller registration callback Feature request - Controller registration (load) callback Aug 19, 2022
@marcoroth
Copy link
Member

Yeah, I was also thinking about that. The function which adds a controller to the application is called register():

application.register("hello", HelloController)

And this is the function we want the after callback from. In hindsight shouldLoad probably should have been shouldRegister.

@lb-
Copy link
Contributor Author

lb- commented Aug 30, 2022

Please let me know if this is something you would like to see a PR for. Happy to get one together.

@marcoroth
Copy link
Member

Please do, I'm happy to get this moving! Thank you! 🙏🏼

lb- pushed a commit to lb-/stimulus that referenced this issue Aug 30, 2022
- when a controller is registered, the `afterLoad` static method, if present, will be called
- it gets passed the application instance and the identifier that was used to register it
- resolves hotwired#574
lb- added a commit to lb-/stimulus that referenced this issue Oct 3, 2022
- when a controller is registered, the `afterLoad` static method, if present, will be called
- it gets passed the application instance and the identifier that was used to register it
- resolves hotwired#574
@dhh dhh closed this as completed in 2fdac1a Nov 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants