Vue Directive that creates a component and appends to parent - vue.js

How can i create a directive that appends another vue component to the element with the directive
For example:
<div :informable="myModel">
<span>Some html</span>
</div>
would add an icon with information using the given model
Update:
To be more clear on what i want to do
<div :informable="myModel">
<span>Some html</span>
</div>
would result to this:
<div>
<span>Some html</span>
<i>This is the information given from myModel</i>
</div>

Related

Components as slot content Vue3

I wonder how to add components as slot content. Instead of doing it like:
<template v-slot:content>CONTENT HERE</template>
I'd like to pass a component.
PkDynModalCenter:
<div class="...">
<div id="modalIndicator" class="...">
<slot name="content"></slot>
</div>
</div>
Parent:
<PkDynModalCenter v-if="togglePayment" #closeModal="togglePayment = false">
<PaymentTemplate :info="voucherInfo" name="content"></PaymentTemplate>
</PkDynModalCenter>
But it's not displayed. Docs are very vague there...
Have a look at the docs for named slots: https://vuejs.org/guide/components/slots.html
You can only use your parent code with the default slot, so your PkDynModalCenter should look like this:
<div class="...">
<div id="modalIndicator" class="...">
<slot></slot> <!-- no name → default slot -->
</div>
</div>
With your current code for the modal, you can only call it like you did in your first code snippet.

control over inherited attributes by vue component

Is there a way to have control over attributes provided through the component tag?
For example:
<my-component class="myClass" style="myStyle"></my-component>
My component:
<template>
<div>
<div>
</div>
<div>
</div>
</div>
</template>
At render Vue applies given attributes on the root:
<div class="myClass" style="myStyle">
<div>
</div>
<div>
</div>
</div>
I want to control where those attributes are applied like so:
<div>
<div>
</div>
<div class="myClass" style="myStyle">
</div>
</div>
#Boussadjra Brahim answer is definitely one way to handle it, however this will require you to pass in all of the class attributes you want everytime you define the component.
This question is answered in this SO post already as well.How to style a nested component from its parent component in Vuejs?
If you want a bit more flexibility I would suggested using interpolation and properties as below. This will let you define some default classes and pass in whatever else in addition.
<app-header :headerclass="parent-header-class"> </app-header>
Inside of your child component, you can use these properties and v-bind the class inside the HTML, as shown in the example below:
<template>
<div :class=`${headerClass} internal-class-example button`> </div>
</template>
Note: This does not allow you to use any scoped parent CSS to pass to the child. The classes you pass down must be global. Otherwise, the child component will not know what it is.

preventing Vue from aggresively reusing dom-elements

Condider the following snippet:
<template v-if="tryIsMobile" >
<div class='device device-mobile-portrait' :class="deviceClass">
<div class="device-scroller-container">
<div class='device-scroller'>
<img id='tryit-img-mobile' :src="srcUrlMobile" v-on:load="onImgLoad" v-on:error="onImgError"/>
</div>
</div>
</div>
</template>
<template v-else>
<div class='device device-tablet-landscape' :class="deviceClass" >
<div class="device-scroller-container">
<div class='device-scroller'>
<img id='tryit-img-tablet' :src="srcUrlTablet" v-on:load="onImgLoad" v-on:error="onImgError"/>
</div>
</div>
</div>
</template>
This code conditionally renders one of the two images. Some user action results in the actual shown image to be toggled.
What I'm seeing is the following: When toggling from say, tryit-img-mobile to tryit-img-tablet, the image loaded as part of tryit-img-mobile will get displayed with different dimensions instantly. However, during the time the image loads it's new source :src="srcUrlTablet", the image with src :src="srcUrlMobile" still displays.
This is probably due to Vue using the same img-tag for both the templates. How can I prevent Vue from doing this, and instead use seperate img-tags?
In cases such as this, Vue uses a special key attribute that tells it not to reuse the same element. Give each element this attribute with a unique value, and Vue will no longer reuse the same element:
<div v-if="tryIsMobile"
class="device device-mobile-portrait"
:class="deviceClass"
key="mobile"
>
...
</div>
<div v-else
class="device device-tablet-landscape"
:class="deviceClass"
key="tablet"
>
...
</div>

How do I use conditional rendering on template tag?

According to the Vue documentation I should be able to add the v-if condition to the <template> tag:
<template v-if="false">
<div>Invisible text</div>
</template>
But this will not hide the element, however it does work when added to the child element:
<template>
<div v-if="false">Invisible text</div>
</template>
Any suggestions?
I'm including the template in another .vue file:
<template>
<div id="app">
<H1 class= "main-title">Title</H1>
<span class="components">
<testtemplate></testtemplate>
</span>
</div>
</template>
The template tag of a single-file component is not rendered by Vue like normal <template> tags. It is simply one of the placeholders, along with <script> and <style> that vue-loader uses to build the component. The root element of that template is what will be the root in the component.
But, even if it worked the way you want, there would be no difference between your first and second example. Using v-if on the root will prevent the entire component's template from rendering if set to false.
Had this problem with VUE3. Using SFC just nest tag template inside another tag template :
<template>
<template v-if="false">
You won't see this
</template>
</template>

Vue.js can template without no root element or vue el specify for two div

HTML:
<div class="a">
Some HTML ...
</div>
<div class="b">
Some HTML
</div>
Javascript:
new Vue({
el: "#item_info",
....
....
(Other Config)
....
....
})
The two div above need to show the information from vue,
I tried using <template></template> like:
<template>
(my two div)
</template>
but it does not work because both divs need to be inside a root element.
I know that if I modify my html to:
<div id="item_info">
<div class="a"></div>
<div class="b"></div>
</div>
It can work, but I have no authorization to modify the base Html structure
Is there any other way that could help me solve it?
Maybe you should try to split those div's in two components and then add them to parent.
One.vue
<template>
<div class="a">
Some HTML ...
</div>
</template>
Two.vue
<template>
<div class="b">
Some HTML
</div>
</template>
Three.vue
<template>
<One></One>
<Two></Two>
</template>
If you have no authorization then I think you can't put that <template></template> either. Vue JS doesn't allow selecting multiple elements. But you can use Vue Component, please refer to this official link of Vue JS: https://v2.vuejs.org/v2/guide/components.html.
But remember Component also requires one root element.