I am new in Vue.js. There is my question:
I try this:
<li v-for="(msg,index) in system_message" :class="index">
in order to create different className like 0,1,2,3 for every li element.
but v-bind does not work in this way. class name remain empty.
how do I use setAttribute function in Vue?
thanks!
Numbers are not accepted as classes names, you should concatenate the index with string like :
<li v-for="(msg,index) in system_message" :class="`item${index}`">
that gives your item0, item1, item2 ...
The class attribute can not be a number, you need to concatenate it with a string. Check the code snippet below with the two examples:
new Vue({
render: h => h({
data() {
return {
system_message: ["Message 1", "Message 2", "Message 3"]
}
},
template: `
<div>
<li v-for="(msg,index) in system_message" :class="index">{{msg}}</li>
<li v-for="(msg,index) in system_message" :class="'class-'+index">{{msg}}</li>
</div>
`
}),
}).$mount('#app');
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
Related
I'm importing a simple array of 4 strings called QUIZ_DATA into my Vue.js component:
["Question1?", "Question number 2?", "This is number 3!", "And # 4"]
These 4 questions are static and won't change. I don't need them to be reactive, so I import them into my component as QUIZ_DATA, but when I try to iterate through the array, it gives me an error that the property is non-reactive.
<template>
<div v-for="(question, index) in QUIZ_DATA">
{{ question }}
</div>
</template>
<script>
import QUIZ_DATA from "~/plugins/QuizData.js";
export default {
// Nothing here yet
}
</script>
The console says:
Make sure that this property is reactive.
I got rid of the error by copying the array into my component's data object, which feels like an unnecessary step, given that the array won't change:
data(){return {quizData: QUIZ_DATA}}
Is there a way of iterating through static objects without needing to copy them into the component's data() object first?
QUIZ_DATA must be a property of the component instance if you want to access it from within the template.
Non-reactive data can be assigned to the component instance in the created hook.
created() {
this.QUIZ_DATA = QUIZ_DATA;
}
You can return your array with computed property:
const QUIZ_DATA = ["Question1?", "Question number 2?", "This is number 3!", "And # 4"]
new Vue({
el: '#demo',
computed: {
questions() {
return QUIZ_DATA
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div v-for="(question, index) in questions">
{{ question }}
</div>
</div>
Is there a way of iterating through static objects without needing to
copy them into the component's data() object first ?
Answer is Yes, ways to achieve :
By using computed property.
const QUIZ_DATA = ["Question1?", "Question number 2?", "This is number 3!", "And # 4"];
new Vue({
el: '#app',
computed: {
QUIZ_DATA() {
return QUIZ_DATA
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(question, index) in QUIZ_DATA">
{{ question }}
</div>
</div>
As data is non-reactive we can use created hook.
let QUIZ_DATA = ["Question1?", "Question number 2?", "This is number 3!", "And # 4"];
new Vue({
el: '#app',
created: function () {
this.QUIZ_DATA = QUIZ_DATA;
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(question, index) in QUIZ_DATA">
{{ question }}
</div>
</div>
JSBin and Stackoverflow snippet are below.
I am trying to have a list of input components. If all input components are filled with a value (not blank), then there should be a "new blank field" visible at the end for the user to type into. When he types into it, it should make this field apart of the list above it, maintaining focus in it.
However the problem I'm having is, focus maintains in the new field, and never moves into the array. Here is my code:
JSBIN and stackoverflow snippet - https://jsbin.com/cudabicese/1/edit?html,js,output
const app = new Vue({
el: '#app',
data: {
inputs: [
{ id:'foo', value:'foo' },
{ id:'bar', value:'bar' }
]
},
methods: {
addRow(e) {
this.inputs.push({
id: Date.now(),
value: e.target.value
})
},
deleteRow(index) {
this.inputs.splice(index, 1)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
<div id="app">
<ul>
<li v-for="(input, index) of inputs">
<input type="text" v-model="input.value">
</li>
<li v-if="inputs.filter(input => !!input.value).length">
<input type="text" #input="addRow">
</li>
</ul>
</div>
I'd recommend you put the input for the list within a computed function vs directly using the data. The examples at https://v2.vuejs.org/v2/examples/ are a good place to start.
I am reading Vuejs documentation and I can say it is confusing. without running example or complete examples they have snippets, I am trying to understanding about using one prop instead of using a each for every property. I am trying to make a example from the docs but I cannot. Following is my code.
Vue.component('blog-post', {
props:['post'],
template:`
<div class="blog-post">
<h3>{{ post.title }}</h3>
</div>
`
})
new Vue({
el : '#app',
data: {
}
})
HTML
<div id="app">
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
</div>
The error I am getting is "[Vue warn]: Property or method "posts" is not defined on the instance but referenced during render". I am confused on how one value can be used to show many objects.
props:['post'] check this plural. I figure that you are passing an array of posts to the component, and inside that component iterate over it.
You need top pass data.
Vue.component('blog-post', {
props:['post'],
template:`
<div class="blog-post">
<h3>{{ post.title }}</h3>
</div>
`
})
new Vue({
el : '#app',
data: {
posts: [
{
title: 'post-1'
},
{
title: 'post-2'
},
{
title: 'post-2'
}
]
}
})
so now
<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:post="post"
></blog-post>
you can use v-for and it will take posts data and iterate through it and pass single post to the component and component will use that property and render html.
here when blog-post will receive post it will be this [ v-bind:post="post" ]
{
title: 'post-1'
}
and it will use its post.title
v-for it will iterate this blog-post component [in our case 3 times] and pass each post object which is in array as post property of blog-post component.
if any doubts please comment.
Not sure I understand the question but I'll try to help:
The reason you get the error is because you are looping posts, but you haven't defined them anywhere, so you need to change your main instance data:
new Vue({
el : '#app',
data: {
posts: [{author: "someone", text: "something", title: "Some post"}]
}
})
There is a shorthand for v-bind, so instead you can write:
<div id="app">
<blog-post
v-for="post in posts"
:key="post.id"
:post="post"
></blog-post>
</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>
I have a set of elements being generated in a v-for directive that, if the object has a url property, get wrapped in an <a> tag - otherwise, I need it to just emit the element itself.
For example,
var data = {
events: [
{name: "Foo"},
{name: "Bar", url: "google.com"}
]
};
and the corresponding HTML:
<div v-for="event in events">
<span>{{event.name}}</span>
</div>
What I need is to wrap the <span> in an <a v-bind:href="url"> only if there is a url property present.
I understand I could use a v-if and use two spans, such as:
<span v-if="!event.url">{{event.name}}</span>
<a v-bind:href="event.url" v-if="event.url">
<span>{{event.name}}</span>
</a>
However, in my use case the <span> element here could be massive and I don't want to repeat myself just to wrap the element.
Is there a way to achieve a conditional wrap such as the above?
You can use v-html for example and render your logic inside a function:
function wrapSpan(el, link) { // link wrapper function
return `${el}`;
}
new Vue({
el: '#app',
data: {
events: [
{name: "Foo"},
{name: "Bar", url: "google.com"}
]
},
methods: {
element: function(i) {
const name = this.events[i].name;
const url = this.events[i].url || null;
const span = `<span style="color: green">${name}</span>`; // long span
return (url) ? wrapSpan(span, url) : span;
}
}
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<div v-for="(event, index) in events">
<span v-html="element(index)"></span>
</div>
</div>