vue: escape and render HTML string? - vue.js

I'm trying to render some HTML string in template, but I want them to be string, I don't want to render "rich text"
I started with:
<template>
<div>{{'something <like /> this'}}</div>
</template>
but vue will render the code above into follwing:
<like /> will be rendered as html tag
<div>{{'something <like></like> this'}}</div>
but what I want is this:
<div>something <like/> this</div>
I know I can put the text inside data
<template>
<div>{{text}}</div>
</template>
<script>
export default {
data() {
return {
text: 'something <like /> this'
}
}
}
</script>
but this would become tedious, and how can I do it directly inside template

I think you need to pre-process your string first like this
text.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
Then you can use it in the template

You'll need to replace the characters < and > as you've pointed out, but you'll also need to use the v-html directive since the tags in the string literal break the mustache binding.
In your script:
methods: {
htmlToText(html) {
return html.replace(/</g, '<').replace(/>/g, '>')
},
}
In your template:
<div v-html="htmlToText('something <like/> this')"></div>
Doing <div>{{ htmlToText('something <like/> this') }}</div> will not work.

Related

Vue : How to use v-bind on svg image?

I tried to load a svg image on img tag in two ways. When I use the 1st way then it works well, but when I use the 2nd way then it doesn't work.
How to make the 2nd way(v-bind:) working well?
<template>
<div>
<img src="../../assets/ico_refresh-ccwb.svg"> <!-- 1st : working -->
<img :src="imgSrc"> <!-- 2st : not working -->
</div>
</template>
<script>
export default {
data(){
return{
imgSrc : '../../assets/ico_refresh-ccwb.svg'
}
}
}
</script>
#niddddddfier you need to prefix your imgSrc property with the require keyword. eg,
data(){
return{
imgSrc : require('../../assets/ico_refresh-ccwb.svg')
}
}

passing object to component using v-for

I am trying to send a series of objects that are in an array to a child component using v-for, but when I try to access them from the child component, it tells me that the props are not defined.
Im using Quasar Framework actually
This is how I pass the data:
<div class="row justify-center">
<foo
v-for="brand in brands"
:key="brand.id"
:brand="brand"
></foo>
</div>
<script>
import foo from "src/components/foo.vue";
export default {
components: {
foo
},
data() {
return {
brands: []
};
},
methods: {
async getData() {
let x = await get.getData();
this.brands = x.data;
console.log(this.brands);
}
},
mounted() {
this.getData();
}
};
</script>
brands is an array that obtains two objects from a request made to a local database, which I have already verified that it receives the data correctly
And this is the component file and how I try to get the properties:
<q-card class="my-card" flat bordered>
<q-img
:src="require(`../assets/${brand.img}`)"
:alt="brand.img + ' Logo'"
/>
<div class="text-h5 q-mt-sm q-mb-xs">{{ brand.name }}</div>
<div class="text-caption text-grey">
<p>
{{ brand.price }}
</p>
</div>
<script>
export default {
name: "foo",
props: ["brand"],
data() {
return {
expanded: false
};
},
};
</script>
but when I try to execute the code it gives me the following error:
Error in render: "Error: Cannot find module './undefined'
I know one way to make it work, and it is by creating a property for each of the object's values, for example:
<component
v-for="brand in brands"
:key="brand.id"
:name="brand.name"
:price="brand.price"
></component>
But I dont think thats the correct way to do this....
try to change
import component from "src/components/component.vue";
to
import foo from "src/components/component.vue";
on your components section you just call foo instead of foo:component
I am not sure, but:
Looks like ${brand} is empty. Your function GetData() is async, so the <foo> is created before the GetData() has its data set/returned.
You can change
<foo v-for="brand in brands" :key="brand.id" :brand="brand"></foo>
To
<foo v-if="brands.length> 0" v-for="brand in brands" :key="brand.id" :brand="brand"></foo>
To make sure that the element is renderd after the data if set.
Note: v-if is when the html is rendered, v-show is just a css display hide, but the html is always renderd

Image path stored in variable doesn't render properly in template

If I used #/ in template, it works fine:
<img src="#/assets/images/image.png">
However if I use it in a variable, it doesn't: I just see it intact in the DOM (<img src="#/...">) which of course makes the image not render at all on the page.
Why?
<template>
<section>
<article
v-for="article in articles"
>
<img :src="article.imageUrl" />
...
</article>
</section>
</template>
<script>
export default {
data() {
return {
articles: [
{
imageUrl: "#/assets/images/AdobeStock_135975827_Preview.jpeg"
},
...
]
}
}
}
</script>
Because of the webpack, # and ~ only work in templete or import/require in script.
So, if you want to define url in a variable, let's use absolute URL.

How do I insert object created with document.createElement into template?

I like to know how I can insert a Element that has already been created with the document.createElement method into the template. I am not sure how to proceed here because eventually I would also like to bind the contents of that particular textBox. Here is the (non working) code that I have up till now to illustrate what I like to do:
<template>
<div>
<p id="status">{{ statusMessage }}</p>
<div id="output" v-html="textBox"></div>
</div>
</template>
<script>
export default {
name: 'Result',
data() {
return {
statusMessage: "Status",
textBox: Object,
}
},
mounted() {
this.textBox = this.$someModule.createTextBox()
console.log('textBox should become: '+this.textBox)
// Shows: textbox should become: [object HTMLTextAreaElement]
},
...
}
First of all, v-html is a directive that allow you to use raw html text.
ref: https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML
Second of all, you can you a ref directive to create a link to you element (ref="someName"):
<div id="output" ref="textBox"></div>
Then:
const el = this.$refs.textBox;
el.appendChild('entity which you want to append');

return elements from a vuejs method

I'm a bit new to vuejs and I'm not even sure what exactly am I looking for,
I have this template:
<template>
<md-content class="md-elevation-2">
<div class="md-layout">
<div class="md-layout-item" v-for="key in ruleData">
{{ getKeyOutput(key) }}
</div>
</div>
</md-content>
</template>
and my script is:
<script>
export default {
props: ['ruleData'],
methods: {
getKeyOutput(value) {
switch (typeof value) {
case 'string':
if (/(ban)$/g.test(value)) {
return createElement(`<h1>${ value }</h1>`) // here is the problem
} else {
return value
}
break
case 'number':
return String(value)
break
case 'boolean':
return String(value)
break
default:
return value
break
}
}
}
}
</script>
What I want to do is on some case return the string, and in some other cases like return an HTML component like h1 for example, and I can't seem to understand how I need to do this, or even if I have the correct approach for this.
You have to use v-html directive to render html tags that is stored as a string.
if you don't use v-html then vuejs by default escapes the html tags and therefore the html tags are displayed as a plain text. You don't need to use createElement() at anyplace in your code, just remove it.
Change your vue template code as below and verify if you are getting the expected result
<div
class="md-layout-item"
v-for="(value,key) in ruleData"
:key="key"
v-html="getKeyOutput(value)">
</div>
You don't need to use createElement() anymore, just return the html code as a string or template string
if (/(ban)$/g.test(value)) {
return `<h1>${ value }</h1>`; //problem solved
} else {
return value
}
Read More details about v-html in the docs https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML