I've got a case where I have a text that begins with characters like that I do not want to escape, but then the rest of the string I do want to escape.
In Vue, given text = " <strong>something</strong>", if I do:
<p>{{ text }}</p>
It escapes all text, including the , printing out:
<strong>something</strong>
If I do this:
<p v-html="text"></p>
Then I get:
something
What I want to achieve is not escaping the but escaping all the rest of the html. My thought was doing something like this:
<p v-html="formatText()"></p>
<script>
methods: {
formatText() {
return ' ' + e('<strong>something</strong>');
}
}
</script>
where e would be some function that escapes the undesired html.
Does Vue have a method like that? Or is that something I'd have to write up? I'm not sure how Vue does its escaping under the hood.
You can achieve this by using RegEx with the help of String.replace() method.
Live Demo :
new Vue({
el: '#app',
data: {
text: ' <strong>something</strong>'
},
mounted() {
this.text = this.text.replace(/[^ ].*/, '');
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p>{{ text }}</p>
</div>
So I haven't found an answer yet to if Vue has a way to do this natively. But for the meantime I've done the following:
<p v-for="line in messageLines">
<span v-html="extractIndent(line)"></span>{{ line.trim() }}
</p>
<script>
methods: {
extractIndent(line) {
let indent = '';
for (let i = 0; i < line.length; i++) {
if (line.charAt(i) === ' ') {
indent += ' ';
} else {
break;
}
}
return indent;
}
}
</script>
This takes a text like " An indented text" and turns the spaces into and puts them in the <span> unescaped, and then escapes all the rest of the text by using Vue's brackets.
Good enough for what I need for now.
Related
I have an html string that contains some variables wrapped in {{}}. Is there a way to trigger the parsing of the html to replace {{}} with values that are present in the teamplate already
<div v-html="desc"></div>
desc = "<p>Some text {{aVar}}</p>"
I would like to be able to do something like
v-html="parse(desc)"
and {{aVar}} be replaced with the actual value that is available
Hopefully there is Vue method to do this, but I can definitely use a custom method and replace the values myself.
Thank you
For now I solved it with
function parseHtml(html = "") {
const expose = {
player,
};
return html.replace(/{{(.+?)}}/g, (_, g) => {
return _get(expose, g);
});
}
where _get is the lodash _.get
Like this?
<script setup>
import { ref } from 'vue'
const msg = ref('Hello World!')
const parse = (text) => (`<span style=\"color:red\">${text}<span>`)
</script>
<template>
<input type="text" v-model="msg">
<div v-html="parse(msg)"></div>
</template>
With inspiration from your example #orbitory
What about this?
Options API
<script>
export default {
data() {
return {
template: `<p> {{ message }} {{ message2 }}</p>`,
message: "hello",
message2: "world",
};
},
methods: {
parse(html) {
return html.replace(/{{(.+?)}}/g, (_, g) => {
return this[g.trim()];
});
},
},
};
</script>
<template>
<input v-model="message">
<input v-model="message2">
<div v-html="parse(template)" />
</template>
Demo with reactive input fields example.
https://codesandbox.io/s/how-do-i-render-data-inside-an-html-string-in-vue-before-it-is-displayed-x8oq1?file=/src/App.vue
Composition API
<script setup>
import { ref } from 'vue'
let template = "<p> {{ message }} {{ message2 }} </p>"
let message = ref('hello')
let message2 = ref('world')
let data = { message, message2 }
function parse(html) {
return html.replace(/{{(.+?)}}/g, (_, g) => {
return this[g.trim()].value;
});
}
parse = parse.bind(data)
</script>
<template>
<input v-model="message">
<input v-model="message2">
<div v-html="parse(template)"></div>
</template>
Demo with reactive input fields - based on #tauzN example.
link
I am working on a Vue app with i18n and want to list items from a large JSON file in the selected languages.
Here is an example JSON file:
items: [
{
"name_en": "Name",
"name_de": "Name"
},
{
"year_en": "Year",
"year_de": "Jahr"
}
]
I would like to get the items with v-for like this:
<div v-for="(item, index) in data.items" :key="index">
<p {{item.name_[$i18n.locale]}} </p>
</div>
$i18n.local drops the current language code such as 'en' or 'de'. But what the correct syntax is to get the item.name_en or item.name_de?
Thank you for all your suggestion!
You're almost there: it's just the square brackets are misplaced + a bit of help with concatenating strings:
<p>{{ item['name_' + $i18n.locale] }}</p>
However, I am not the biggest fan of in-template string interpolation (personal preference). You can consider offloading/abstracting that logic into a computed property:
computed: {
i18nameKey() {
return `name_${this.$i18n.locale}`;
}
}
Then, you can use i18nameKey in your template as such:
<p>{{ item[i18nameKey] }}</p>
Hi guys I'm working with Nuxt
And I have image saved on server as blob that I would like to display on client
My Component looks like this:
<template>
<div class="product-page">
<div class="product-image">
<img data-image="black" :src="{imgSrc}" alt class="active" />
</div>
<div class="product-info">
<h2>{{ product.name }}</h2>
<h3>{{ product.price }}</h3>
<div class="description">
<p>The purposes of bonsai are primarily contemplation for the viewer, and the pleasant exercise of effort and ingenuity for the grower.</p>
<p>By contrast with other plant cultivation practices, bonsai is not intended for production of food or for medicine. Instead, bonsai practice focuses on long-term cultivation and shaping of one or more small trees growing in a container.</p>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
product: {
type: Object,
default: () => {}
}
},
computed: {
imgSrc() {
const src = URL.createObjectURL(this.product.images.data);
return src;
}
}
};
</script>
Bu I keep getting following error:
URL.createObjectURL is not a function
Does anyone know what could be the problem ?
This error likely occurs on the server side, as Node does not support URL.createObjectURL(). Instead, you could create a data URL for your image in this format:
data:image/png;BASE64_OF_IMG_BLOB
where BASE64_OF_IMG_BLOB is computed from:
Node: blob.toString('base64')
Browser: btoa(blob)
imgSrc would then look like this:
export default {
computed: {
imgSrc() {
const isServer = typeof window === 'undefined'
const blob = this.product.images.data
const base64 = isServer ? blob.toString('base64') : btoa(blob)
return 'data:image/png;base64,' + base64
}
}
}
Note the :src binding should be updated to remove the curly brackets:
<img :src="{imgSrc}"> ❌ brackets unnecessary
<img :src="imgSrc"> ✅
I want to group my refs in to an object and access them by object notation. With that in mind, I now have this component:
new Vue({
el: '#app',
template: `
<div>
<input ref="input.name" type="text"/>
<input ref="input.email" type="email"/>
<input ref="input.password" type="password"/>
</div>
`,
created(){
console.log(this.$refs["input.name"]); // This works fine
console.log(this.$refs.input.name); // throws "TypeError: Cannot read property 'name' of undefined"
}
})
But it only shows this:
{
input.name: input,
input.email: input,
input.password: input,
}
What I want is something like this:
{
input: {
name: input,
email: input,
password: input,
},
}
Check fiddle here
Update:
I'm well aware of v-model but that's not what I need, I'll be doing something else with DOM.
new Vue({
el: '#app',
data() {
return {
inputs: {}
}
},
template: `
<div>
<input ref="input.name" type="text" value="123"/>
<input ref="input.email" type="email"/>
<input ref="input.password" type="password"/>
<button type="button" #click="clickMe">Click ME</button>
</div>
`,
mounted() {
this.setRefs();
console.log("this.inputs", this.inputs);
},
methods: {
setRefs() {
const INPUTS = {};
for (key in this.$refs) {
if (key.indexOf(".")) {
const KEYS_LIST = key.split(".");
INPUTS[KEYS_LIST[0]] = INPUTS[KEYS_LIST[0]] || {};
INPUTS[KEYS_LIST[0]][KEYS_LIST[1]] = this.$refs[key];
}
}
this.inputs = INPUTS;
},
clickMe() {
console.log("this.inputs.input.name.value", this.inputs.input.name.value);
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
This cannot work: refs only support strings as keys (see the docs), so there is not way of using objects here.
Also, a string with "dot notation" does not magically transform into an object with a nested property -- it's just a string. You could work around this by manually parsing the ref strings into an object structure, as has been demonstrated by #Ilia Brykin's answer. But I honestly think that you are misunderstanding the purpose of the whole ref system if you really want to do that.
P.S.: If you drop the "dort notation" part, you could use keys like input_name and access them via this.$refs.input_name.
EDIT
Another idea: you can get all input refs by their common prefix.
Object.keys(this.$refs).filter(ref => ref.startsWith('input.')
This gives you an array of ref strings of input elements.
I use VueJS 2 to render and calculate form items. Now I need to show a number if a propertie is under 10, and I need show a text message if the propertie is over or equal 10.
I use this code:
Vue.component('mycomponent', {
template: '#mytemp',
data: function() {
// ...
},
computed: {
mycomputedprop: function() {
if (this.model_a < 10) {
return '<span class="numbervalue">' + this.model_a + '€</span>';
} else {
return '<span class="textvalue">I\'ll contact you as soon as possible!</span>';
}
}
}
});
I use this code to show the value:
<div id="app">
{{ mycomputedprop }}
</div>
The problem is: if I show this value it shows the HTML code as text, not as HTML. How can I show the returned value as a HTML code?
You could use v-html
Document : Raw-HTML
<div id="app">
<div v-html="mycomputedprop"></div>
</div>
The contents of this div will be replaced with the value of the
rawHtml property, interpreted as plain HTML - data bindings are
ignored. Note that you cannot use v-html to compose template partials,
because Vue is not a string-based templating engine. Instead,
components are preferred as the fundamental unit for UI reuse and
composition.
Vue 3 Example:
const RenderHtmlApp = {
data() {
return {
rawHtml: '<span style="color: red">This should be red.</span>'
}
}
}
Vue.createApp(RenderHtmlApp).mount('#example1')
<script src="https://unpkg.com/vue#next"></script>
<div id="example1">
<p>Using mustaches: {{ rawHtml }}</p>
<p>Using v-html directive: <span v-html="rawHtml"></span></p>
</div>
Assuming that modal_a is defined in the data of your component, why not handle this within the component template?
<div id="app">
<span v-if="model_a < 10" class="numbervalue">{{model_a}} €</span>
<span v-else class="textvalue">I\'ll contact you as soon as possible!</span>
</div>