I have a data with object, when im using v-for:
data: {
comp: {
title: {
...
},
title2: {
...
},
title3: {
...
},
}
..
div(v-for="item in comp" #click="method(item)")
How i can get name of item (title, title2, title3) in method?
Try this:
new Vue({
el:'#app',
data: {
comp: {
title: {},
title2: {},
title3: {},
}
},
methods: {
itemClicked(item) {
console.log(item);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(val,key) in comp" #click="itemClicked(key)">
{{ key }} - {{ val }}
</div>
</div>
Related
I have some data that I get from axios and pass to a Bootstrap table. In my computed properties where I declare the nameOfPerson field, I have made a click event, so that when a user clicks on the name, a modal opens. This modal also contains the data shown in the table.
However, I would like to change it so that when you click on the name of a person, ONLY the data for THAT single person gets passed to the modal. So instead of passing a prop containing data of ALL users the modal, I just want the data related to the name that I actually click on.
How would I accomplish this?
The parent:
<template>
<b-container>
<b-card class="mt-4">
<b-table
:items="dataItems"
:fields="fields"
:per-page="[5, 10]"
sort-desc
primary-key="id"
/>
</b-card>
<data-modal ref="dataModal" :selected-name="dataItems"/>
</b-container>
</template>
<script>
import {axiosComponent} from '#/axios/services';
import DataModal from '#/components/DataModal';
export default {
components: {
DataModal
},
data() {
return {
dataItems: null,
};
},
computed: {
fields() {
return [
{
key: 'nameOfperson',
label: 'name',
sortable: true
click: () => this.$refs.dataModal.show(),
},
{
key: 'ageOfPerson',
label: 'Age',
sortable: true
},
]
},
},
methods: {
load(){
axiosComponent.getData().then(result => {
this.dataItems = result.data
})
}
},
created() {
this.load()
}
};
</script>
The child (modal)
<template>
<b-modal v-model="showModal">
<div v-for="log in selectedName">
{{ log }}
</div>
</b-modal>
</template>
<script>
export default {
props: {
selectedName: Array
},
data() {
return {
showModal: false,
};
},
methods: {
show(){
this.showModal = true
}
}
};
</script>
You can use #row-selected method, take a look at following demo:
Vue.component('child', {
template: `
<b-modal v-model="showModal">
<div v-for="log in selectedName">
{{ log }}
</div>
</b-modal>
`,
props: {
selectedName: Array,
},
data() {
return {
showModal: false,
};
},
methods: {
show(){
this.showModal = true
}
}
})
new Vue({
el: "#demo",
data() {
return {
dataItems: null,
selected: null,
};
},
computed: {
fields() {
return [
{
key: 'nameOfperson',
label: 'name',
sortable: true,
},
{
key: 'ageOfPerson',
label: 'Age',
sortable: true
},
]
},
},
methods: {
load(){
// axiosComponent.getData().then(result => {
this.dataItems = [{id: 1, nameOfperson: 'aaa', ageOfPerson: 5}, {id: 2, nameOfperson: 'bbb', ageOfPerson: 25}, {id: 3, nameOfperson: 'ccc', ageOfPerson: 35}, {id: 4, nameOfperson: 'ddd', ageOfPerson: 45}]
// })
},
onRowSelected(items) {
this.selected = items
this.$refs.dataModal.show()
},
},
created() {
this.load()
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.css" />
<script src="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue.min.js"></script>
<script src="https://unpkg.com/bootstrap-vue#latest/dist/bootstrap-vue-icons.min.js"></script>
<div id="demo">
<b-container>
<b-card class="mt-4">
<b-table
:items="dataItems"
:fields="fields"
:per-page="5"
sort-desc
primary-key="id"
selectable
:select-mode="'single'"
#row-selected="onRowSelected"
/>
</b-card>
<child ref="dataModal" :selected-name="selected"></child>
</b-container>
</div>
In my project vuejs a create a list element with ul li and v-for directive vuejs like this:
<ul>
<li :class="{active: 'isActive+index'}" v-for="(car, index) in cars"></li>
</ul>
Those elements are dynamics. Sometimes are 2 sometimes are 3 or 4 elements
But I need to have a specific logic active class css for each like this:
'isActive+index'
Where this represent a dynamic computed name (already exist). But obviously this code not run and generate basic string word not a link to computed method. I want to execute those computed methods:
computed:
{
isActive1: function ()
{
return myLogic
},
isActive2: function ()
{
return myLogic
},
isActive3: function ()
{
return myLogic
},
isActive4: function ()
{
return myLogic
},
}
How can I link element with dynamic method name for execute computed with vuejs ?
new Vue({
el: '#app',
template: `
<div>
<ul>
<li v-for="(item, index) in cars" :key="index" :class="{ active: statusActive[index] }">
<strong>Car:</strong> {{item.name}} ,
</li>
</ul>
<button #click="changeCars">Change cars</button>
</div>
`,
data() {
return {
cars1: [{
name: "car1",
},
{
name: "car2",
},
{
name: "car3",
},
],
cars2: [{
name: "car1",
},
{
name: "car2",
},
{
name: "car3",
},
{
name: "car4",
},
],
cars3: [{
name: "car1",
},
{
name: "car2",
},
],
carsIndex: 1,
};
},
computed: {
cars() {
return this["cars" + this.carsIndex];
},
statusActive() {
return {
0: this.statusActive0,
1: this.statusActive1,
2: this.statusActive2,
3: this.statusActive3,
};
},
statusActive0() {
return false;
},
statusActive1() {
return true;
},
statusActive2() {
return false;
},
statusActive3() {
return true;
},
},
methods: {
changeCars() {
if (this.carsIndex < 3) {
this.carsIndex++;
} else {
this.carsIndex = 1;
}
},
},
})
.active {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app"></div>
or
new Vue({
el: '#app',
template: `
<div>
<ul>
<li v-for="(item, index) in cars" :key="index" :class="{ active: isActive(index) }">
<strong>Car:</strong> {{item.name}} ,
</li>
</ul>
<button #click="changeCars">Change cars</button>
</div>
`,
data() {
return {
cars1: [{
name: "car1",
},
{
name: "car2",
},
{
name: "car3",
},
],
cars2: [{
name: "car1",
},
{
name: "car2",
},
{
name: "car3",
},
{
name: "car4",
},
],
cars3: [{
name: "car1",
},
{
name: "car2",
},
],
carsIndex: 1,
};
},
computed: {
cars() {
return this["cars" + this.carsIndex];
},
statusActive0() {
return false;
},
statusActive1() {
return true;
},
statusActive2() {
return false;
},
statusActive3() {
return true;
},
},
methods: {
changeCars() {
if (this.carsIndex < 3) {
this.carsIndex++;
} else {
this.carsIndex = 1;
}
},
isActive(index) {
return this["statusActive" + index];
},
},
})
.active {
color: red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app"></div>
I have the following code:
const BasicInput = {
template: '<input v-model="content" #input="handleInput" />',
prop: ["value"],
data() {
return {
content: this.value
};
},
methods: {
handleInput(e) {
this.$emit("input", this.content);
}
}
};
new Vue({
el: "#app",
data: { name: "" },
mounted() {
self = this;
setTimeout(() => {
self.name = "test";
}, 2000);
},
components: { BasicInput }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<basic-input v-model="name"></basic-input>
<p>
<strong>Name:</strong> {{ name }}
</p>
</div>
How do I get the updated v-model value to also show in the input tag ?
You need to v-bind the property for the BasicInput component. The short form of it is :.
See <basic-input :value="name"></basic-input> usage below, only changed it.
const BasicInput = {
template: '<input v-model="content" #input="handleInput" />',
prop: ["value"],
data() {
return {
content: this.value
};
},
methods: {
handleInput(e) {
this.$emit("input", this.content);
}
}
};
new Vue({
el: "#app",
data: { name: "" },
mounted() {
self = this;
setTimeout(() => {
self.name = "test";
}, 2000);
},
components: { BasicInput }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<basic-input :value="name"></basic-input>
<p>
<strong>Name:</strong> {{ name }}
</p>
</div>
I got :key="index" but it still does not do it as I need.
If you add for example 6 items and select something from select on the third item and hit remove button on that item, it will delete another item, but not this one.
Here is a link to fiddle
https://jsfiddle.net/benderlio/ecyskz83/1/
Vue.config.devtools = true
Vue.component('select-component', {
data: function () {
return {
currentSelectedData: undefined,
}
},
template: `<div>
<select v-model="currentSelectedData">
<option v-for="(item,key) in dataArray" :key="key" :value="key">{{item}}</option>
</select>
<select v-if="currentSelectedData >= 0">
<option v-for="(item,key) in tempData" :key="key" :value="key">{{item}}</option>
</select>
</div>`,
watch: {
currentSelectedData(newValue, oldValue) {
console.log('', newValue, oldValue);
this.$emit("got-selected-value", newValue)
}
},
props: {
'data-array': {
type: Array,
required: true,
},
'temp-data': {
type: Array,
required: true,
},
},
})
new Vue({
el: '#app',
data: {
components: [],
dataFirstSelect: ["sheet3", "sheet4", "sheet5"
],
dataSecondSelect: [1, 2, 3]
},
methods: {
emitedValue(payload) {
console.log('Got the value from child: ', payload);
},
addComp() {
const comp = {
id: new Date().getTime()
};
this.components.push(comp)
},
remove(id) {
// this.components = this.components.filter(i => i.id !== id)
console.log('Remove', id, this.components);
//this.$delete(this.components, id)
this.components.splice(id, 1)
},
log() {
console.log('---------', this.components.map(i => i.id));
}
},
})
It works fine if you use item.id as your key instead of index and put your key on a real DOM element, not a template. Using index as a key is an anti-pattern.
Vue.config.devtools = true
Vue.component('select-component', {
data: function() {
return {
currentSelectedData: undefined,
selectedTemp: undefined
}
},
template: `<div>
<select v-model="currentSelectedData">
<option v-for="(item, key) in dataArray" :value="key">{{item}}</option>
</select>
<select v-if="currentSelectedData >= 0" v-model="selectedTemp">
<option v-for="(item, key) in tempData" :value="key">{{item}}</option>
</select>
<div>{{currentSelectedData}}</div>
<div>{{selectedTemp}}</div>
</div>`,
watch: {
currentSelectedData(newValue, oldValue) {
console.log('', newValue, oldValue);
this.$emit("got-selected-value", newValue)
}
},
props: {
'data-array': {
type: Array,
required: true,
},
'temp-data': {
type: Array,
required: true,
},
},
})
new Vue({
el: '#app',
data: {
components: [],
dataFirstSelect: ["sheet3", "sheet4", "sheet5"],
dataSecondSelect: [1, 2, 3]
},
methods: {
emitedValue(payload) {
console.log('Got the value from child: ', payload);
},
addComp() {
const comp = {
id: new Date().getTime()
};
this.components.push(comp)
},
remove(id) {
// this.components = this.components.filter(i => i.id !== id)
console.log('Remove', id, this.components);
//this.$delete(this.components, id)
this.components.splice(id, 1)
},
log() {
console.log('---------', this.components.map(i => i.id));
}
},
})
.select-component {
display: block;
margin: 10px;
}
.item {
padding: 10px;
margin: 10px;
border: 1px solid gray;
}
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="app">
<button #click="addComp">Add</button>
<template v-for="(item,index) in components">
<div class="item" :key="item.id">
id: {{item.id}} {{index}}
<button #click="remove(index)">Remove</button>
<select-component class="select-component" v-on:got-selected-value="emitedValue" :data-array='dataFirstSelect'
:temp-data='dataSecondSelect'>
</select-component>
</div>
</template>
</div>
I have an object like this:
myObject: {
items: [{
title: '140',
isActive: true,
}, {
title: '7',
isActive: false
}, {
title: '10',
isActive: false
}]
}
Which I'm using like this:
<my-component :items="myObject.items"></my-component>
This is how the component looks like:
<template>
<div class="i-panel panel-container d-flex"
<div
v-for="item in prefs.items"
class="panel-item"
#click="onClick(item)">
<!-- some content -->
</div>
</div>
</template>
<script>
export default {
name: 'IPanel',
props: {
items: {
type: Array,
default () {
return []
}
}
},
computed: {
// code
prefs () {
return {
items: this.items
}
}
},
methods: {
onClick (item) {
this.prefs.items.forEach(item => {
if (JSON.stringify(item) === JSON.stringify(clickedItem)) {
item.isActive = true
}
})
}
}
}
</script>
When I click an item (and that item is the same as the clickedItem), it's supposed to become isActive true. It does. But I have to refresh the Vue devtools or re-render the page for the change to take effect.
Why isn't item.isActive = true reactive?
In the code you posted, you are using a clickedItem object that is not defined anywhere. I don't know if this is just in the process of writing your question or if it is your problem.
However, when using clickedItem the right way, it seems to work: https://jsfiddle.net/d5z93ygy/4/
HTML
<div id="app" class="i-panel panel-container d-flex">
<div
v-for="item in prefs.items"
class="panel-item"
#click="onClick(item)">
<!-- some content -->{{ item.isActive ? 'active' : 'inactive' }}
</div>
</div>
JS
new Vue({
el: "#app",
data: {
items: [{
title: '140',
isActive: true,
}, {
title: '7',
isActive: false
}, {
title: '10',
isActive: false
}]
},
computed: {
// code
prefs () {
return {
items: this.items
}
}
},
methods: {
onClick (clickedItem) {
this.prefs.items.forEach(item => {
if (JSON.stringify(item) === JSON.stringify(clickedItem)) {
item.isActive = true
}
})
}
}
})
Change
<div
v-for="item in prefs.items"
class="panel-item"
#click="onClick(item)">
<!-- some content -->
</div>
to
<div
v-for="(item, index) in prefs.items"
class="panel-item"
#click="onClick(index)">
<!-- some content -->
</div>
Then, in your change method, go like this:
onClick (index) {
Vue.set(this.items, index, true);
}
https://v2.vuejs.org/v2/guide/list.html#Object-Change-Detection-Caveats