Injecting html - using slot or v-html? - javascript

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>

Related

Page breaks after reload VueJS + Nuxt.js

I have strange problem. I'm creating my application where I have a couple of pages. Normally it looks ok:
But this is what happens when I reload the page:
As you can see, I pressed Ctrl + A just to show you that there is a text. Second reload doesn't help. My application is made on VueJS + NuxtJS. Did anyone meet that?
Here is HTML, if it can be useful:
<template>
<div>
<SideBar :subpages='subpages' #clicked="filterByDate" />
<div class='blog-header'>
<div class='search-div'>
<input class='search-field' placeholder='Search...'>
</div>
</div>
<div class='post-content'>
<div v-if='$route.params.id'>
<h1 class='big-text post-title'>{{ post.title }}</h1>
<h1 class='big-text post-title'>{{ post }}</h1>
</div>
<div v-else>
<div v-for='title in categoriesAndPretitles' :key='title.section'>
<div v-if='$route.params.category === title.section'>
<h1 class='big-text post-title'>{{title.title}}</h1>
<p class='description-text'>{{title.text}}</p>
</div>
</div>
<div v-for='p of posts' :key='p.id'>
<div class='post-preview' #click='toPost(p.id, p.type)'>
<div class='post-preview-img'></div>
<div class='post-preview-content'>
<p>{{ p.title }}</p>
<p class='plot'>{{ p.plot }}</p>
<p class='date'>{{ p.created_at }}</p>
</div>
</div>
</div>
</div>
</div>
<!-- <Footer />-->
</div>
</template>
Actually, answer is kinda silly, because it was about styles. I mean, styles wasn't import correctly. For main page I have this style:
body {
margin: 0;
background-color: #181919;
}
And for some reason this style also worked, for which I didn't import file with this style. And after reload it crused, but now, just by importing it work fine :p

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

How can i render ngx-quill editor content from my database to a view component?

I'm working on an angular blog app that uses ngx-quill as a text editor. I had no trouble adding records to my database. the problem occurs when I try to render content, it's not showing the data.
this is my details-post component HTML where I want to show content:
<article class="post" *ngIf="post$ | async as post; else loading">
<div class="post-thumbnail" style="background-image: url("https://images.unsplash.com/photo-1538370965046-79c0d6907d47?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80");" >
<h1 class="post-title">{{ post.titlePost }}</h1>
<div class="post-meta">February 20, 2020</div>
</div>
<div class="blog-post-content">
{{ post.contentPost }}
</div>
</article>
<ng-template #loading>
<div class="container-spinner">
<mat-spinner></mat-spinner>
</div>
</ng-template>
For ngx-quill you have to either use their own directive:
<quill-view [content]="content" format="text" theme="snow"></quill-view>
or innerHTML. More info here
<div class="ql-container ql-snow" style="border-width: 0;">
<div class="ql-editor" [innerHTML]="byPassedHTMLString">
</div>
</div>
I would suggest using their own directive.
Cheers

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