I'm trying to pass data into inserted (transcluded) template.
In Angular, this would be done by modifying scope passed into transcludeFn, but I can't figure out how to do it in Vue since it simplifies things (I LOVE IT) and takes care of transclusion internally.
I've tried using v-with directive on <content> but it seems like it doesn't work for it.
Simplified component source
<template>
<div>
<ul>
<li v-repeat="tab: tabs">
<content></content>
</li>
</ul>
</div>
</template>
<script>
module.exports = {
data: function () {
return {
tabs: [{ name: 'First' }, { name: 'Second' }]
};
}
};
</script>
Usage
<div v-component="my-component">
<pre>{{ $data | json }}</pre>
</div>
Expected output
<div>
<ul>
<li>
<pre>{ "name": "First" }</pre>
<pre>{ "name": "Second" }</pre>
</li>
</ul>
</div>
Actual output
<div>
<ul>
<li>
<pre>{"tabs": [{ "name": "First" }, { "name": "Second" }]}</pre>
<pre>{"tabs": [{ "name": "First" }, { "name": "Second" }]}</pre>
</li>
</ul>
</div>
This will not work because transcluded content compiles in the parent scope.
Also now you are using v0.11.x version of Vue. Try to use v0.12.
You can pass data to the component this way:
new Vue({
el: "#app",
data: {
tabs: [{ name: 'First' }, { name: 'Second' }]
},
components: {
'my-comp': {
template: "#mycomp",
props: ['tabs'],
}
}
})
<template id="mycomp">
<div>
<ul>
<li v-repeat="tab: tabs">
<pre>{{tab | json }}</pre>
</li>
</ul>
</div>
</template>
<div id="app">
<my-comp tabs="{{tabs}}" />
</div>
<script src="https://rawgit.com/yyx990803/vue/dev/dist/vue.js"></script>
Related
The goal is to make the output look like this:
<div id="tabs">
<div id="first">
<a>tab 1</a>
<a>tab 2</a>
</div>
<div id="second">
<a>tab 3</a>
</div>
</div>
Currently I'm using this solution (using two v-for loops):
tabs.js (current)
export default {
data() {
return {
tabs: {
first: [{ name: 'tab1' }, { name: 'tab2' }],
second: [{ name: 'tab3' }],
}
}
}
template: `
<div id="tabs">
<div id="first">
<a v-for="tab in tabs.first">{{ tab.name }}</a>
</div>
<div id="second">
<a v-for="tab in tabs.second">{{ tab.name }}</a>
</div>
</div>
`
}
I had an idea to do something like this but it performs more iterations than in the case with two loops:
tabs.js (idea)
export default {
data() {
return {
tabs: {
test: [
{ name: 'tab1', category: 'first' },
{ name: 'tab2', category: 'first' },
{ name: 'tab3', category: 'second' }
]
}
}
}
template: `
<div id="tabs">
<div v-for='category in ["first", "second"]' :id='category' :key='category'>
<template v-for="tab in tabs.test">
<a v-if="tab.category === category">{{ tab.name }}</a>
</template>
</div>
</div>
`
}
I read this topic but it contains slightly different solutions, which unfortunately didn't work in this case.
There's no problem using more than one v-for loops. And there's no problem using nested v-for loops.
The problem I see with your current code is that it's not scalable. You're hard-coding the exact values of your tabs in <template />(e.g: first, second).
The main idea here is to loop through tabs and, inside each tab, to loop through each contents, without the <template> needing to know what the tab is or how many there are.
So that when you change your tabs to, say...
{
tab1: [{ name: 'intro'}],
tab2: [{ name: 'tab2-1' }, { name: 'tab2-2' }],
tab3: [{ name: 'tab3' }]
}
template still works, without needing any change.
To achieve this type of flexibility, you need to use a nested v-for loop:
<div id="tabs">
<div v-for="(items, name) in tabs" :key="name" :id="name">
<a v-for="(item, key) in items" :key="key" v-text="item.name"></a>
</div>
</div>
Demo:
new Vue({
el: '#app',
data: () => ({
tabs: {
tab1: [{
name: 'intro'
}],
tab2: [{
name: 'tab2-1'
}, {
name: 'tab2-2'
}],
tab3: [{
name: 'tab3'
}]
}
})
})
#tabs a { padding: 3px 7px }
<script src="https://v2.vuejs.org/js/vue.min.js"></script>
<div id="app">
<div id="tabs">
<div v-for="(links, name) in tabs" :key="name" :id="name">
<a v-for="(link, key) in links"
:key="key"
:href="`#${link.name}`"
v-text="link.name"></a>
</div>
</div>
</div>
But I'd take it one step further and change the tabs to be an array:
data: () => ({
tabs: [
[{ name: 'intro'}],
[{ name: 'tab1' }, { name: 'tab2' }],
[{ name: 'tab3' }]
]
})
And use :id="'tab-' + name" on tab divs if you really need those unique ids. (Hint: you don't).
It makes more sense to me.
I did not see any harm in using two v-for (one for the object keys and another for the array elements) as far as it is all dynamic. You can give a try to this solution by using of Object.keys() :
new Vue({
el: '#app',
data: {
tabs: {
first: [{ name: 'tab1' }, { name: 'tab2' }],
second: [{ name: 'tab3' }],
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="tabs">
<div v-for="tab in Object.keys(tabs)" :key="tab" :id="tab">
<a v-for="tab in tabs[tab]">{{ tab.name }}</a>
</div>
</div>
</div>
You could add a computed property being the .concat from both and loop for it
export default {
data() {
tabs: {
first: [{ name: 'tab1' }, { name: 'tab2' }],
second: [{ name: 'tab3' }],
}
},
computed: {
tabsCombined () {
return this.tabs.first.concat(this.tabs.second)
}
},
template: `
<div id="tabs">
<div v-for='category in tabsCombined' :id='category' :key='category'>
<template v-for="tab in tabs.test">
<a v-if='tab.category === category>{{ tab.name }}</a>
</template>
</div>
</div>
`
}
I am trying to use v-model on v-for loop and its throwing an error.
How can i get this to work
<ul class="">
<li class="" v-model="category.data" v-for="category in categories" :key="category.id">
<input :id="'checkbox'+ category.id" type="checkbox" #change="categoriesComputed($event)" :value="category.slug">
<label :for="'checkbox'+ category.id">
{{category.title | capitalize}}
<span>{{category.job_posts | countObj | toNumber}} Jobs</span>
</label>
</li>
</ul>
And in Vue
<script>
export default {
data(){
return {
type: [],
categories: [],
category: {
data: [],
},
}
},
}
</script>
V-model only works if it’s being used on an input element or a custom component that emits a value event that supplies the value you want v-model to be updated with.
https://v2.vuejs.org/v2/guide/forms.html
https://jsfiddle.net/amcquistan/grq3qj36/
V-model is demo in this fiddle
You have to use v-model in the <input> tags.
const app = new Vue({
el: '#app',
data: {
categories: [
{ id: 1, slug: true, title: 'FOO', job_posts: 'Foo'},
{ id: 2, slug: false, title: 'BAR', job_posts: 'Bar'},
{ id: 3, slug: true, title: 'BAZ', job_posts: 'Baz'}
]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<div id="app">
<ul class="">
<li class="" v-for="category in categories" :key="category.id">
<input
:id="'checkbox'+ category.id"
type="checkbox"
v-model="category.slug">
<label :for="'checkbox'+ category.id">
{{category.title}} {{category.slug}}
</label>
<input v-model="category.title"/>
</li>
</ul>
</div>
I just writed the vue simple code, But unable to follow the HTML effect. After traversal rendering a bit wrong. If gift object is no, for example the goods object has two data, goods_b1 + goods_b2. But i want to follow the HTML effect. Go to the HTML still. And go to the vue loops.
I want to the this effect:
Look at the javascript:
var app = new Vue({
el: "#app",
data: {
list: [{
id: 1,
name: 'A',
goods: [{
name: "goods_a1"
}],
gift: [{
name: "gift_a1",
}]
}, {
id: 2,
name: 'B',
gift: [],
goods: [{
name: "goods_b1"
}, {
name: "goods_b2"
}],
}, {
id: 3,
name: 'C',
goods: [{
name: "goods_c1"
}, {
name: "goods_c2"
}, {
name: "goods_c3"
}],
gift: [{
name: "gift_c1",
}]
}]
}
})
HTML:
<div id="app">
<div class="mui-row" v-for="item in list">
<div class="span-title-main">
<span class="span-title">{{item.name}}</span>
</div>
<br>
<ul>
<li>
<div class="mui-col" v-for="items in item.goods">
<span class="span-name">{{items.name}}</span>
</div>
<div class="addspan">+</div>
<div class="mui-col" v-for="itemss in item.gift">
<span class="span-name">{{itemss.name}}</span>
</div>
<div class="addspan">+</div>
</li>
</ul>
</div>
</div>
Are you asking that the (+) being inside the loop of your goods and gift ?
<div id="app">
<div class="mui-row" v-for="item in list">
<div class="span-title-main">
<span class="span-title">{{item.name}}</span>
</div>
<br>
<ul>
<li>
<div class="mui-col" v-for="items in item.goods">
<span class="span-name">{{items.name}}</span>
<div class="addspan">+</div>
</div>
<div class="mui-col" v-for="itemss in item.gift">
<span class="span-name">{{itemss.name}}</span>
</div>
</li>
</ul>
</div>
</div>
Edit: Remove the (+) for gifts loop as requested by OP.
Note: if the OP is asking to have a style for element in between goods and gift. I would suggest to use the css :last selector with a display:none to have this kind of effect.
It looks like the only difference is that you want a + button to appear after each item.goods instead of just one after the loop.
So put it inside the loop:
<template v-for="items in item.goods"><!-- using "template" to avoid modifying your html structure; you could of course use any tag -->
<div class="mui-col">
<span class="span-name">{{items.name}}</span>
</div>
<div class="addspan">+</div>
</template>
<div class="mui-col" v-for="items in item.gift">
<span class="span-name">{{items.name}}</span>
</div>
<!-- your image doesn't show a + button after gifts, so I've omitted it here -->
I'm learning how to use Vue and one of the methods in my practice code isn't working, any idea why?
When clicking 'Add name' an alert should pop up, but it doesn't.
new Vue({
el: '#array',
data: {
names: ['Jo', 'Joana', 'Joanna', 'Joan']
},
methods: {
addName: function() {
alert('Adding name');
}
}
});
<script src="https://unpkg.com/vue"></script>
<div id="array">
<ul>
<li v-for="name in names" v-text="name"> {{ names }} </li>
</ul>
</div>
<input type="text">
<button v-on:click="addName">Add name</button>
Try this.
new Vue({
el: '#array',
data: {
names: ['Jo', 'Joana', 'Joanna', 'Joan'],
newName: ""
},
methods: {
addName: function() {
this.names.push(this.newName);
this.newName = ""
}
}
});
<script src="https://unpkg.com/vue"></script>
<div id="array">
<ul>
<li v-for="name in names"> {{ name }} </li>
</ul>
<input v-model="newName" type="text">
<button v-on:click="addName">Add name</button>
</div>
Could you help me to solve this issue? I get this error
Cannot read property 'raw' of undefined"
when I click on the second link.
HTML
<div id="demo">
<div class="item">
<div class="menu">
object 1 -
object 2
</div>
</div>
<div class="main">
<!-- 1st LOOP on main object -->
<template v-for="object in objects" v-if="object.visible">
<!-- 2nd LOOP on children -->
<template v-for="children1 in object">
<!-- 3rd LOOP on array -->
<template v-for="children2 in children1">
{{children2 | json}}
</template>
</template>
</template>
</div>
</div>
JS
new Vue({
el: '#demo',
data: {
"objects": {
"object_1": {
"visible": false,
"children": [{
"string": "string 1"
}, {
"string": "string 2"
}]
},
"object_2": {
"visible": false,
"children": [{
"string": "string 3"
}, {
"string": "string 4"
}]
}
}
},
methods: {
onClick: function(event) {
var getID = event.path[0].id
for (object in vm.objects) {
vm.$set(`objects.${object}.visible`, false)
}
vm.$set(`objects.${getID}.visible`, true)
}
}
})
http://jsbin.com/gesigohuqo
You do not need 3 loops:
<!-- 1st LOOP on main object -->
<template v-for="object in objects" v-if="object.visible">
<!-- 2nd LOOP on array -->
<template v-for="children in object.children">
{{ children | json }}
</template>
</template>