I have the following template in a specific modal component:
<template>
<my-base-modal ref="BaseModal" :width="1000">
<template v-slot:header>Details</template>
<template v-slot:body>
<detail-card ref="DetailCard"></detail-card>
</template>
</my-base-modal>
</template>
It creates a base modal and overwrites the slots for header and body.
The body slot is filled with a sub component which needs to load some data.
I tried to use the following method to open and load the content of this modal:
open (id) {
this.$refs.DetailCard.load(id)
this.$nextTick(() => {
this.$refs.BaseModal.open()
})
}
But this.$refs.DetailCard is always undefined. I suspect this is because the reference DetailCard is defined inside the body slot of the <base-modal> component?
How am I supposed to trigger a function on the <detail-card> component in this example, without using EventBus or passing some props into it?
My suspicion is that at runtime, the DOM is not rendered until the BaseModal's open method is invoked. Therefore, this.$refs.DetailCard will returned undefined since the body slot of your component has not rendered with the nested component.
As you have mentioned in the comments, the fix can be as easy as ensuring that the DOM is already rendered, e.g. using v-show instead of v-if.
Related
I am trying to implement a component named CamViewMatrix in Vue.js. My requirement is to get the width of CamViewMatrix's parent inside itself (say in created() method of CamViewMatrix) so that I can make some calculations with it (there are some time-based charts that need to be made responsive which is not possible unless an initial value for width is in hand).
<div>
<div class='controller-wrapper'>
...
</div>
<CamViewMatrix v-bind:cameras='cams' />
</div>
I tried assigning an id to its parent and passed the same as a prop to CamViewMatrix, and attempts to getElementById, but it's not able to. Code given below:
<div id='parentid'>
<div class='controller-wrapper'>
...
</div>
<CamViewMatrix v-bind:cameras='cams' parentId='parentid' />
</div>
And inside CamViewMatrix component:
<script>
export default {
name: 'CamViewMatrix',
props: {
parentId: {
type: String,
required: true,
},
...
},
created() {
console.log(document.getElementById(this.parentId)); // 👈️ logs null
...
}
}
With the above code, I am not able to get the parent element (it's logging null).
Have also tried using ref and $parent, but was not able to. Kindly help me with this.
Thanks in advance.
created() is the wrong lifecycle hook to do that.
If you check the lifecycle diagram from the docs: https://v2.vuejs.org/v2/guide/instance.html#Lifecycle-Diagram
The element stuff is not yet done (rendered) and only the instance is created.
You most likely what to do that in mounted.
Next, you can access your component's parent via this.$parent and the element via this.$parent.$el.
Check out: https://v2.vuejs.org/v2/api/#Instance-Properties
If you want a specific element from parent, create a ref and access it like:
this.$parent.$refs.refNameYouAdded
If it's a Vue component, then it'd be a Vue instance so you need to access $el again:
this.$parent.$refs.refNameYouAdded.$el
otherwise if it's a HTML element, then no need to do that.
most of the time, the above answers work but sometimes if your parent component does things like moving elements somewhere else then it might not be accurate.
as mentioned in the comment, you can still access the correct parent element by doing:
this.$el.parentElement
I have a VueJS project - which in one view there are parent and child components that are both using the same component called deleteModal.
When I trigger the modal from the child (to show it), it triggers both the child and parent modals (except no data is passed to the modal triggered by the parent). As I understand it, this is because I have used the component twice - in the parent and child - example below. To note, it works as expected from the paren
I've researched and tried a few things: setting a key value for each of the components, changing the components ref name among other things. I have also tried using v-show to only show component just before I trigger the parent model however, this solution is not ideal.
How can I only trigger the modal from the child?
Parent Component
<template>
<div>
<childCompt ref="childCompt" />
<deleteModal
ref="deleteModal"
#deleteTriggerAPI="deleteAPIParent"
/>
</div>
<template>
Child Component - childCompt
<template>
<div>
<deleteModal
ref="deleteModal"
#deleteTriggerAPI="deleteAPIChild"
/>
</div>
<template>
My old answear is not good at all. I personally to show and hide element using jquery in vue. For me right now this is best solution but maybe i don't know some best.
If you want use only vue i using also variable passing to child from parent which will support visable of your modal.
We pass variable with ":" and register event with "#".
<template>
<childComponent :isModalOpen="isModalOpen" #onModalClose="isModalOpen=false">
<template>
export default {
name:"parent",
data: () => {
isModalOpen: false
}
}
In child we catch this by using props. We need to define type of varialbe we pass. Different between props and data is that in props we cannot change value in child component.
export default {
name: "child",
props: {
isModalOpen: Boolean
}
}
And you can use this variable to show or hide modal. Also in child component we can create button to close modal and we emit event to parent in order to change variable value.
To do this we using this.$emit('eventName');
More information right here: https://forum.vuejs.org/t/passing-data-back-to-parent/1201
You could try globally defining the component,
ie, in main.js
Vue.component('deleteModal',deleteModal)
<el-tree :data="Project">
<span class="custom-tree-node" slot-scope="{ node, data }" v-contextmenu:contextmenu>
<el-input
placeholder="Please input"
v-model.trim="data.label"
#blur="saveOrDiscard(node, data)"
></el-input>
</span>
</el-tree>
I have used method as below, where I am updating id of treenode (which is from ajax call inserted id. I have simply changed to clearly explain problem).
But data of tree (which I have given as Project) is not updating. Next time it shows 0 value (which I have set as deault).
public saveOrDiscard(node: TreeNode<any, TreeData>, data: TreeData) {
//Following 456 is not updating in tree data.
node.data.id = 456;
}
Scoped Slots and Slot Props
el-tree is a slotted component and, by default, slots only have access to the same instance properties as the rest of the containing template. So for example, the slot does not have access to :data.
If you must access this data in the parent template, you need to use slot props and also explicitly bind the data in the slot's template. So in the el-tree component template, you bind the data to the slot like this:
<slot :data="data"></slot>
Then in the parent template, you can access data via the v-slot directive like this:
<template v-slot:default="slotProps">
{{ slotProps.data }}
</template>
The default argument refers to the slot name, which is named "default" if none is specified.
Here is a fiddle showing this behavior.
*You can read more about slots & slot props here.
Binding blur event as following worked for me.
#blur="() => saveOrDiscard(node, data)"
instead of following.
#blur="saveOrDiscard(node, data)"
If i have a presentational (child) component with the following line:
<small id="parameters"> some parameters text </small>
I noticed that if i go to its parent container component and try to get that element by:
const textElem = document.getElementById('parameters').value;
It is not going to get its value.
Why is that? If i use document in a component, is it only "local" to that component?
You can use document inside a component, to reference the global document object, it's not local to that component, however, at the point you're referencing document.getElementById('parameters') this element might not have been rendered yet to the dom, so make sure to call it after the child element has rendered.
On the other hand, maybe you meant to use: document.getElementById('parameters').innerHTML
to get the text inside that element, instead of .value
How to target method inside other component?
I'm working on a project where I want to target a method inside another component. I press a button inside the dashboard component and I want to change the data inside my line-chart component (which uses vue-chartjs). How can I target this method?
Well you could target it over $refs however, this is pretty dirty, as it prodvides a pretty strict binding of your componentes.
A better solution would be to trigger an event (eventbus) or over an prop.
You can call children's method by referencing them through refs
In your example, your dashboard's template should looks like this :
<template>
<div>
<button #click="$refs.chart.yourMethod()">Call child method</button>
<line-chart ref="chart"></line-chart>
</div>
</template>