How to pass ref from parent to child component in template - javascript

I am using this component https://element.eleme.io/#/en-US/component/popover
Issue related to triggering element (it is used to calculate where is popover located)
For the triggering element, you can write it in two different ways: use the slot="reference" named slot, or use the v-popover directive and set it to Popover's ref.
Everything ok with default examples. But I am using transparent wrapper for el-popover component like so.
<script id="my-popover" type="x-template">
<el-popover
ref="mypopover"
transition="el-zoom-in-top"
v-bind="$attrs"
v-on="$listeners"
>
<!-- Pass on all named slots -->
<slot
v-for="slot in Object.keys($slots)"
:slot="slot"
:name="slot"
/>
<span> My popover </span>
</el-popover>
</script>
It works ok with slot="reference" named slot.
<my-popover
placement="bottom"
title="Title"
width="200"
trigger="manual"
v-model="visible"
>
<el-button
slot="reference"
#click="visible = !visible"
>
Click me
</el-button>
</my-popover>
But due to complex layout I need to use v-popover directive. Got no luck with wrapped component.
<my-popover
ref="popover"
placement="right"
title="Title2"
width="200"
trigger="manual"
v-model="visible2"
>
</my-popover>
<el-button
v-popover:popover
#click="visible2 = !visible2"
>
Click me too
</el-button>
So I need somehow to pass in v-popover reference to ref="mypopover" from wrapped component. I.e. pass ref to child directly in template.
I've tried v-popover:popover.$refs.mypopover but that doesn't work.
Related codepen https://codepen.io/anon/pen/rgRNZr
Click on button Click me too should show popup connected to that button.

The problem is that the ref you want is the one that is on the el-popover but you are using the ref that is set on the my-popover component instead of the one you want.
This is kind of a wierd thing since that component wants a ref but it will be annoying to get one from the component inside your component.
I would put the button and popup with a slot in the same component.

Related

How to render VueJS Slot in a another component

VueJS slot could be placed anywhere inside a parent component.
However, I have a use case where I need to show a slot in another (foreign) component outside the parent component.
For example, I have component Student:
<template>
<slot name="detail" />
<slot name="status" /> <!-- I don't want to render this slot inside this component, but somewhere else -->
</template>
I want to display the student's status in a header section outside the student component as below:
<div class="Header">
<!-- student status slot should go here-->
<student-status-slot></student-status-slot>
</div>
<div class="InputForm">
<student>
<template #detail>This the detail information about student</template>
<template #status>Grade A</template>
</student>
</div>
You may suggest to create a new "student-status-slot" component. However, the idea is to have all student related information, including "status" declared under the component, but render some of the slot somewhere else.
I have tried another approach creating a separate component and pass the status data via prop. But That is not what I wanted to achieve. I don't want to pass data, but re-use the student status component, which can be dynamic.
In a parent component you can access child's slots by adding ref attribute to child, and then render the VNode obtained. See the demo here https://codesandbox.io/s/happy-einstein-9f5rke?file=/src/components/StudentPage.vue
But actually I wouldn't recommend this way such it's not conventional and slots were not designed for this. I think you should rather consider using portals (Vue 3 portals or https://www.npmjs.com/package/portal-vue if you use Vue 2) to achieve your goal

Attach a sibling component using ref of a component

I am using a library in my page, I wish to update the input component of this library when it is rendered. More specifically I wish to add an icon to the input box of this library.
The library doesn't provide any slots to perform the same but what we it does give us a ref for the input element. I wish to use this to update the html by attaching an icon as a sibling of the ref.
I want to know if this is possible and a base guide as to how I achieve it
I have tried to use document to perform the same but I feel vue should be able to do it and the state will be consistent post that.
App.Vue
// App.vue (Parent)
<template>
<Component ref="componentRef" />
</template>
//Component.vue (Child)
<template>
<div id="iconMountPoint">
</div>
<input ref="inputEleRef">
</template>

Vue 2 not updating specific component properties despite v-if v-else directive, while the rest is updated successfully

Vue2 is not updating one specific component (<Button>) inside v-if and v-else, while the rest of the content is updated.
I have just found out a way to make this code work, but I do not catch the behaviour of Vue2 re-rendering, and I am afraid that I will not be able to make it work this way anytime, because here I only have 2 conditionally excludent blocks (or <v-if> and v-else, and now I use <span> and <div> for each).
This was the original code that does not work. The problem is that it did not update the component once the condition ('root.authentication') is changed, but seamlessly, the <p> tag is updated successfully (why <Button> not?):
<template>
<span v-if="root.authentication" data-id-logout-box>
<p>Logout</p>
<Button :root="root" text-label-preset="Salir" :on-click-preset="root.logout" />
</span>
<span v-else data-id-login-box>
<p>Login</p>
<Button :root="root" text-label-preset="Entrar" :on-click-preset="root.login" />
</span>
</template>
This second code does the trick. The only difference is that, in the previous, there were 2 span tags, while in this one, there is 1 span and 1 div tag:
<template>
<span v-if="root.authentication" data-id-logout-box>
<Button :root="root" text-label-preset="Salir" :on-click-preset="root.logout" />
</span>
<div v-else data-id-login-box>
<Button :root="root" text-label-preset="Entrar" :on-click-preset="root.login" />
</div>
</template>
I have tried to do it changing the class attribute applied to that elements, and also playing with data-* attributes, as you can see in the example. But none of them worked.
My quesiton is, as I do not have infinite tags to make it work, how could I do the workaround for this, in order to make it work with infinite nested <v-else-if>?
Thank you.
If and else elements are identical that's causing this issue. when you are changing else part to div fixes because how vue update and render template.
for more details
https://snipcart.com/blog/vue-render-functions
you can give first span and second span unique keys and that should solve the problem.

Include component from parent app in component contained in node_modules directory

I am working on Vue app that incorporates Vue Bootstrap Calendar, and I would like to be able to override the content of the day cell (handled by the Day.vue component) to add my own custom content inside. My thought was initially to modify the Day component to include <slot></slot> tags and pass in the custom content that way.
The problem has to do with accessing the Day component. To include the calendar in your app, you include the Calendar.vue component, which includes Week.vue, which in turn includes Day.vue. As I understand slots, I have to have the child component (Day.vue in this case) included in the component where I'm passing the data, which means it would need to be included in my own component.
If this is not possible, my other thought is to perhaps modify the library by adding another configuration prop (something like dayCustomContent) to the Calendar.vue that indicates that the Day cell content is custom content, pass that in to Calendar.vue, and then down to Day.vue, and then in the Day.vue template, have a v-if conditional based on this prop that either displays the custom content or the default cell content, something like:
<template>
<div class="day-cell" v-if="dayCustomContent">
...my custom content here...
</div>
<div class="day-cell" v-else>
...default events from my.events goes here...
</div>
</template>
I would probably then need to define a custom component to render whatever custom content I want to display, and somehow include that component within Day.vue.
So to sum up, my questions are these:
1) Is there a way to do what I need with slots?
2) For my second option, am I going down the right path? I'm open to suggestions.
UPDATE: I was able to get this done by adding a boolean customDayContent prop in Calendar.vue like so and passing it down to Week.vue and then to Day.vue:
<template>
...
<div class="dates" ref="dates">
<Week
v-for="(week, index) in Weeks"
:firstDay="firstDay"
:key="week + index"
:week="week"
:canAddEvent="canAddEvent"
:canDeleteEvent="canDeleteEvent"
:customDayContent="customDayContent"
:displayWeekNumber="displayWeekNumber"
#eventAdded="eventAdded"
#eventDeleted="eventDeleted"
></Week>
</div>
...
</template>
<script>
export default {
...
props: {
...
customDayContent: {
type: Boolean,
default: false
}
},
}
</script>
and then in Day.vue, do like I had suggested with v-if:
<template>
<div class="day-cell" v-if="customDayContent">
<custom-day></custom-day>
</div>
<div
class="day-cell"
:class="{'today' : day.isToday, 'current-month' : day.isCurrentMonth, 'weekend': day.isWeekEnd, 'selected-day':isDaySelected}"
#click="showDayOptions"
v-else
>
... existing code goes here...
</div>
</template>
The last part is referencing the CustomDay.vue component referenced in my v-if block. I want the user to be able to define the content of their own custom CustomDay.vue template in their own parent app. However, I'm having trouble trying to figure out how to do that. Following the pattern of including components already in this component, I added this in the components section of Day.vue:
CustomDay: require("../../../../src/Components/CustomDay.vue").default
? require("../../../../src/Components/CustomDay.vue").default
: require("../../../../src/Components/CustomDay.vue")
However, no matter what I try along these lines, I get an error that the relative module was not found. On top of that, I need to add it to the componentsarray only if customDayContent is true. What is the best way to do that? In a watcher or computer property, perhaps? Or another way?

Vuejs component click event not working

I am using Vuejs - Vuikit components and have the following setup:
<template>
<div class="uk-scope">
<vk-modal :show="isShow" v-if="config">
<vk-modal-close #click="alert('hello!')" large></vk-modal-close>
<vk-notification :messages.sync="messages"></vk-notification>
<app-breadcrumb :current-view="currentView" />
<!-- render the currently active component/page here -->
<component v-bind:is="currentView"/>
</vk-modal>
</div>
</template>
My issue is that, the close modal does not see to fire the #click function.
The parent component, does emit an event, but I would prefer to fire something directly from the close button.
I have tried to use #click.native="someFunction()", but this has not helped!
Hey I've not used vuikit before but from their documents they show this is how to close a modal. I would also remove that v-if="config" as that might be confusing Vue
<template>
<div class="uk-scope">
<vk-modal :show.sync="isShow">
<vk-modal-close #click="isShow = false" large></vk-modal-close>
<vk-notification :messages.sync="messages"></vk-notification>
<app-breadcrumb :current-view="currentView" />
<!-- render the currently active component/page here -->
<component v-bind:is="currentView"/>
</vk-modal>
</div>
</template>
Have you tried using #click.native="someFunction" note that this does not have ().

Categories

Resources