How to get html content of component in vue js - javascript

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

Related

How to solve error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key in Vuejs?

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app-gridview">
<div>
<button class="button" v-on:click="switchView()"><span>{{ buttonSwitchViewText }}</span></button>
<button class="button" v-on:click="switchData()"><span>{{ buttonSwitchDataText }}</span></button>
</div>
<div v-bind:class="[ isGridView ? 'grid-wrapper' : 'list-wrapper' ]">
<div class="grid-row" v-if="isGridView">
<div class="grid-header" v-for="name in gridData.columns">{{ name }}</div>
</div>
<!-- GridView structure -->
<div v-if="isGridView" class="grid-row" v-for="row in gridData.data">
<div class="list-row-item" v-for="name in gridData.columns">
<div>{{ row[name] }}</div>
</div>
</div>
<!-- ListView structure -->
<div v-if="!isGridView" class="list-row" v-for="row in gridData.data">
<img v-bind:src="row.ImagePath" class="list-image" />
<div class="list-property">
<div class="list-row-item" v-for="name in gridData.columns">
<div class="list-property-name">{{ name }}</div>
<div>{{ row[name] }}</div>
</div>
</div>
</div>
</div>
</div>
Getting error as
error Elements in iteration expect to have 'v-bind:key' directives vue/require-v-for-key
How can I solve this issue, With some reference, I come to know we need to pass v-bind-key for the value, But not sure how to pass it.
Whenever we are using v-for in vuejs, we need to pass a unique value which is key which helps in properly rendering the components whenever the loop runs.
You can pass it like <div class="list-row-item" v-for="(name, index) in gridData.columns" :key="index">
The value of the key needs to be unique.
You should use uniq index inside your loop. Look hear https://v2.vuejs.org/v2/guide/list.html
<div v-if="!isGridView" class="list-row" v-for="(row, index) in gridData.data" :key="index">

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

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>

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.

Dynamic change of content better ways. AngularJS 1.6

I have REST service that gives some information for banner. I want to use this information for dynamic change of slider on main page.
So I simply use $http.get to get data, and then interpolation, with some additional ng-if's to check, if there is specific data, to displaying or not some elements.
<div class="main-block" ng-if="locale==='ru'">
<div ng-repeat="slider in restData.result" ng-class="{'active':$first}" class="slide {{ slider.location }}" ng-style="{'background-image':'url({{ slider.url.url }})'}">
<div class="content-block">
<div class="container">
<div class="right-block">
<h2>{{ slider.text1 }}</h2>
</div>
<div class="clearfix"></div>
<div ng-if="slider.text2 || slider.text3 || slider.text4 || slider.text5" class="offer-block" ng-style="{'background':'rgba({{ slider.color }},0.6)'}">
<div class="offer-block__country">{{ slider.text2 }}</div>
<div class="offer-block__name">
{{ slider.text3 }}
</div>
<div class="offer-block__days">
{{ slider.text4 }}
</div>
<div class="offer-block__date">
{{ slider.text5 }}
</div>
</div>
<div class="clearfix"></div>
<a ng-if="slider.link" ui-sref="shell.tourShow({url:'{{ slider.link }}'})" class="orange-btn">
Подробнее
</a>
</div>
</div>
</div>
</div>
But I feel like there must be better way to work with such type of data manipulation, more readable and understandable. Can you please help to find one, or give a little example, how to do it better.
It is relatively good already, the only thing I would change is not to directly map to ng-repeat="slider in restData.result"
but rather create a $scope variable like
$scope.sliders = {};
// in rest request update the local variable with most recent data
// and then use ng-repeat="slider in sliders"

Categories