How can I get the HTML from a slot with Vue? - javascript

How can I get the HTML from a slot with Vue?
<template>
<div>
<slot></slot>
<pre>{{ code }}</pre>
</div>
</template>
I want to get the html from <slot></slot> and show it in the <pre></pre>
Currently I have tried to do this
mounted: function () {
this.code = document.getElementById("demo-" + this.title).innerHTML;
}
but that gets the code after webpack and that is not what I want. I just want the code that gets put in.
<Demo>
<h1>This is a header</h1>
</Demo>
Should turn into
<div>
<h1>This is a header</h1>
<pre><h1>This is a header</h1></pre>
</div>

Related

conditional rendering to display component in vue

I have a parent comp which content should be displayd conditionally
when the userinput variable is false
The <div class="parent">
should be removed and the PopUp component displayed
I tried to use `v-if` but dont know how to remove the entire div with it elements
I could only change single elements with v-if else
parent comp
<template>
<div>
<h1>header</h1>
<div class="parent">
<h2>infos</h2>
<button>x</button>
</div>
</div>
</template>
<script>
import PopUp from './PopUp.vue';
export default {
data() {
return {
userinput: true,
}
}
}
</script>
child component - PopUp
<template>
<div>
<button>x</button>
<p>errorMessage</p>
</div>
</template>
Add v-if="userinput" doesn't work ?
If I understand what you want, you should have something like this :
// parent comp
<template>
<div>
<h1>header</h1>
<div v-if="userinput" class="parent">
<h2>infos</h2>
<button>x</button>
</div>
<PopUp v-else/>
</div>
</template>
Do not hesitate to read the Vue.js documentation

Injecting html - using slot or v-html?

So here’s my case:
I’m creating a modal via:
<Modal id="modal">
<my-component></my-component>
</Modal>
Now I want the content inside the modal to be dynamic, so I can put <input> or <table> or w/e. I’ve tried using slots (it works), but it isn’t really dynamic. I’m wondering if I missed something that would allow the slot to be a bit more dynamic.
Here’s how my modal is set up:
<div
:id="id"
class="main"
ref="main"
#click="close_modal"
>
<div ref="content" class="content" :style="{minHeight: height, minWidth: width}">
<div ref="title" class="title" v-if="title">
{{ title }}
<hr/>
</div>
<div ref="body" class="body">
<slot></slot>
</div>
</div>
</div>
I think using slots is a good choice for this. With the introduction of slot-scope in 2.5, you basically get a reverse property capability where you can set defaults within the child component and access them within the parent. They are of course completely optional to use and you're free to place whatever content you like in the slots.
Here's an example component that would allow you to customize the header, body and footers as you see fit:
// MyModal.vue
<template>
<my-modal>
<slot name="header" :text="headerText"></slot>
<slot name="body" :text="bodyText"></slot>
<slot name="footer" :text="footerText"></slot>
</my-modal>
</template>
<script>
export default {
data() {
return {
headerText: "This is the header",
bodyText: "This is the body.",
footerText: "This is the Footer."
}
}
}
</script>
// SomeComponent.vue
<template>
<div>
<my-modal>
<h1 slot="header" slot-scope="headerSlotScope">
<p>{{ headerSlotScope.text }}</p>
</h1>
<div slot="body" slot-scope="bodySlotScope">
<p>{{ bodySlotScope.text }}</p>
<!-- Add a form -->
<form>
...
</form>
<!-- or a table -->
<table>
...
</table>
<!-- or an image -->
<img src="..." />
</div>
<div slot="footer" slot-scope="footerSlotScope">
<p>{{ footerSlotScope.text }}</p>
<button>Cancel</button>
<button>OK</button>
</div>
</my-modal>
</div>
</template>
<script>
import MyModal from './MyModal.vue';
export default {
components: {
MyModal
}
}
</script>

Assigning a parent element for each <slot> in Vue

I have a vue component, say my-component, which is like this:
<div class="outer">
<div class="inner">
<slot></slot>
</div>
</div>
When I use the component:
<my-component>
<p>This is paragraph 1 </p>
<p>This is paragraph 2 </p>
</my-component>
The produced html becomes this (as it normally should):
<div class="outer">
<div class="inner">
<p>This is paragraph 1 </p>
<p>This is paragraph 2 </p>
</div>
</div>
But instead, I am looking for a way to produce something like this:
<div class="outer">
<div class="inner">
<p>This is paragraph 1 </p>
</div>
<div class="inner">
<p>This is paragraph 2 </p>
</div>
</div>
How can I associate one inner div with each of the slot elements?
One way to do this would be to use a render function instead of a template. Doing that, you can examine the content of the default slot and wrap the contents as needed.
Here is an example.
console.clear()
Vue.component("container",{
template: "#container-template",
render(h){
// filter out things like carriage returns, spaces, etc
const content = this.$slots.default.filter(c => !c.text)
// build a list of wrapped content
const wrapped = content.map(c => h('div', {attrs: {class:"inner"}}, [c]))
// render the component
return h("div", {attrs:{class:"outer"}}, wrapped)
}
})
new Vue({
el: "#app"
})
<script src="https://unpkg.com/vue#2.4.2"></script>
<div id="app">
<container>
<p>This is paragraph 1 </p>
<p>This is paragraph 2 </p>
</container>
</div>

VueJS - Pass slot to child of child component

I have a list and a list_item component that I reuse a lot inside my application. On a simplified form:
contact_list.vue
<template lang="pug">
.table
.table-header.table-row
.table-col Contact
.table-col Info
.table-body
contact-list-item(v-for='contact in contacts',
:contact='contact',
#click='doSomething()')
</template>
contact_list_item.vue
<template lang="pug">
.table-row(#click='emitClickEvent')
.table-col {{ contact.name }}
.table-col {{ contact.info }}
</template>
When I use contact_list inside a specific component, I want to be able to send a slot that will add some new columns to the contact_list_item component. This slot will use data of the specific contact that is being rendered inside that contact_list_item component to generate the new columns.
How could I achieve that? Is using slot the best approach?
Thanks in advance.
Slots are the best approach and you will need to use a scoped slot for the contact-list-item component. I'm not really familiar with pug, so I will use HTML for the example.
In contact-list you would add a slot. Notice in this case that the contact is being passed as a property. This is so we can take advantage of scoped slots.
<div class="table">
<div class="table-header table-row">
<div class="table-col">Contact</div>
<div class="table-col">Info</div>
</div>
<div class="table-body">
<contact-list-item v-for='contact in contacts'
:contact="contact"
#click="doSomething"
:key="contact.id">
<slot :contact="contact"></slot>
</contact-list-item>
</div>
</div>
Then add a slot to the contact-list-item.
<div class="table-row" #click="emitClickEvent">
<div class="table-col">{{contact.name}}</div>
<div class="table-col">{{contact.info}}</div>
<slot></slot>
</div>
Finally, in your Vue template, use the scoped template.
<div id="app">
<contact-list :contacts="contacts">
<template scope="{contact}">
<div class="table-col">{{contact.id}}</div>
</template>
</contact-list>
</div>
Here is a working example. I have no idea what your styles are but notice the id column is now displayed in the contact-list-item.
You can use template for registering slot to the child of child component.
There is also a case when you want to have many named slots.
child.vue
<template>
<div>
<h2>I'm a father now</h2>
<grandchild :babies="babies">
<template v-for="(baby, id) in babies" :slot="baby.name">
<slot :name="baby.name"/>
</template>
</grandchild>
</div>
</template>
grandchild.vue
<template>
<div>
<p v-for="(baby, id) in babies" :key="id">
<span v-if="baby.isCry">Owe...owe...</span>
<slot :name="baby.name">
</p>
</div>
</template>
parent.vue
<template>
<div>
<h2>Come to grandpa</h2>
<child :babies="myGrandChilds">
<button slot="myGrandChilds[2].name">baby cry</button>
</child>
</div>
</template>
Add to #DrSensor's answer.
In Vue3, you should use dynamic slot name.
<template>
<div>
<h2>I'm a father now</h2>
<grandchild :babies="babies">
<template v-for="(baby, id) in babies" #[baby.name]>
<slot :name="baby.name"/>
</template>
</grandchild>
</div>
</template>
To translate several slots one level down conveniently to use the method described at this link, and if you modify it a little, perhaps you will be able to transfer it deeper.

How to get html content of component in vue js

I have a html template as below
AdvanceTemplatePage.vue
<template>
<div class="content edit-page management">
<md-card class="page-card">
<md-card-header class="page-card-header">
<md-card-header-text class="page-title">
<div class="md-title">{{ 'AdvanceDetail' | translate }}</div>
</md-card-header-text>
</md-card-header>
<md-card-content class="page-content">
<div class="info-container">
<div class="label">{{ 'AdvanceStatus' | translate }}</div>
<div class="value">{{ '#AdvanceStatus' }}</div>
</div>
<div class="info-container">
<div class="label">{{ 'Amount' | translate }}</div>
<div class="value">{{ '#Amount' }} {{ '#Currency' }}</div>
</div>
<div class="info-container">
<div class="label">{{ 'RefundStartingAt' | translate }}</div>
<div class="value">{{ '#RefundStartingAt' }}</div>
</div>
<div class="info-container">
<div class="label">{{ 'RefundInstallmentQuantity' | translate }}</div>
<div class="value">{{ '#RefundInstallmentQuantity' }}</div>
</div>
<div class="info-container">
<div class="label">{{ 'Description' | translate }}</div>
<div class="value">{{ '#Description' }}</div>
</div>
</md-card-content>
</md-card>
</div>
</template>
I need to access this template html from another page.
I am trying to access html like this on another page, but I do not know how to do it.
import AdvanceTemplatePage from 'pages/print/template/AdvanceTemplatePage.vue';
methods: {
onPrint() {
const vm = this;
const template = new AdvanceTemplatePage({ el: '#templateDiv' })
}
}
How can i get html info from another page in vue.js
Any help will be appreciated.Thanks.
The template will be compiled to a render function so your code won't work. And basically you can't get the original html template.
I'm not sure what you are trying to do. If you want to get the source template content, the easiest way to achieve this is to save the template in a variable so that you can ref to it in the future.
Note that .vue doesn't support named exports so you need to put this in another .js file:
export const templateOfAdvanceTemplatePage = `
<div class="content edit-page management">
<md-card class="page-card">
...
</md-card>
</div>
`
and in your AdvanceTemplatePage.vue
import templateOfAdvanceTemplatePage from 'path/to/templateOfAdvanceTemplatePage.js'
export default {
template: templateOfAdvanceTemplatePage,
...
}
Now you can simply import templateOfAdvanceTemplatePage everywhere you want since it's just a variable.
If you want the compiled html instead of the source template, I found out a tricky way to achieve. Simply render the component and use innerHTML to get the html:
in another component, you render but hide it, also give it a ref:
<template>
...
<advance-template-page v-show="false" ref="foo"></advance-template-page>
...
</template>
now you can get the html content in your methods:
onPrint() {
const template = this.$refs.foo.$el.innerHTML
}
You can just add <slot></slot> (documentation) to your component

Categories