How to enable v-pre only for child elements and text nodes? - vue.js

I have an HTML server-side template that looks like this:
<div id="vue">
<button v-pre>{% trans "Save" %}</button>
</div>
The server-side templating language will replace {% trans "Save" %} with the translated string, with <, > and & escaped to <, > and & respectively. However, it won't escape the Vue delimiters. For this reason, to be safe, I've used v-pre directive in the element, as is recommended when mixing server-side templating with Vue. Here is the documentation for v-pre:
v-pre: Skip compilation for this element and all its children.
Some time later, I modify the code to include a v-if condition, like this:
<div id="vue">
<button v-if="condition" v-pre>{% trans "Save" %}</button>
</div>
It doesn't work. The problem is that the v-if directive has no effect, because of the v-pre directive.
What I'm looking for is something like the v-pre directive that will turn off compilation for all the element's children (including child text nodes), but won't turn off other directives on the same element. Is this possible?

One workaround is to use a child <template> element, like this:
<div id="vue">
<button v-if="condition">
<template v-pre>{% trans "Save" %}</template>
</button>
</div>

Related

Display translation on a component in Vuejs

I want to show a translation on the title of a component.
Here is the HTML code:
<user-card
:totalUser="totalUsers"
color="primary"
icon="UserIcon"
user-title="Total users"
/>
On my user-card component I have this:
<b-card class="text-center">
<b-avatar
:variant="`light-${color}`"
class="mb-1"
size="45"
>
<feather-icon
:icon="icon"
size="21"
/>
</b-avatar>
<div class="truncate">
<h2 class="mb-25 font-weight-bolder">
{{ totalUser}}
</h2>
<span>{{ user-title }}</span>
</div>
</b-card>
And to use translation I have this syntax where I get the translated terms from the JSON file:
{{$t("Total users")}}
How can I implement this on the user-title?
Have a look at this, I have tried to replicate your scenario in code sandbox.
sample app
What you are doing wrong is that $t is a function that accepts variable name which has an actual message in it, first you have to define a variable e.g totalUserTitle: 'Total users' for multiple languages like I did in index.js, and then you can use it as $t(totalUserTitle).
Just use v-bind and pass the expression to your user-card component directly:
<user-card
...
:user-title="$t('Total users')"
/>
You're actually already using this syntax in multiple places, this directive just tells Vue to "dynamically bind one or more attributes, or a component prop to an expression", which is exactly what you're looking for here.
This will evaluate $t('Total users') as an expression and then pass the result to your component as a prop.

Mustache with condition display HTML attributes?

Is it possible to display HTML attributes in Vue mustache?
{{ (data.status)? "<div>Active</div>" : "<div>InActive</div>"}}
You can use the v-if directive in your case.
<div v-if="data.status">Active</div>
<div v-else>Inctive</div>
You cannot add HTML within a mustache expression. It causes the expression to not be evaluated.
https://jsfiddle.net/0zaknb56/
What you can do is use the v-html directive
<div v-html="data.status ? `<div>Active</div>` : `<div>Inactive</div>`">
</div>
https://jsfiddle.net/7h6osyt9/

is special attribute vs v-if / v-show

is special attribute is:
<!-- Component changes when currentTabComponent changes -->
<component v-bind:is="currentTabComponent"></component>
conditional rendering is:
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
I know the different between using v-if and v-show, but I don't know the difference between using a list of v-ifs for different cases vs using the is special attribute. When should I use them?
Does is work like v-if or v-show? I mean, does it render all the components anyways? Is is like a syntactic sugar for a list of subsequent v-ifs?
is would be useful if the list of v-ifs would all render a component if true.
Like so:
<template v-if="component == "firstComponent">
<first-component></first-component>
<template v-else-if="component == "secondComponent">
<second-component></second-component>
</template>
<template v-else-if="component == "thirdComponent">
<third-component></third-component>
</template>
This can then be reduced to:
<component :is="component"></component>
Concerning your second question
Wether component :is works like v-if or v-show depends on wether you wrap it in <keep-alive> or not. Read the documentation on this here. Note though, that using <component> a component only gets created until it is necessary the first time, wether you use <keep-alive> or not.
So:
v-if (re)creates the component everytime the condition is met.
<component :is="..."> creates the component everytime the condition is met (like v-if).
<keep-alive><component :is="..."></keep-alive> creates the
component at most 1 time (but possibly 0).
A component with only v-show on it is created exactly once.

vuejs conditional rendering leaving extra html markup

I am new to VueJS and I have a simple HTML markup where I iterate through some objects and render them in html like so:
<div v-for="item in some_counter">
<p v-if="item.some_param1 !== 'None'">
[[ item.some_param2 ]]
</p>
</div>
However, I notice that even when the condition evaluates to false, I see an extra HTML <div></div> markup. This seems very odd to me, coming from the Django world.
How do I avoid this extra markup?
The v-if applies to the element you place it on. So if you want to conditionally include the <div> you need to put the v-if on the <div> (or a parent element). It won't remove the <div> just because it is empty.
Technically you can have both v-for and v-if on the same element but it is generally discouraged as it can be confusing trying to understand which is applied first (see https://v2.vuejs.org/v2/guide/list.html#v-for-with-v-if). Instead you should include a wrapping <template> for the v-for:
<template v-for="item in some_counter">
<div v-if="item.some_param1 !== 'None'">
<p>
[[ item.some_param2 ]]
</p>
</div>
</template>
The <template> tag is special and won't add an extra element to the finished DOM.
An alternative approach would be to filter the list of items in a computed property and then iterate over the filtered list in your template.

How to use v-if and v-else without any html tag or else

List item
<ul>
<li>language</li>
< v-if= "tree()"> //which tag I may use or any other process
<li>home</li>
<li>about</li>
<>
< v-else> //which tag I may use or any other process
<li>accounts</li>
<li>listing</li>
<>
</ul>'
In the V-if which html tag i may use or any other vue.js process to work with this.
You can use template:
<template v-if="condition">
</template>
<template v-else>
</template>
Template will not be rendered in the browser. But it will parse the contents inside of this to the html.
you can sometimes use the <slot> element to make what you want. Have a look at the slot documentation here