# Create Instance of controller from a controller

**URL:** <https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351>\
**Category:** General\
**Created:** [August 5, 2022, 10:09am UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351 "2022-08-05T10:09:10Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![ffwd-david](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/ffwd-david/32/2847_2.png) [@ffwd-david](https://discuss.hotwired.dev/u/ffwd-david)\
**Post date:** [August 5, 2022, 10:09am UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/1 "2022-08-05T10:09:10Z")

</div>

Hello everybody,

I just stared using stimulus and I’m having some trouble, converting my existing javascript to stimulus.

I have a class A that does things and a class B that does things.  
In class A an instance of class B is created with some params.

So I wrote class A as a stimulus controller, which works just finde. But I integrated class B in that. Now I want to have class B as a separate controller and call it from that A stimulus controller. I have no idea how to do that.

I cannot use events, since there are no events that trigger my script. The controller A does its job when it’s initialized.

Hope I can get some help. Thank you

David

---

<div class="post-metadata">

**Author:** ![rockwell](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/rockwell/32/1884_2.png) [@rockwell](https://discuss.hotwired.dev/u/rockwell)\
**Post date:** [August 5, 2022, 8:44pm UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/2 "2022-08-05T20:44:50Z")

</div>

> [@ffwd-david](#):
>
> I cannot use events, since there are no events that trigger my script. The controller A does its job when it’s initialized.

You can definitely use events. Events are the way to go in your case. And, it’s pretty easy to listen and dispatch events with stimulus. Let’s follow along with your case and create the classes.

```auto
class A extends Controller {
    initialize() {
       this.dispatch("custom-event-from-a-class", { 
        target: document.documentElement,
        data: { 
          // data you want to send to class B
         }
       })
    }
}

class B extends Controller {
  onClassAEvent({ data }) {
     // data dispatched from class A custom event
  }
}

```

Now, with the classes being set up. You want to “listen” for `custom-event-from-a-class` from `b` element. Let’s say your markup looks like this

```auto
<div data-controller="b" data-action="a:custom-event-from-a-class@window->b#onClassAEvent" />
<div data-controller="a" />

```

In the `b` element. We listen for a `a:custom-event-from-a-class` that targets the window via the `@window` descriptor. See [Global Events](https://stimulus.hotwired.dev/reference/actions#global-events)

when `a` controller dispatches it’s event. Every controller that has the `a:custom-event-from-a-class@window->b#onClassAEvent` would react to it.

Now, A and B controller can communicate together. And vice-versa is true. If you want to interact with A controller from B, you need to dispatch an event from B, and listen to the event inside A controller.

Hope this helps

---

<div class="post-metadata">

**Author:** ![ffwd-david](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/ffwd-david/32/2847_2.png) [@ffwd-david](https://discuss.hotwired.dev/u/ffwd-david)\
**Post date:** [August 6, 2022, 8:34am UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/3 "2022-08-06T08:34:56Z")

</div>

That was really helpful to understand the dispatch. Thank you.

Still it is a bit confusing to me.  
I found out that data-controller must in in the correct order, so data-controller=“a b” did not work, but data-controller=“b a” does. So far so good.

Now I don’t really get, what custom-event-from-a-class is there for… Code in custom-event-from-a-class is not executed that way. So at the moment it seems to be only helping for the dispatch (since I need a custom method, initialize doesn’t work).  
If I want code from custom-event-from-a-class to be executed I have to call it (from initialize)…

But the main issue now is, that I need the return value from B-\>onClassAEvent in A. How can I access the return value?

Thanks again for your help.

David

---

<div class="post-metadata">

**Author:** ![tleish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/tleish/32/920_2.png) [@tleish](https://discuss.hotwired.dev/u/tleish)\
**Post date:** [August 6, 2022, 3:28pm UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/4 "2022-08-06T15:28:44Z")

</div>

Does B also need to be a controller, or just a class referenced by controller A?

---

<div class="post-metadata">

**Author:** ![ffwd-david](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/ffwd-david/32/2847_2.png) [@ffwd-david](https://discuss.hotwired.dev/u/ffwd-david)\
**Post date:** [August 6, 2022, 7:57pm UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/5 "2022-08-06T19:57:51Z")

</div>

I don’t think it has to be a controller.  
It’s just a class, that checks if intersectionObserver is present and returns an instance if so, otherwise “false”. It gets 2 params: the callback and the observer options.

I just don’t know what’s the right way to instantiate it now, stimulus style 😬

---

<div class="post-metadata">

**Author:** ![tleish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/tleish/32/920_2.png) [@tleish](https://discuss.hotwired.dev/u/tleish)\
**Post date:** [August 6, 2022, 8:53pm UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/6 "2022-08-06T20:53:11Z")

</div>

It would help if you shared the code

---

<div class="post-metadata">

**Author:** ![ffwd-david](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/ffwd-david/32/2847_2.png) [@ffwd-david](https://discuss.hotwired.dev/u/ffwd-david)\
**Post date:** [August 6, 2022, 9:14pm UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/7 "2022-08-06T21:14:40Z")

</div>

```auto
export default class extends Controller {

    createObserver(callback, threshold, rootMargin) {

        this.observerCallback = callback ?? {};
        this.observerOptions = {
            root: null,
            threshold: threshold ?? 0,
            rootMargin: rootMargin ?? "0px 0px 0px 0px",
        };

        return this.checkIfObserver();
    };

    checkIfObserver() {

        if (!('IntersectionObserver' in window) ||
            !('IntersectionObserverEntry' in window) ||
            !('intersectionRatio' in window.IntersectionObserverEntry.prototype)) {

            return false;
        } else {
            return new IntersectionObserver(this.observerCallback, this.observerOptions);
        }
    };
}

```

that’s “B” … A is whatever needs this return value…  
Don’t think, this needs to be a controller, since I don’t use it as such. I just need it for other classes to call it. I jus want it to integrate the way it’s supposed to in stimulus…

---

<div class="post-metadata">

**Author:** ![tleish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/tleish/32/920_2.png) [@tleish](https://discuss.hotwired.dev/u/tleish)\
**Post date:** [August 7, 2022, 12:12am UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/8 "2022-08-07T00:12:59Z")

</div>

If I understand correctly, you can use javascript modules

```auto
// utils/createObserver.js
import IntersectionObserver from 'intersection-observer'

export default function createObserver(callback, threshold, rootMargin) {
    const observerCallback = callback ?? {};
    const observerOptions = {
      root: null,
      threshold: threshold ?? 0,
      rootMargin: rootMargin ?? "0px 0px 0px 0px",
    };

    return checkIfObserver(observerCallback, observerOptions);
};

function checkIfObserver(callback, options) {
  if (!('IntersectionObserver' in window) ||
    !('IntersectionObserverEntry' in window) ||
    !('intersectionRatio' in window.IntersectionObserverEntry.prototype)) {

    return false;
  } else {
    return new IntersectionObserver(callback, options);
  }
}

```

Then you import into your controller

```auto
// utils/my_controller.js
import createObserver from 'utils/createObserver'

export default class extends Controller {
  connect() {
    this.observer = createObserver(... )
  }
}

```

---

<div class="post-metadata">

**Author:** ![ffwd-david](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/ffwd-david/32/2847_2.png) [@ffwd-david](https://discuss.hotwired.dev/u/ffwd-david)\
**Post date:** [August 7, 2022, 9:45am UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/9 "2022-08-07T09:45:59Z")

</div>

Ok thank you.  
If I understand correctly, there is no special “stimulus way” to integrate this. I’m ending up, keeping my original observer class and creating a regular instance in my controller:

```auto
export class Observer {

    constructor(observerCallback, observerOptions) {
        this.callback = observerCallback ?? function() {};
        this.options = observerOptions ?? {
            root: null,
            threshold: 0,
            rootMargin: "0px, 0px, 0px, 0px",
        };

        return this.checkIfObserver();
    };

    checkIfObserver() {

        if (!('IntersectionObserver' in window) ||
            !('IntersectionObserverEntry' in window) ||
            !('intersectionRatio' in window.IntersectionObserverEntry.prototype)) {

            return false;
        } else {
            return new IntersectionObserver( this.callback, this.options);
        }
    };
}

```

and

```auto
import {Controller} from '@hotwired/stimulus';
import {Observer} from './observer.js'

export default class extends Controller {
    initialize() {
    this. this.observerCallback = ... ;
    this.observerOptions = ... ;
        const observer = new Observer(this.observerCallback, this.observerOptions);
    ...
    }
}

```

---

<div class="post-metadata">

**Author:** ![tleish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/tleish/32/920_2.png) [@tleish](https://discuss.hotwired.dev/u/tleish)\
**Post date:** [August 7, 2022, 3:22pm UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/10 "2022-08-07T15:22:04Z")

</div>

Correct. I will mention a couple of additional things.

If the element assigned the controller might be removed and reinitialized in the DOM, you may want to use connect() instead of initialize().

If you are also using turbo (which acts like an SPA), you want to be careful of memory leaks caused by listeners and observers. To avoid memory leaks, add disconnect() to the stimulus controller with code that removes the listeners or observers.

---

<div class="post-metadata">

**Author:** ![ffwd-david](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/ffwd-david/32/2847_2.png) [@ffwd-david](https://discuss.hotwired.dev/u/ffwd-david)\
**Post date:** [August 7, 2022, 4:23pm UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/11 "2022-08-07T16:23:23Z")

</div>

First of all thank you so much for helping me understand stimulus!

> you may want to use connect() instead of initialize().

yes, I read about that in the docs. So far initialize does the job for me.

> If you are also using turbo

Turbo is actually the reason I started having a look into stimulus. Turbo killed my JavaScripts ( 🥳) … so I wanted to start understanding what stimulus does etc.

Still not sure I really need / should use stimulus or turbo. Especially turbo seems “dangerous”… But I will try a few things and see what happens…

---

<div class="post-metadata">

**Author:** ![tleish](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/tleish/32/920_2.png) [@tleish](https://discuss.hotwired.dev/u/tleish)\
**Post date:** [August 7, 2022, 6:20pm UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/12 "2022-08-07T18:20:15Z")

</div>

In the past I tried using TurboLinks (now Turbo) several times, each time I ran into enough issues which caused me to give up. It wasn’t until recently that I realized why.

Turbo Drive caches pages using HTML. Since most JavaScript libraries persist data in memory, this can cause weird behavior with turbo caching.

Stimulus easily persists data in HTML (data attributes). This is why stimulus works so well with Turbo. With stimulus you can also wrap libraries which save data in memory to store data in html.

Once I started using stimulus and understood how turbo worked, the entire Hotwire stack worked really well and no longer felt brittle. In fact, for me it feels more robust than the majority of the SPA frameworks out there.

Best of luck.

---

<div class="post-metadata">

**Author:** ![ffwd-david](https://yyz1.discourse-cdn.com/flex027/user_avatar/discuss.hotwired.dev/ffwd-david/32/2847_2.png) [@ffwd-david](https://discuss.hotwired.dev/u/ffwd-david)\
**Post date:** [August 8, 2022, 11:30am UTC](https://discuss.hotwired.dev/t/create-instance-of-controller-from-a-controller/4351/13 "2022-08-08T11:30:55Z")

</div>

Thanks so much for your help and sharing your experience. I’m definitely eager to learn more about stimulus and turbo. I’ll keep testing it. I’m certain I’ll ask for advice here again 😄
