Reload/reinit renderless vue component after morph dom node - javascript

I'm building at the moment a frontend editor.
When I'm logged in, elements are getting rendered by server (laravel) and are enclosed in a renderless vue component:
<vue-element>
<template v-slot="{ editing }">
<div class="element">
// other HTML
</div>
</template>
</vue-element>
The problem is, when I'm editing this element, css classes and other stuff are getting changed and I have to swap (morph dom) the element with a new element from the server. But when I do that, the element disappears and vue has lost track of the component.
How can I reinit the component or are there other solutions to my problem?

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>

How to add a boot message before initializing a Vue component?

I have a Rails application. In the main layer I wrap the HTML code of the controllers in #app:
body
#app
= yield
Vue components in the HTML (Slim) Rails application code I describe as follows:
news-list limit="24"
news-show news-id="528"
Vue in the project is globally initialized as follows:
document.addEventListener('DOMContentLoaded', (event) => {
if (document.getElementById('app')) {
new Vue({
el: '#app',
// ...
})
The problem is that sometimes there is a delay before Vue completes the render.
That is, it looks like this:
Go to the Rails application page. We see an empty page.
Render the Vue component. There is still no news list. General information only.
API request takes place. Rendered list of news. Done.
I want to do on the side of a Rails application between 1 and 2 points that something similar to the spinner.
That is, I go to the Rails application page. Wherever there is a Vue component, I see a spinner. The spinner disappears as soon as the component finishes the render.
But I do not know how to do it...
I hope for your help. And sorry for my english.
Showing spinner before vue component is initialized can be done by rendering spinner inside element that vue is being initialized on.
<div id="app">
<!-- This content will be replaced, once the Vue component is rendered -->
</div>
Spinner after component is loaded can be done using v-if
<template>
<div>
<spinner v-if='!news' />
<list-of-news v-else :news='news' />
</div>
</template>

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?

Render HTML Tag Vue.js

I am trying to add a render a template using the push mutation method. I want to push a section component, but instead of the template content I get the raw output of <vsection></vsection'. Can anyone help me render the actual template content and not the raw tags? I included a jsbin below.
http://jsbin.com/wurofatuve/1/edit?html,js,output
You're thinking about this a little oddly. What I think you'd be better off doing is putting a v-for on a <vsection> component.
<vsection v-for="section in sections">
{{ section.content }}
</vsection>
This way, when you push content to sections it'll out put another one. You'll also have to adjust your section component so you can use the content.
<template id="section-template">
<div class="section">
<slot></slot>
</div>
</template>
Here it is working like I think you want: http://jsbin.com/suhadidobe/1/edit?html,js,output

Categories

Resources