Vue.js eventBus doesn't emit property after page refresh - javascript

I want to pass property from one component to other, they are siblings, after a page refresh. I want to do this on the page load.
I am using eventBus to do it:
EventBus.$emit('generatedSum', this.sum);
Receiving it in the sibling component with:
EventBus.$on('generatedSum', (sum) => {
this.correct = sum;
});
and I am puting both in the lifecycle hook:
created(){}
The problem is that after code is compiled after a saved change, I get the property emited to the sibling component, but when I manualy refresh the page the property is not visible in the sibling component.

I think when the page refreshes the Vue components mount one after another. Since both are siblings, when the first component trigger the event the second component may not be available to listen to the triggered event. Because the second component is mounted after the first component.
As a work around try
mounted() rather than using created() life cycle event.
More on life cycle events can be found here.
https://v2.vuejs.org/v2/guide/instance.html#Lifecycle-Diagram

Related

How do you update state in parent component from a child component when an event takes place in the parent component

I have to update state of the parent class component from child functional component only when a click event takes place in the parent component. Right now I've access of the data from child to parent component but when I update the state I get error, maximum depth reached. So I thought it'd be better to update the parent's state from child only when the certain event takes place in the parent component but I'm unable to find any approach. Could you please show some light?
From your description, the best thing to do is to lift state up from the child to the parent so that the information you currently only have in the child is available in the parent (which can provide it to the child as a prop). Then, the child isn't involved in this at all, the event in the parent updates the parent's state, which is standard.
But if you absolutely can't do that:
It's taking you off the beaten path, but you could:
Have the parent pass the child two things:
a means of subscribing to an event from the parent
a function to call to update the parent's state
Have the child subscribe to the event
Have the parent raise the event the child subscribes to when the click occurs
Have the child respond to that event by calling the function from (1)(2) above
While that would work, it's a bit convoluted. So again, if you can avoid it, move the state needed for the update from the child to the parent and keep the entire update in the parent.
Finally I figured out a way to achieve it.
Step 1: Set a boolean for your event taking place in your parent state using useState hook.
// Inside Parent component
const [eventInParent, setEventInParent] = React.useState(false);
Step 2: pass the eventInParent as prop to your child component
// Inside Child component
Step 3: Receive the event status (eventInParent) in your child component in your props and use it as a dependency in useEffect hook
React.useEffect(() => {
if(eventInParent) {
}
}, [eventInParent]);
As you can see every time event will hit in parent component the eventInParent value will change which will trigger the useEffect hook in the child component.

React: moving to a particular child component of my react app

I have a callback function which receives an argument from child component(here CardTiles) and it is processed and passed as props to another child component. The output is displayed correctly but I have to move my page to that particular section(the second child component-OutputWindow). How can i trigger an anchor tag from my 1st child component? or would refs work here?
Child component 1:
<CardTiles parentCallback={handleCallback}/>
Child component 2:
<OutputWindow name={place}/>
or would refs work here
Yes. Have a ref in the parent, put it on the child (ref={theRef}), have the child forward that ref to the outermost (probably) HTML element it renders, and then in the callback function have the code use theRef.current?.scrollIntoView()¹ to scroll that element into view.
More
Refs
Forwarding refs
scrollIntoView
¹ That's using optional chaining, which is fairly new. If your project isn't set up for it, you can use if (theRef.current) { theRef.current.scrollIntoView(); } instead.

Vue 2 load ajax data before component render

I have a few nested Vue Components and the child loads the data using an AJAX call. Is it possible to have the parent wait to finish mounting until the child has made the ajax call and finished rendering? I have seen some solutions that use async created() or beforeRouteEnter: function (to, from, next) but I cannot seem to get it to work on the Fiddle.
I have a jsfiddle posted here: https://jsfiddle.net/likwidmonster/20potzwc/16/
In the jsfiddle, I have nextTick functions that print to the log when each is loaded. I would like it to have the following output:
grandchild next tick
child next tick
grandchild next tick
child next tick
grandchild next tick
child next tick
parent next tick
You cannot stop the parent from loading so to speak, but you can make it seem like it is by applying v-cloak, v-if, or v-show to the top level HTML element in the template. You can have a property on the parent, such as:
loaded: false
You can then use sync to synchronize this value with the parent and child, by attaching it to the child like this:
<child :loaded.sync="loaded"></child>
Then, within the child, you can use $emit when your Promise resolves:
this.$emit('update:loaded', true)
Which will tell the parent to change loaded from false to true.
Finally, you can make sure the parent isn't rendering until that variable is try by attaching a v-show directive which and passing it the loaded variable:
<div v-show="loaded">
So on initial page load this is false. When the data is finished loading and the child $emit's, then it will be true, and the parent will become visible.

Angular2 Destroy Current Component Completely

I tried searching google and stackoverflow but could not find an answer. So my question is simple "How can i remove current component in angular 2, 4"
example:
<div (click)="remove($event)">Remove Current Component</div>
remove($event) {
// this.destroy() ????
}
Basically what i want is ComponentRef see this answer ngOnDestroy() which calls this.cmpRef.destroy() :
ngOnDestroy() {
if(this.cmpRef) {
this.cmpRef.destroy();
}
}
But he is getting the ComponentRef due to dynamically creating the component.
You can use a *ngIf="myBoolean" directive on the component element in the parent template. When myBoolean becomes false, the component will be destroyed.
No more component or DOM element present. (and ngOnDestroy event raised)
If myBoolean becomes true again, a new component will be instantiated.
A new one will appear in DOM (and ngOnInit event raised)
Your click event can emit an event (binded in the parent with the (myEventEmitter) syntax, and a method in the parent component can then just set the boolean to false.
Demonstration on this Plunker. If it doesn't suit your need, consider editing your question to provide more specific details, including a Minimal Complete Verifiable example

Is there a way to capture events emitted by multiple child components in vuejs?

I have a parent component which has multiple child components
<grid>
<cell></cell>
<cell></cell>
<cell></cell>
</grid>
My cell components emit an event with payload saying it is being edited
this.$emit('editing',cellId)
I know I can capture the event like
<cell #editing="do something"></cell> or capture using EventBus.$on('editing'), I do not want to use root listener as well this.$root.$on('editing')
But because its the parent component, how can i listen to event of 'editing' when the parent component is mounted
mounted: function(){
this.$on('editing',dosomething)
}
why am I not able to add listen when the parent component is mounted?
The main difference that you are missing is described in the Custom Events section:
In addition, a parent component can listen to the events emitted from a child component using v-on directly in the template where the child component is used.
You cannot use $on to listen to events emitted by children. You must use v-on directly in the template, as in the example below.
What this means is that child-parent communication is done through a directive, using the v-on (or #edit) way.
Your example here
mounted: function(){
this.$on('editing',dosomething)
}
Won't actually work. In the emit documentation it's said that:
Trigger an event on the current instance.
Which means that inside the same component, you can actually use this.$on and it will work. But if you want to use it in parent, then you should use the inline directive to have it bind, otherwise it won't work.
Also keep in mind that emits works only for a single step, meaning that the the parent can catch it. If you need to emit subchild -> child -> parent, then you should catch the event (using inline binding) from subchild in child, and re-emit it again so it goes to parent.
If it is outside of children-parent scope, then you should use what is called a global bus. Basically it narrows down everything to a single instance, which emits and listens for all events. So then they are no longer child-parent or whatever kind of connection, they are all on the very same instance, and therefore you can always use them in every component of yours.
Bottom line is - your approach to listen on mounted won't work. Hope that helps :)
The difference between listening to each child and listening to the EventBus is this:
when you emit an event like this.$emit('event') the event will be fired only for the parent component.
when you do a EventBus like EventBus.$emit('event') then your event will be sent to all the components
There are pros and cons for each one; EventBus can send events to components which will never use that event (can become an event polution), and the parent event emitter can be not that elegant to use as EventBus.
So you decide which approach is good for you.
TL;DR
Stumbled across this issue my self. Like the other said, when you want to bind an event listener from a parent, you need to use v-on because, well ... , you are binding something tot he child. So the actual callback is ran by the child, when that child detects that the event ocured.
In the child use this.$parent.$emit('event-name');
In the parent use
mounted: function() {
this.$on('event-name', function() {console.log('test')});
}
The above will let you trigger the event in the parent so you can use $on in the parent to lsiten to that event that was triggered by the child.

Categories