I've made a customizable flash message using Vue.js. This is working great but the next step is allow a dynamic class to be added to the component.
Flash.vue
<template>
<transition name="fade">
<div v-if="showMessage" :class="flash-container {{ styleClass }}">
<p>{{ message }}</p>
<p>{{ styleClass }}</p>
</div>
</transition>
</template>
<script>
export default{
methods: {
clearMessage () {
this.$store.commit("CLEAR_MESSAGE")
}
},
computed: {
message () {
return this.$store.getters.renderMessage
},
showMessage () {
return this.$store.getters.showMessage
},
styleClass () {
return this.$store.getters.styleClass
}
},
}
</script>
If I try to add it like this I get this error:
- invalid expression: Unexpected token { in
flash-container {{ styleClass }}
Raw expression: v-bind:class="flash-container {{ styleClass }}"
What am I missing here?
Change it to this and it will work:
:class="[styleClass, 'flash-container']"
Another option would be to split the declarations between the dynamic and static ones:
class="flash-container" :class="styleClass"
Under the hood, the separate ones are joined on render.
This this link for more info: https://v2.vuejs.org/v2/guide/class-and-style.html
If you use v-bind, you can't use mustache {{}}.
So you can do something like this:
<div class="flash-container" :class="styleClass">
</div>
or
<div :class="`flash-container ${styleClass}`">
</div>
or
<div class="flash-container" :class={'styleClass': true}>
</div>
Read this https://v2.vuejs.org/v2/guide/class-and-style.html#Binding-HTML-Classes
Related
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 have done my research trying to figure out how to achieve what I am describing below, however I had no luck.
In my Algolia index, some records have nested objects.
For example, title and subtitle attributes are of the following format:
title:
{
"en": "English title",
"gr": "Greek title"
}
I would like to execute queries only for a specific subset (in our example "en" or "gr") of these attributes, withoute "exposing" any facet in the UI — language selection would ideally be done “automatically” based on a variable (lang) passed to the Vue component with props. I am using Laravel Scout package with default Vue implementation, as described in documentation here.
My InstantSearch implementation is pretty simple, I am not defining anything specific regarding queries and searchable attributes, I am currently using all the default functionality of Algolia.
<template>
<ais-instant-search
:search-client="searchClient"
index-name="posts_index"
>
<div class="search-box">
<ais-search-box placeholder="Search posts..."></ais-search-box>
</div>
<ais-hits>
<template
slot="item"
slot-scope="{ item }"
>
<div class="list-image">
<img :src="'/images/' + item.image" />
</div>
<div class="list-text">
<h2">
{{ item.title }}
</h2>
<h3>
{{ item.subtitle }}
</h3>
</div>
</template>
</ais-hits>
</ais-instant-search>
</template>
<script>
import algoliasearch from 'algoliasearch/lite';
export default {
data() {
return {
searchClient: algoliasearch(
process.env.ALGOLIA_APP_ID,
process.env.ALGOLIA_SEARCH
),
route: route,
};
},
props: ['lang'],
computed: {
computedItem() {
// computed_item = this.item;
}
}
};
</script>
I would like to somehow pass an option to query “title.en” and “subtitle.en” when variable lang is set to “en”. All this, without the user having to select “title.en” or “subtitle.en” in the UI.
Update
Maybe computed properties is the path to go, however I cannot find how to reference search results/hits attributes (eg item.title) within computed property. It is the code I have commented out.
I think, you can use computed property. Just transform current item according to the current language variable.
new Vue({
template: "<div>{{ computedItem.title }}</div>",
data: {
langFromCookie: "en",
item: {
title: {
en: "Hello",
ru: "Привет"
}
}
},
computed: {
computedItem() {
const item = JSON.parse(JSON.stringify(this.item));
for (value in item) {
if (typeof item[value] === "object" && Object.keys(item[value]).includes(this.langFromCookie))
item[value] = item[value][this.langFromCookie];
}
return item;
}
}
}).$mount("#app")
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
If lang variable is available via props, you can check that inside list-text class and return {{title.en}} or {{title.gr}} accordingly by passing a dynamic lang value title[lang] like below
...
<div class="list-text">
<h2>
{{ item.title[lang] }}
</h2>
<h3>
{{ item.subtitle[lang] }}
</h3>
</div>
If you want to make a request according to lang prop when component mounts ,then you can make a request inside mounted() method then query like below
mounted() {
axios.get(`/getSomethingWithLang/:${this.item.title[this.lang]}`)
...
}
Looking at the Vue Documentation, I can't understand how to call a function with arguments in Vue, using data already in the template.
For example,
JavaScript
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
methods: {
reverse: function (word) {
return word.split('').reverse().join('');
}
}
})
HTML
<div id="example">
<p> {{ message }} </p>
<p> {{ reverse( {{ message }} ) }} </p>
</div>
I know the HTML is wrong, but this is similar to what I'm looking to achieve.
Code between {{ }} is interpreted as javascript, so you can pass the variable directly to the function:
<p> {{ reverse(message) }} </p>
#Jerodev answer is correct, and it's what you were looking for.
However, for the code snippet you pasted, a computed property is the way to go:
JS:
var vm = new Vue({
el: '#example',
data: {
message: 'Hello'
},
computed: {
reverse(){
return this.message.split('').reverse().join('');
}
}
})
HTML:
<div id="example">
<p> {{ message }} </p>
<p> {{ reverse }} </p>
</div>
In this way, the code is more performant, because the expression is cached, and arguably more clear, since you don't need to call the method with the argument in the html.
If you like typescript, you can write it like this
import { Vue, Component } from 'vue-property-decorator';
#Component({name: 'test-component'})
export default class TestComponent extends Vue {
private message: string = 'Hello';
get reverse(): string {
return this.message.split('').reverse().join('');
}
}
And in your template
<div id="example">
<p> {{ message }} </p>
<p> {{ reverse }} </p>
</div>
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>
My vue component, you can see below :
<template>
<div>
<div class="panel-group" v-for="item in list">
...
<div :class="'alert ' + item.created_at ? 'alert-success' : 'alert-warning'">
...
</div>
</div>
</template>
<script>
export default {
...
computed: {
list: function() {
return this.$store.state.transaction.list
},
...
}
}
</script>
When executed, it display alert-success. Whereas item.created_at = NULL
Should it display alert-warning
If the above conditions are incorrect?
How the correct writing?
if alert should always be present you could write:
<div :class="['alert', item.created_at ? 'alert-success':'alert-warning']">...</div>
Don't concatenate in the bindings, use the list notation!