So I have this issue with my lib Aurelia-Slickgrid which is a Custom Element and I use the Event Aggregator in a few areas of the plugin but then I had some issues where certain actions were reflected in all elements created.
To give a concrete example of my issues, I create 2 or 3 grids (that is my custom element lib) and in the plugin I have some events which basically say something like when you get a filter cleared event then do other things in the grid and some of these actions were reflected in all my grids. At first I thought I had issues with DI and Services not being transient, I didn’t even think about the Event Aggregator, then after 2 days I found that the problem originate fromr the Event Aggregator being shared in the entire app. I tried setting the Event Aggregator as Transient with aurelia.container.registerTransient(EventAggregator); but that has no effect.
If you include the aurelia-event-aggregator plugin using “basicConfiguration” or “standardConfiguration” then the singleton EventAggregator’s API will be also present on the Aurelia object. You can also create additional instances of the EventAggregator, if needed, and “merge” them into any object.
It basically mentions about the Singleton, but doesn’t seem to say what to do for my use case (I want transient Event Aggregator in the Custom Element so that the events are only valid within each separator element).
Something like ea.publish(SessionCreatedEvent.Channel, new SessionCreatedEvent(params))
…
You don’t need the enum. If you pass an object, the constructor will be used as the key. Same result.
is that what I’m suppose to do to get a transient EA in each component? The doc isn’t clear about such use case.
I was thinking about that at some point but the problem is that if I create 3 grids, even if I have only 1 event aggregator sent (say “filter-cleared” message), it actually sends 3 messages even if I have a uid (which I tried and it sends 3 messages with same uid which is weird). That is why I’m trying to the Event Aggregator to be somehow transient (where it lives in it’s own component)
That doesn’t seem right… If you had it working as I’d expect I see no issue with each listener getting each others messages., but they should only be sent once
Why not just do some custom events then that you stop propogation on.
I know that doesn’t seem right but I spent more than 2 days on this and I don’t wish to spend another 2 days on troubleshooting this further. Worst case, I’ll just make my own pub/sub with simple callback methods but I was hoping there was a better way of having independent Event Aggregator… however that would mean rewriting a bunch of code, which I would try to avoid
right now I have some EA that tells when filters are cleared (passes a boolean), and other events like filter changed (which in that case is the filter object). Was that your question?
But again if I read the doc quote again
If you include the aurelia-event-aggregator plugin using “basicConfiguration” or “standardConfiguration” then the singleton EventAggregator’s API will be also present on the Aurelia object. You can also create additional instances of the EventAggregator, if needed
It does seem to say that there is a way to handle the EA in a transient fashion and be independent in each components, so what is the config to do so? I’m almost sure that I’m just missing a config of the EA somehow.
Wow @bigopon how do you come with these answers so quickly? You’ve even created a sandbox, you’re amazingly fast, I’m just speechless
Indeed the NewInstance looks like is what I need and to answer your questions, it would be Yes to everything you said… and funny enough the problem I have identified and causing me all these issues is the Pagination (because it’s a custom element (pager) into a custom element (grid)). I won’t use any global events (I might have some now, but I plan to remove them all and just use dispatchEventon the custom element and use the EA only internally).
Thanks, I did pass a lot of time on these Wikis, they exist to help me remember how to do certain things and also to avoid having too many questions on GitHub hehe
BTW, I haven’t tried the NewInstance yet, I’m still working on other features but will try in coming days, but I’m quite certain it will work as you explained it well
@elitemike just to point out that Transient is super useful and required in my case for all the Services that I use in Aurelia-Slickgrid and I have like 10 of them (it’s a big plugin) and without Transient in the picture, I wouldn’t be able to create multiple grids in the same page. The problem that I have today is because of a custom element into a custom element, the Pagination that is, (which is different than a service) and @bigopon provided a really great answer… So Transient still has it’s place in the family picture, mainly Services
@bigopon I can confirm that totally fixes my problem, I only added the NewInstance.of(EventAggregator) in the Parent (the grid custom element) and now the Pagination (child) is working as expected without affecting any other grid… sweet!!!
However, I just have a small issue with my Jest unit tests, they are failing with this message
(note: this unit test can be seen here)
Inner Error:
Message: #<Object> is not a constructor
Inner Error Stack:
TypeError: #<Object> is not a constructor
at Object.invoke (C:\\OwnCloudDev10\\GitHub\\aurelia-slickgrid\\node_modules\\aurelia-dependency-injection\\dist\\commonjs\\aurelia-dependency-injection.js:387:24)
at InvocationHandler.Object.<anonymous>.InvocationHandler.invoke (C:\\OwnCloudDev10\\GitHub\\aurelia-slickgrid\\node_modules\\aurelia-dependency-injection\\dist\\commonjs\\aurelia-dependency-injection.js:360:28)
at Container.Object.<anonymous>.Container.invoke (C:\\OwnCloudDev10\\GitHub\\aurelia-slickgrid\\node_modules\\aurelia-dependency-injection\\dist\\commonjs\\aurelia-dependency-injection.js:546:28)
at NewInstance.Object.<anonymous>.NewInstance.get (C:\\OwnCloudDev10\\GitHub\\aurelia-slickgrid\\node_modules\\aurelia-dependency-injection\\dist\\commonjs\\aurelia-dependency-injection.js:261:34)
at Container.Object.<anonymous>.Container.get (C:\\OwnCloudDev10\\GitHub\\aurelia-slickgrid\\node_modules\\aurelia-dependency-injection\\dist\\commonjs\\aurelia-dependency-injection.js:488:24)
EDIT:
As @bigopon pointed out correctly my approach would create a new instance every time whereas his re-uses the same object which typically would be favourable.
I ended up using a class factory instead of injection for my needs. I may revisit it, but I need to do some extra logic in the factory to set some properties anyways that can’t be completely set during injection. Can I make injection work, maybe. Is it worth my time to redo something that works… Maybe when I’m bored.
Glad you got everything working
When you do transient. Are you just doing @transient decorator?
I had another user helping me for that part, what he found to work best is to add on top of each Service @singleton(true). The documentation says the following:
singleton(overrideChild?:boolean) - Normally, types are auto-registered as singletons in the root container. So, why do we provide this decorator? This decorator allows you to specify true as an argument to indicate that the singleton should be registered not in the root container, but in the immediate container to which the initial request was issued.