How to use Event Aggregator as Transient with Custom Element?

Dont wanna be the boo man here but one of your i18n related unit tests failed for me when i cloned your repo. Guess its because of different timezones.

1 Like

Haha yeah I had some date check failed at some point on CircleCI, which I donā€™t know what TZ they use. I might have hacked a test or two just to get it going on CircleCI. The date TZ stuff are not really big tests that I care. Anywho, you can maybe tell me which test that is and I can take a look to see if I can tweak it, thanks.

Iā€™m on the Eastern TimeZone (North America) and I know youā€™re on a different TZ.

1 Like

I think all youā€™d need to do for the tests is to fix the tz like here https://github.com/aurelia/i18n/blob/master/test/unit/dfvalueconverter.spec.ts#L64

2 Likes

You canā€™t ā€œnewā€ arrow function. It probably works with Jest because it was transpiled to ES5.
image

Just in case you hit it in the future

@bigopon
My Jest unit tests are all written in TypeScript, so I usually do it with the arrow function since the linter will complain if I donā€™t.

I have another issue though, I looked at your sandbox again and I understand how to have a global and a local instance of the Event Aggregator but how do I get access to the global one from my Services and from the Pagination child component? I have a few subscribed events when the I18N locale changed, and now they are all broken except for the ones that are in the parent component, for example the grid column headers are being translated because the code is in the parent component but the ones in the pagination component are no longer being translated because the injected EA is the local EA one. Is there a way to alias that or something? in the sandbox you did name it parent_not_global_Ea in the child component.

EDIT

After some digging in the Aurelia-I18N lib, I found that we can have access to itā€™s internal EA directly from the I18N Service with this.i18n.ea.subscribe('i18n:locale:changed', () => {}) and that will do it for my usage.

I still would like to know how to access both Global DI from Services or Child Component, but at least now I can work around it.

2 Likes

May I know why aliasing with NewInstance.of().as didnā€™t work for you? Itā€™s working for me here https://codesandbox.io/s/httpsdiscourseaureliaiothow-to-use-event-aggregator-as-transient-with-custom-element3181-o3e2b

Thanks, I did see the NewInstance.of().as() in the docs but I couldnā€™t find any examples in the docs neither online and the d.ts didnā€™t help either. When I tried it, I thought it was a string name aliasing as('string') but that didnā€™t work. I see you updated the sandbox and now I understand how to use it, it would help so much to have this in the docs. Does the aliased class have to have all the methods? Because I donā€™t see SlickgridEa being extended from EventAggregatorand itā€™s missing the dispose, does it have to be defined or that doesnā€™t matter?

Thanks again

1 Like

The purpose of alias is to alter the key required to retrieve an instance.

In this case, the flow is like this:

  • we want to retrieve an instance of EventAggregator, EventAggregator was used to inject the instance in Child via @inject(EventAggregator)
  • we want to scope an EventAggregator per instance of Parent, so we use NewInstance.of(EventAggregator)
  • we want to avoid scoping issue, since only Child wishes to get the scoped EventAggregator instance, while other Child_xs donā€™t. so we need another way to retrieve it without blocking others.
  • We used NewInstance.of().As(SlickGridEa) to scope EventAggregator and make it only retrievable via the alias SlickGridEa (https://github.com/aurelia/dependency-injection/blob/191d7d68cd0271a985178e770dd6b64d8cf9c418/src/resolvers.ts#L439). So SlickGridEa is basically is just a key to get our scoped EventAggregator instance, and provides strict typing for event name. What constructor that will actually be invoked is the EventAggregator
1 Like

Thanks again, Iā€™m starting to see the power of these DI wording. I rewrote all of my Services and Custom Elements to now use whichever I need and when I want both I now have

@inject(EventAggregator, SlickgridEventAggregator)

export MyClass {
  constructor(private globalEa: EventAggregator, private pluginEa: SlickgridEventAggregator) {}

This is powerful and awesome!

1 Like

Now I have yet another question, how do we extend the Event Aggregator from the at alias? This is following a new issue that Iā€™ve opened today in the Event Aggregator lib (this issue) which Rob replied here that I should extend the EA class

I tried changing the absctract class that you provided and change it into an extended class of the Event Aggregator but that doesnā€™t seem to work.

export class SlickgridEventAggregator extends EventAggregator {
  constructor() {
    super();
  }

  publish(event: string, data: any): void {
    // do something before calling super
    super.publish(event, data);
  }

  subscribe(event: string, callback: (data: any) => void): Disposable {
    // do something before calling super
    return super.subscribe(event, callback);
  }
}

I added a bunch of console log and nothing shows up, is that supposed to be only an abstract interface that I canā€™t extend? Sorry about all of these questions, I feel like I still have a lot to learn.

Probably because of what you wrote in previous post?

SlickGridEa is basically is just a key to get our scoped EventAggregator instance, and provides strict typing for event name. What constructor that will actually be invoked is the EventAggregator

1 Like

If you extended jt, then you can use the subclass as the key, or just inject the subclass. The only reason we went for aliasing was because we wanted to avoid conflict. Since you already have your own internal key (subclass), theres no need to do anything extra

Ok I was confused at first, but I think I understand now and that make sense, so if I understood correctly then you mean to change NewInstance.of(EventAggregator).as(SlickgridEventAggregator) into this NewInstance.of(SlickgridEventAggregator)and thereā€™s no need for alias since the class name is now unique. I tried it and that seems to work, so I think Iā€™m finally good now.

Thanks for everything, really appreciate your time in helping others like me :wink:

1 Like

Iā€™m glad we had this discussion, as we can finally have a Q/A topic that demonstrates:

  • how to scope a class to your plugin custom element
  • how to extend event aggregator and do your custom stuff (Non-existence, can you doc it here or somewhere please, my turn to ask for help :stuck_out_tongue:)

btw, if your constructor only call super then probably you donā€™t need it

1 Like

Ahh really, I thought it was required to call the super constructor so that it instantiate the class. I didnā€™t know we could go without it. I removed it like you said and pasted the remaining code in the issue I had previously opened.

Hmm Iā€™m not sure if Iā€™m the right person to explain it in docs, but I can try to help a bit yeah since you provided me lot of good information. What did you have in mind? Would that be to extend on this doc or something else? Iā€™m not even sure where the docs code is.

I do like the flow that we followed together, we covered lot of good stuff with DI and Event Aggregator, that certain flow might be explainable in a doc as a sample.

2 Likes

Yes, that section would be very useful, and our chat will be a very nice example for that

2 Likes

Hello @bigopon, Iā€™m not sure if this is what you wanted but I spent an hour writing this Event Aggregator - Use Cases Wiki. It has 4 unit cases, which were all related to our conversation. Iā€™ve created the Wiki under my Aurelia-Slickgrid lib, just for a placeholder, you can also edit the Wiki if you wish to adjust some of the text. Is that what you were looking for? I donā€™t think I used all the correct wording, so feel free to update.

4 Likes

Nice, looks pretty good to me. I was asking fornhelp with our official docnbut i guess that will do, i probably need to bookmark this for later to show as exmple for other similar Qs

1 Like

Thanks, it might be lengthy for a docā€¦ however the fact is that itā€™s the kind of doc I like to read, with brief use cases and some code samples to demo them.

2 Likes

Also just to provide more details about the kind of docs that I like to read, MDN (which is now used in VSCode intellisense for any html/css selector), they have wonderful docs that are super easy to understand with enough details, for instance see Array.prototype.filter(). They provide a set of use cases that are easy to understand, I see a lot of Stack Overflow references to their docs as well. They have the best docs Iā€™ve seen

in Aurelia we can find this tutorial adding pub/sub messaging which is similar in some ways, however I donā€™t think we need to provide a full and lengthy story. I would prefer to see docs like MDN and/or like the one I wrote. That would be easier to search and follow.

1 Like

Yes, I your observation & conclusion is on point. That is probably could be a lot better for us. Tons of example in every corner

Looping @EisenbergEffect into this