I have a wrapper component (waypoint) which collects child elements. On the child elements I want to set functions which should be executed from the wrapper component, how can I do that?
//page
//template
<v-waypoint>
<div
:data-wp-cb="animateIn"
// :data-wp-cb="animateIn.bind(this)"
class="js-wp"
//methods
animateIn() {
// do something
}
//waypoint component
update(el) {
const cb = el.dataset.wpCb
cb() // cb is not a function
}
How can I make this work?
You should solve it emitting the event from child to the parent.
Waypoint component:
update(param) {
this.$emit('update-from-child', param);
}
Page component:
<v-waypoint #update-from-child="localMethod">
<div
:data-wp-cb="animateIn"
// :data-wp-cb="animateIn.bind(this)"
class="js-wp"
This is how vue deals with child -> parent comunication. For more info, check the docs.
Related
I have a parent component creating child components using v-for directive:
<div class="planlist">
<ul id="planOl">
<PlanLego
v-for="action in store.plan"
:v-if="action !== activeStep"
:action_id="action.act_id"
:actor="action.actor"
:blocked="action.blocked"
:key="action.act_id"
#choose="planClick"
#fix="changeActor"
/>
</ul>
</div>
and I'm emitting a signal from the child component:
this.$emit('fix', {
act_id: this.action_id,
actor: this.actor
});
My question is:
how can I access and change the properties (for example actor) of this specific child component that emitted the signal? thanks in advance.
As per my understanding, You want to update the actor for the specific child in the parent component based on the act_id passed from child. If Yes, You can achieve this by iterating the original array object in the parent.
In the parent component, Your changeActor method should be like this :
In template :
#fix="changeActor($event)"
In script :
changeActor(emittedObj) {
store.plan.forEach(item => {
if (item.act_id === emittedObj.act_id) {
item.actor = emittedObj.actor
}
});
}
I have a parent component that has a button when the user clicks it will make a request and passed the data into a child component (a ngx-bootstrap modal). The child component will use the async data to make another request to render its UI.
My parent component is like this:
<Parent>
<child-modal [subSectionInfo]="subSectionInfo"></child-modal>
</Parent>
the subSectionInfo is async data retrieved from an ajax in Parent component.
My child component will make call like this:
ngOnInit() {
const id = this.subSectionInfo.id;
this._fetchData(id)
}
private _fetchData(id: number) {
this.service
.getData(id).pipe(
.subscribe((data: any) => {
this.list = data;
});
}
However, this always gives me undefined which causes the child component ajax call failed. Is any way to solve this issue? Thank you so much in advance!
Currently, your code does not wait on the first request to complete. While the request for subSectionInfo is being made in the parent component, it's value is undefined since the value hasn't returned from the server yet. This is why the child component get's undefined. There are 2 ways to approach this.
In your parent component, you can wait until the data is loaded and then pass in subSectionInfo to your child component.
In your child component, you can make use of the ngOnChanges life-cycle hook. This is where your child component implements OnChanges. You can read more about it here.
ngOnChanges(changes: SimpleChanges) {
if (changes['subSectionInfo'].currentValue !== undefined) {
const id = this.subSectionInfo.id;
this._fetchData(id)
}
}
private _fetchData(id: number) {
this.service
.getData(id).pipe(
.subscribe((data: any) => {
this.list = data;
});
}
Hope this helps
I have problem whit scrolling to the element while opening the page. It's like scrolling to an anchor. I'm sending div id via props to the nested child component. On mounted I call a method scrollToSection where I have logic with scrolling.
props: {
section: String
},
mounted() {
this.scrollToSection();
},
methods: {
scrollToSection () {
if (this.section != null) {
const options = {
force: true,
easing: 'ease-in',
};
VueScrollTo.scrollTo(`#${this.section}`, 100, options);
}
}
}
In that point child component dosen't render the DOM and document.getElementById(this.section) return null. But in parent component I have an access to that div.
Do you have any idea how to resolve that issue? Method nextTick dosen't work.
Had the same problem, where I needed to access an image in a nested component, I had to wait till the image is loaded within the nested component, by adding a #load event listener that emit a loaded event to the parent, so I knew it was ready and perform my actions.
If nextTick isn't working, you can do the same, just emit a ready event on the mounted hook of the child component and when it's ready, perform the scroll.
//Child component
mounted(){
this.$emit('ready');
}
_
//Parent component
...
<child-component #ready="scrollToSection()" />
...
Or in alternative, if you have access to the div you want to scroll to, you can use pure javascript
MyDiv.scrollIntoView({ block: "start", behavior: 'smooth' });
I have two components that are in a parent-child relationship. In the child select component I've defined a watcher for the currently selected value and I want the parent to get the updated value whenever it changes. I tried to use events but the parent can only listen to its own vm.
In the child component
watch: {
selected (value) {
this.$emit('selectedYearChange', value)
}
}
In the parent
mounted () {
this.$on('selectedYearChange', function (value) {
this.selectedYear = value
})
}
This obviously doesn't work because of the reason I mentioned above.
I wasn't able to find relevant examples in the documentation.
You can setup an event listener on the child component element itself where its used in the parent and pass it a method to be executed
//parent component
<div id="app>
<child-comp #selected-year-change='changeYear'></child-comp>
</div>
In your parent component use the method changeYear to change the value of `selectedYear'
methods:{
//you get the event as the parameter
changeYear(value){
this.selectedYear = value
}
}
See the fiddle
And avoid using camelCase for event names use kebab-case instead as HTML attributes are case-insensitive and may cause problems
html:
<Parent>
<Child #selected-year-change=HandleChange(data)></Child>
</Parent>
Javascript/Child Component:
watch: {
selected (value) {
this.$emit('selectedYearChange', value)
}
}
Javascript/Parent Component:
HandleChange: function(data){}
good luck. maybe work!
as title, how can I do that
from offical documentation just tell us that $delete can use argument 'object' and 'key'
but I want delete a component by itself like this
this.$delete(this)
I couldn't find instructions on completely removing a Vue instance, so here's what I wound up with:
module.exports = {
...
methods: {
close () {
// destroy the vue listeners, etc
this.$destroy();
// remove the element from the DOM
this.$el.parentNode.removeChild(this.$el);
}
}
};
Vue 3 is basically the same, but you'd use root from the context argument:
export default {
setup(props, { root }){
const close = () => {
root.$destroy();
root.$el.parentNode.removeChild(root.$el);
};
return { close };
}
}
In both Vue 2 and Vue 3 you can use the instance you created:
const instance = new Vue({ ... });
...
instance.$destroy();
instance.$el.parentNode.removeChild(instance.$el);
No, you will not be able to delete a component directly. The parent component will have to use v-if to remove the child component from the DOM.
Ref: https://v2.vuejs.org/v2/api/#v-if
Quoted from docs:
Conditionally render the element based on the truthy-ness of the expression value. The element and its contained directives / components are destroyed and re-constructed during toggles.
If the child component is created as part of some data object on parent, you will have to send an event to parent via $emit, modify (or remove) the data and the child component will go away on its own. There was another question on this recently: Delete a Vue child component
You could use the beforeDestroy method on the component and make it remove itself from the DOM.
beforeDestroy () {
this.$root.$el.parentNode.removeChild(this.$root.$el)
},
If you just need to re-render the component entirely you could bind a changing key value to the component <MyComponent v-bind:key="some.changing.falue.from.a.viewmodel"/>
So as the key value changes Vue will destroy and re-render your component.
Taken from here