I am learning the Angular 5+ and recently comes to the subject/subscription part, I see many tutorial would like to use the subscription in the certain way:
Declare the subscription in component
Subscribe it in ngOnInit via a service's subject or ngrx/store
Unsubscribe it in ngOnDestroy
However, I am not sure if we have to subscribe/unsubscribe every subscription in the component in ngOnInit and ngOnDestroy. For example, if my subscription will get updated through a button click event, which plan should I subscribe it in my component?
Only ngOnInit
Only button click event
Both ngOnInit and button click event
Why would we always subscribe a subscription in ngOnInit? The ngOnInit would be like a Page_Load in page life cycle, so it would only be called once at the very first time, if so whenever the subscription gets updated, will the ngOnInit be fired over and over again? If so, will my component be loaded over and over again which would cause a performance issue if in large application?
You usually put Observables to subscribe to inside a Service and make them available via getters and setters.
When subscribing to an Observable it behaves in a certain way like an EventListener. Whenever the object inside the Observable gets changed, an Event gets fired and your code inside the subscription gets executed. Additionally, you get provided the updated object.
Even if you init the subscription inside ngOnInit this won't cause your entire Component to reload when an update arrives. Only those parts that get updated by your code inside the subscription.
You don‘t have to put a subscription inside ngOnInit(). It depends on what you want to achieve in the component. But most of the time you want to load and display data directly when you access the component and update the UI when this data changes. That's why it is good practice to put the subscription in ngOnInit().
Related
how could a pass a click event from one component to two parents up.
I have a form with a bottom clear, this form component is in a file filterForm
the filterform component is called in another file called TableView and the tableView component is called in a file called Admin
I want to execute a function inside admin when the button clear is clicked
the button is in the file filterForm
the filterForm is used in TableView
and tableView is used in Admin
this is the function I want to call from Admin to test
I understand that I have to make a click event from fileForm and emit that event to Tableview, but the function is on Admin that contains all the data and methods.
Thanks for your help!
Based on $emit event in Vue.js: https://vuejs.org/guide/components/events.html
When you emit an event like this: $emit('someEvent'), the parent someEvent function will fire (and also you can pass some parameters).
Passing a data or emitting a function so that two parents up listens to your event and get the data will need some chaining.
Fire the event on 1st component and get it in 2nd component and then fire the event in 2nd component to get it in 3rd.
Edit: one of the best practices is to use Vuex(Pinia) as a state management tool to pass or get data in an easier and cleaner way.
I have a custom Vue component that does not render to HTML.
When the component is first mounted, I am able to loop through this.$listeners and optimize the underlying non-HTML event implementation accordingly (e.g. not to emit mousemove type events unless something is listening).
To complete this process I'd like to know when listeners are programatically added later through $on().
Is there any non-polling way to be notified of this? My current workaround is to listen for and emit everything but that is a poor solution.
Note that in some instances I want to be able to use the events in question, and others not. For example:
<custom-component #eventThatWouldFireOften="doSomething" #anotherEvent="doMoreStuff"/>
and another usage might be simply.
<custom-component ref="custom"/>
...
mounted() {
this.$refs.custom.$on('anotherEvent', ...)
}
So in the first case the result would be:
CustomComponent tells the underlying API it wants to listen for eventThatWouldFireOften and anotherEvent
CustomComponent receives eventThatWouldFireOften and anotherEvent events from the underlying API and re-emits them as Vue events that can be listened to using v-on or # syntax.
..and the second case the result would be:
CustomComponent tells underlying API it doesn't want to listen for anything just yet
When the parent of CustomComponent is mounted it programatically listens for anotherEvent. That needs to be communicated down to the base API (what I'm trying to solve).
In an angular5 application, I have various sections of my page layout that I would like to control through an angular service. For example, I have a sidenav component that displays when a value is set to open, and I would like to be able to toggle it from any component I'd like.
My initial thought was that it would be nice if I could bind the open value to a variable in a LayoutService I would create, and the LayoutService would contain a toggle() method that would toggle the value and cause the sidenav to open/close. I could then inject my LayoutService into any component I'd like and control various parts of my layout.
Any idea whether this is possible and how I could go about doing this? I thought it might be possible using an EventEmitter or something, but I was wondering whether there was a simpler way and I'd rather not use redux.
https://stackblitz.com/edit/angular-lj7gsz
Here's a side-bar you can open and close using simple rxjs objects.
In the side-bar service, I've created a BehaviorSubject that you can pass boolean values to and I also exposed an Observable, which will emit every time a new value is passed to that subject.
By subscribing to that observable (I've used the async pipe to subscribe for me), my side-bar component will know when other components wish to open or close the side-bar. All the other components need to do is inject the service and call the service's open or close methods.
It's not perfect, but I feel it's definitely better than using event emitters as they were never made to be used in services.
Hopefully this is helpful.
I am using async components in a vue.js project, like this: https://v2.vuejs.org/v2/guide/components.html#Async-Components
Everything works correctly on the first load because my factory function fires. The factory function makes an ajax call, then returns the template to Vue. It also does some custom JS stuff.
My issue is that when a user wants to load that component again, the factory function does not fire again. It will only fire on the first load of the component.
For example, I have a component for each page on the website (Home, About, Contact, etc). When the user clicks on About for the first time, it's all good. But when they go to Contact, then back to About, Vue will not call the factory function, and instead inject what looks to be a cached version of the template.
I need my custom JS to fire again, because it's what triggers a lot of animations. Is it possible to fire the factory function multiple times, or do I need to think about restructuring, and if so, is there a a suggested way?
One of the stated SpineJS goals is to make the entire UI non-blocking (i.e. display the change to the user, even though it might have not been updated successfully on the server side yet).
Can it be used in a standard "blocking" manner?
Yes it can. Look here under "callbacks":
http://spinejs.com/docs/ajax
You can basically block the UI at any point, and I do it for things that just can't be deferred to the server. Note that I don't even use the ajaxSucess() event, but just custom bindings for events. Here is an example use case in meta programming:
Bind 'clickHandlerFinish' event to clickHandlerFinishWork()
Bind 'click' event on button a to clickHandler()
User clicks on button a
clickHandler() gets fired
clickHandler disables the button and blocks the UI
clickHandler makes an AJAX call to the server to do work
(Remember UI is still blocked)
AJAX call finally returns, and fires the clickHandlerFinish() callback
clickHandlerFinish() unblocks the UI, re-enables the button, and presents the new changes
I've used this successfully on a few instances. Works great for me!