Skip to content

Commit

Permalink
Ensure the afterLoad method gets called bound to controller (#658)
Browse files Browse the repository at this point in the history
- Fixes #652

Co-authored-by: LB Johnston <lb.johnston@virginaustralia.com>
  • Loading branch information
lb- and LB Johnston committed Feb 13, 2023
1 parent 3f6a698 commit f7bfc35
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 7 deletions.
6 changes: 4 additions & 2 deletions docs/reference/controllers.md
Expand Up @@ -169,13 +169,15 @@ If you want to trigger some behaviour once a controller has been registered you

```js
class SpinnerButton extends Controller {
static legacySelector = ".legacy-spinner-button"

static afterLoad(identifier, application) {
// use the application instance to read the configured 'data-controller' attribute
const { controllerAttribute } = application.schema

// update any legacy buttons with the controller's registered identifier
const updateLegacySpinners = () => {
document.querySelector(".legacy-spinner-button").forEach((element) => {
document.querySelector(this.legacySelector).forEach((element) => {
element.setAttribute(controllerAttribute, identifier)
})
}
Expand All @@ -193,7 +195,7 @@ class SpinnerButton extends Controller {
application.register("spinner-button", SpinnerButton)
```

The `afterLoad` method will get called as soon as the controller has been registered, even if no controlled elements exist in the DOM. It gets called with the `identifier` that was used when registering the controller and the Stimulus application instance.
The `afterLoad` method will get called as soon as the controller has been registered, even if no controlled elements exist in the DOM. The function will be called bound to the original controller constructor along with two arguments; the `identifier` that was used when registering the controller and the Stimulus application instance.

## Cross-Controller Coordination With Events

Expand Down
2 changes: 1 addition & 1 deletion src/core/router.ts
Expand Up @@ -57,7 +57,7 @@ export class Router implements ScopeObserverDelegate {
this.connectModule(module)
const afterLoad = (definition.controllerConstructor as any).afterLoad
if (afterLoad) {
afterLoad(definition.identifier, this.application)
afterLoad.call(definition.controllerConstructor, definition.identifier, this.application)
}
}

Expand Down
20 changes: 16 additions & 4 deletions src/tests/modules/core/loading_tests.ts
Expand Up @@ -13,12 +13,20 @@ class LoadableController extends LogController {
}

class AfterLoadController extends LogController {
static values = {
example: { default: "demo", type: String },
}

static afterLoad(identifier: string, application: any) {
const newElement = document.createElement("div")
newElement.classList.add("after-load-test")
newElement.setAttribute(application.schema.controllerAttribute, identifier)
application.element.append(newElement)
document.dispatchEvent(new CustomEvent("test", { detail: { identifier, application } }))
document.dispatchEvent(
new CustomEvent("test", {
detail: { identifier, application, exampleDefault: this.values.example.default, controller: this },
})
)
}
}

Expand All @@ -37,22 +45,26 @@ export default class ApplicationTests extends ApplicationTestCase {

"test module with afterLoad method should be triggered when registered"() {
// set up an event listener to track the params passed into the AfterLoadController
let data: { application?: any; identifier?: string } = {}
let data: { application?: any; identifier?: string; exampleDefault?: string; controller?: any } = {}
document.addEventListener("test", (({ detail }: CustomEvent) => {
data = detail
}) as EventListener)

this.assert.equal(data.identifier, undefined)
this.assert.equal(data.application, undefined)
this.assert.equal(data.controller, undefined)
this.assert.equal(data.exampleDefault, undefined)
this.assert.equal(data.identifier, undefined)

this.application.register("after-load", AfterLoadController)

// check the DOM element has been added based on params provided
this.assert.equal(this.findElements('[data-controller="after-load"]').length, 1)

// check that static method was correctly called with the params
this.assert.equal(data.identifier, "after-load")
this.assert.equal(data.application, this.application)
this.assert.equal(data.controller, AfterLoadController)
this.assert.equal(data.exampleDefault, "demo")
this.assert.equal(data.identifier, "after-load")
}

get controllers() {
Expand Down

0 comments on commit f7bfc35

Please sign in to comment.