I am trying to dynamically create a form (why? It's 200+ fields long and I am not permitted to modify it). The entire app is in the VueJs environment.
The problem I'm having is that each field requires different things (obviously). I'm trying to add attributes dynamically to each field, which would allow me to render the entire form dynamically, rather than hard coding a 200+ field form. So in my stupidity I'm taking more time trying to solve this problem than it would take to just hard code the form. Oh well...
Here's a specific (simplified) example of what I want to do...
data() {
return {
form: {
input1: {value: "", classIWantToDynamicallyAdd: "FieldSizeSmallAF"},
input2: {value: "", classIWantToDynamicallyAdd: "FieldSizeBigAF"},
//Repeat 200 times
}
}
}
Now ultimately I want to get the value of "classIWantToDynamicallyAdd" and :class="put it here"
The HTML looks like this:
<template>
<div>
<div v-for="(field, index)" in form" :key="index">
<div class="labelAndInput" :class="**I don't know what to do here**">
<label>index</label> // Successfully outputs: "input1", "input2", etc...
<input>
</div>
</div>
</div>
</template>
Hopefully that's somewhat clear. I expected form.index.classIWantToDynamicallyAdd to work, but it did not, i got the following error:
TypeError: "_vm.form.index is undefined".
Thanks in advance!
You could do :class="[field.classIWantToDynamicallyAdd]" :
<div v-for="(field, index)" in form" :key="index">
<div class="labelAndInput" :class="[field.classIWantToDynamicallyAdd]">
....
<input>
</div>
</div>
You could define those class names on data() and just bind it to :class
Example:
https://jsfiddle.net/pguti19/hL2vamnw/
More help:
https://michaelnthiessen.com/dynamically-add-class-name/
<div id="app">
<h1>
Forms:
</h1>
<div v-for="(field, index) in form" :key="index">
<span :class="field.class">
Using {{field.class}} class
</span>
</div>
</div>
<script>
new Vue({
el: "#app",
data: {
form: {
input1: {value: "", class: "red-theme"},
input2: {value: "", class: "blue-theme"},
input3: {value: "", class: "green-theme"}
},
theme1: 'blue-theme',
theme2: 'red-theme',
theme3: 'green-theme'
},
methods: {
toggle: function(todo){
todo.done = !todo.done
}
}
})
</script>
Related
Here's what I'm trying to accomplish:
<div v-for="columns in pageStructure"
//Print from here
<div v-for="htmlIWantPrinted in array">
...some content...
<button #click="printElementDiv()">Print</button>
</div>
//To here
</div>
I'm trying to print the specific content created in the for-loop. Button included.
Since there are multiple columns, I can't just put an id on it and I can't use ref either for the same reason, and using the element as a parameter for the method grabs the object instead of the html.
Simply add the value you passed to v-for loop and see the magic. This might not actually be what you want, but it should give a better understanding of what you're going to do. This is just enough.
var app = new Vue({
el: '#app',
data: {
pageStructure: ['Welcome', 'to', 'vue', 'world']
},
methods: {
printElementDiv(el) {
console.log(el)
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="column in pageStructure">
<h1>Div: {{column}}</h1>
<button #click="printElementDiv(column)">Print</button>
</div>
</div>
I ended up using #RohìtJíndal' answer from the comments:
<div v-for="columns in pageStructure"
//Print from here
<div v-for="htmlIWantPrinted in array" :id="htmlIWantPrinted.id">
...some content...
<button #click="printElementDiv()">Print</button>
</div>
//To here
</div>
If you don't have a variable available, you can make one and increment it as part of the loop.
I have an array of objects as boxData in my initial data. How would I go about making the word "here" a hyperlink that I can use whenever referencing boxData?
data() {
return {
boxData: [
{
body: "This is the link here."
},
{
body: "Normal text."
}
]
}
}
Child component
<div v-for="(box, index) in boxData" class="box">
<div>
{{ box.body }}
</div>
</div>
Ideally, the objects with a link would have a property like url. Then, assuming all of the links should say "This is the link here", you could do:
<div v-for="(box, index) in boxData" class="box">
<div>
<template v-if="box.url">
This is the link <a :href="box.url">here</a>.
</template>
<template v-else>
{{ box.body }}
</template>
</div>
</div>
Then you don't need "This is the link here" in any of the objects.
You just have to put the data into the hyperlink like so:
<a :href="boxData.body">Here</a>
Much better
<router-link :to="boxData.body">Here</router-link>
I'm attempting to create components using Vue, so that I can remove a lot of duplicated HTML in a site I'm working on.
I have a <ym-menucontent> component, which within it will eventually have several other components, conditionally rendered.
While doing this I've hit a wall and so have simplified everything to get to the root of the problem.
When rendering the ym-menucontent component the first sub-component is the only one which gets rendered and I can't work out why or how to get around it...
<template id="menucontent">
<div>
<ym-categories :menuitem="menuitem"/>
<ym-rootmaps :menuitem="menuitem"/>
<p>1: {{menuitem.rootMapsTab}}</p>
<p>2: {{menuitem.exploreTab}}</p>
</div>
</template>
<template id="rootmaps">
<div>Root Maps</div>
</template>
<template id="categories">
<div>Categories</div>
</template>
app.js
Vue.component('ym-menucontent', {
template: '#menucontent',
props: ['menuitem'],
data: function() {
return {
customMenu: window.customMenuJSON
}
}
});
Vue.component('ym-rootmaps', {
template: '#rootmaps',
props: ['menuitem'],
data: function() {
return {
customMenu: window.customMenuJSON,
rootMaps: window.rootAreas
}
}
});
Vue.component('ym-categories', {
template: '#categories',
props: ['menuitem'],
data: function() {
return {
customMenu: window.customMenuJSON,
rootMaps: window.rootAreas
}
}
});
usage...
<div
v-for="mi in customMenu.topLevelMenuItems"
:id="mi.name"
class="page-content tab swiper-slide">
<ym-menucontent :menuitem="mi"/>
</div>
Output
<div>Categories</div>
if I switch around ym-cateogries and ym-rootmaps then the output becomes...
<div>Root Maps</div>
if I remove both then I see...
<p>1: true</p>
<p>2:</p>
I'd expect to see a combination of all of them...
<div>Categories</div>
<div>Root Maps</div>
<p>1: true</p>
<p>2:</p>
This is probably because you're using self-closing components in DOM templates, which is recommended against in the style-guide ..
Unfortunately, HTML doesn’t allow custom elements to be self-closing -
only official “void” elements. That’s why the strategy is only
possible when Vue’s template compiler can reach the template before
the DOM, then serve the DOM spec-compliant HTML.
This should work for you ..
<template id="menucontent">
<div>
<ym-categories :menuitem="menuitem"></ym-categories>
<ym-rootmaps :menuitem="menuitem"></ym-rootmaps>
<p>1: {{menuitem.rootMapsTab}}</p>
<p>2: {{menuitem.exploreTab}}</p>
</div>
</template>
<div
v-for="mi in customMenu.topLevelMenuItems"
:id="mi.name"
class="page-content tab swiper-slide">
<ym-menucontent :menuitem="mi"></ym-menucontent>
</div>
I'm trying to learn vue.js. I'm adding list of elements, I want to add class="active" only to the first element in the for loop. following is my code:
<div class="carousel-inner text-center " role="listbox">
<div class="item" v-for="sliderContent in sliderContents">
<h1>{{ sliderContent.title }}</h1>
<p v-html="sliderContent.paragraph"></p>
</div>
</div>
So the first element should look like something this:
<div class="item active">
<h1>WELCOME TO CANVAS</h1>
<p>Create just what you need for your Perfect Website. Choose from a wide<br>range of Elements & simple put them on your own Canvas</p>
</div>
I'm able to get the data so everything is working perfectly fine.
And following is my script code:
<script>
export default{
data() {
return {
sliderContents: [
{
title: "WELCOME TO CANVAS",
paragraph: "Create just what you need for your Perfect Website. Choose from a wide<br>range of Elements & simple put them on your own Canvas"
},
{
title: "WELCOME TO CANVAS",
paragraph: "Create just what you need for your Perfect Website. Choose from a wide<br>range of Elements & simple put them on your own Canvas"
},
{
title: "WELCOME TO CANVAS",
paragraph: "Create just what you need for your Perfect Website. Choose from a wide<br>range of Elements & simple put them on your own Canvas"
},
{
title: "WELCOME TO CANVAS",
paragraph: "Create just what you need for your Perfect Website. Choose from a wide<br>range of Elements & simple put them on your own Canvas"
}
]
}
}
}
Help me out.
const TextComponent = {
template: `
<p>{{ text }}</p>
`,
props: ['text'],
};
new Vue({
components: {
TextComponent,
},
template: `
<div>
<text-component
v-for="(item, index) in items"
:class="{ 'active': index === 0 }"
:text="item.text">
</text-component>
</div>
`,
data: {
items: [
{ text: 'Foo' },
{ text: 'Bar' },
{ text: 'Baz' },
],
},
}).$mount('#app');
.active {
background-color: red;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
</head>
<body>
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
</body>
</html>
Above is a snippet demonstrating a solution to your problem. Here's an outline of it:
Inside v-for blocks we have full access to parent scope properties. v-for also supports an optional second argument for the index of the current item.
– https://v2.vuejs.org/v2/guide/list.html#Basic-Usage
The v-for directive has a second argument giving you the index of the item.
v-for="(item, index) in items"
Since you want the active class on the first item you can use an expression testing if the index is 0 and bind it to the class attribute.
:class="{ 'active': index === 0 }"
The easiest solution is to check every element if index is equal to 0 and then setting the active class (or the class you needed). Here is the code of class definition:
:class="{ 'active': index === 0 }"
Here is working example of making Bootstrap Tabs:
<ul class="nav nav-tabs tab-nav-right" role="tablist">
<li role="presentation" :class="{ 'active': index === 0 }" v-for="(value, index) in some_array" v-bind:key="index">
{{some_array[index]}}
</li>
</ul>
Also, if you have multiple classes you can mix them like this:
:class="['tab-pane fade', (index === 0 ? 'active in' : 'something_else')]"
To put active class to first element in loop, basically, you are trying to programattically control the class via VuejS.
VueJS allows you to bind the class of the anchor tag (say, but it could even be an li tag) directly to the index of the li element so that when the vuejs variable bound to the index changes, the class also changes. Check these two links for more details
This is the crux of the solution
:class="{current:i == current}
available on the fiddle below and another post that explains in blog format how class of an li element can be dynamically controlled in vuejs
https://jsfiddle.net/Herteby/kpkcfcdw/
https://stackoverblow.wordpress.com/2021/04/03/how-modern-javascript-makes-click-simulation/
I have a simple model:
var model = [{
content: "",
type: "photo",
src: "xxx"
}, {
content: "",
type: "quote",
text: "blah"
}];
and a simple template:
{{if type eq='photo'}}
<img src="{{:src}}" />
<div class="photo-caption">
{{:caption}}
</div>
{{else type eq='quote'}}
<div class="quote-text">
{{:text}}
</div>
{{/if}}
The problem is that the template renders nothing at all when the type is "quote". If I change it slightly to two ifs instead of an if-else, it renders the quote, but also renders the div class="photo-caption">. I need it to only render one or the other. I have a feeling it's a simple matter of syntax, but can't seem to find sufficient docs on how this is done correctly on the JsRender site.
Here's a fiddle. The two templates should behave exactly alike. Instead one renders both, the other renders only the image.
I got it:
{{if type == 'quote' }}
<div>
{{: text }}
</div>
{{else type == 'photo'}}
<div>
{{: src }}
</div>
{{/if}}
http://jsfiddle.net/4QzZX/2/
When you tried the version with two if statements, did you remember to add a {{/if}} in addition to changing the {{else}} into an {{if}}?
{{if type eq='photo'}}
<img src="{{:src}}" />
<div class="photo-caption">
{{:caption}}
</div>
{{/if}}
{{if type eq='quote'}}
<div class="quote-text">
{{:text}}
</div>
{{/if}}