Separate Array push in Vuejs - javascript

I am trying to get value from object and push into array using Vue. I wanted to separate every value when into different array every time I click my item. Every time I click todo should be push on different array, how I can separate to push into different array
new Vue({
el: "#app",
data: {
todos: [
{ text: "Learn JavaScript"},
{ text: "Learn Vue"},
{ text: "Play around in JSFiddle"},
{ text: "Build something awesome"}
],
mytodo:[]
},
methods: {
myClickTodo: function(e){
this.mytodo.push(e.target.innerText)
console.log(e.target.innerText)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<h2>My list One:</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo">
{{ todo.text + " from todo one" }}
</li>
</ul>
<p>todo 1 </p>
<p>{{mytodo}}</p>
<hr>
<h2>My list Two:</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo">
{{ todo.text + " from todo two" }}
</li>
</ul>
<p>todo 2</p>
<p>{{mytodo}}</p>
</div>

Quick fix
One solution is to change mytodos into an array of 2 arrays (one for each TODO list):
data() {
return {
mytodo: [[], []]
};
}
Then, update your click-handler to pass the specific array element of mytodos along with the todo item to be added:
<!-- My list One -->
<li v-for="todo in todos" #click="myClickTodo(mytodos[0], todo)">
<!-- My list Two -->
<li v-for="todo in todos" #click="myClickTodo(mytodos[1], todo)">
And update myClickTodo to handle these new arguments:
methods: {
myClickTodo(mytodo, todo) {
mytodo.push(todo.text);
}
}
new Vue({
el: '#app',
data: () => ({
todos: [
{ text: "Learn JavaScript"},
{ text: "Learn Vue"},
{ text: "Play around in JSFiddle"},
{ text: "Build something awesome"}
],
mytodo: [[], []]
}),
methods: {
myClickTodo(mytodo, todo) {
mytodo.push(todo.text);
console.log(todo.text);
}
}
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<h2>My list One:</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo(mytodo[0], todo)">
{{ todo.text + " from todo one" }}
</li>
</ul>
<p>todo 1 </p>
<p>{{mytodo[0]}}</p>
<hr>
<h2>My list Two:</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo(mytodo[1], todo)">
{{ todo.text + " from todo two" }}
</li>
</ul>
<p>todo 2</p>
<p>{{mytodo[1]}}</p>
</div>
Components
A cleaner solution is to encapsulate the TODO list into a reusable component (e.g., named "my-list"):
Vue.component('my-list', {
data: () => ({
title: '',
mytodo: [],
}),
props: {
todos: {
type: Array,
default: () => []
}
},
template: `<div>
<h2>{{title}}</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo(mytodo, todo)">
{{ todo.text + " from todo one" }}
</li>
</ul>
<p>{{mytodo}}</p>
</div>`,
methods: {
myClickTodo(mytodo, todo) {
mytodo.push(todo.text);
console.log(todo.text);
}
}
});
...which would allow you to simplify your app template to this:
<my-list title="My List One:" :todos="todos"></my-list>
<my-list title="My List Two:" :todos="todos"></my-list>
Vue.component('my-list', {
data: () => ({
mytodo: [],
}),
props: {
title: '',
todos: {
type: Array,
default: () => []
}
},
template: `<div>
<h2>{{title}}</h2>
<ul>
<li v-for="todo in todos" #click="myClickTodo(mytodo, todo)">
{{ todo.text + " from todo one" }}
</li>
</ul>
<p>{{mytodo}}</p>
</div>`,
methods: {
myClickTodo(mytodo, todo) {
mytodo.push(todo.text);
console.log(todo.text);
}
}
});
new Vue({
el: '#app',
data: () => ({
todos: [
{ text: "Learn JavaScript"},
{ text: "Learn Vue"},
{ text: "Play around in JSFiddle"},
{ text: "Build something awesome"}
],
}),
})
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<my-list title="My List One:" :todos="todos"></my-list>
<my-list title="My List Two:" :todos="todos"></my-list>
</div>

Related

How to make a clone of the array object with new id and same name?

I'm new at vue3 and javascript. I have 2 lists and drag and drop system. The problem is when I drag and drop component from one list to another, I increase an id by 1, but I can't get the name of dragged object and display it. The problem displayed at methods in method "cloneComponent"
<template>
<div class="full-zone">
<div class="components">
<h3>Компоненты бота:</h3>
<draggable
class="dragArea"
:list="list1"
:group="{ name: 'people', pull: 'clone', put: false }"
:clone="cloneComponent"
#change="log"
item-key="id"
>
<template #item="{element}">
<div class="list-group-item">
{{ element.name }}
</div>
</template>
</draggable>
</div>
<div class="constructor">
<h3>Конструктор</h3>
<draggable
class="constructor-list"
:list="list2"
group="people"
#change="log"
item-key="id"
>
<template #item="{ element, index }">
<div class="list-group-item">
{{ element.name }}
<div>
<input type="text" class="input" v-model="element.text" placeholder="Введите текст компонента" />
<span #click="remove(index)" class="remove">x</span>
</div>
</div>
</template>
</draggable>
</div>
<div>
<button class="btn">Сгенерировать бота</button>
</div>
<rawDisplayer class="col-3" :value="list1" title="List 1" />
<rawDisplayer class="col-3" :value="list2" title="List 2" />
</div>
</template>
<script>
import draggable from "vuedraggable";
let idGlobal = 4;
export default {
name: "clone",
display: "Clone",
order: 2,
components: {
draggable
},
data() {
return {
list1: [
{ name: "Сообщение", text: "", id: 1 },
{ name: "Заметка", text: "", id: 2 },
{ name: "Кнопка", text: "", id: 3 },
],
list2: []
};
},
methods: {
log: function(evt) {
window.console.log(evt);
},
cloneComponent() {
return {
id: idGlobal ++,
}
},
remove(idx) {
this.list2.splice(idx, 1);
},
}
};
</script>
How to return not only "id", but "name" at the same time? Please help.
You need to send the item to the other list
// tolist = can be 1 or 2
cloneComponent(item, tolist) {
if (tolist === 2) {
this.list2.push(item)
} else {
this.list1.push(item)
}
}

How use a button in v-for loop in Nuxt.js?

I am using a card component of vuetify in a loop to display data but when I click on the button present in the card, all buttons of all cards present in the loop open. How can I do so that only the card button I clicked opens?
Here is my template :
<template>
<v-row>
<v-col
v-for="(prop, i) in Object.keys(linkIdeal)"
:key="i"
cols="6"
lg="2"
md="3"
sm="4"
class="mb-6"
#click="console.log(prop)"
>
<v-card
v-if="linkIdeal[prop].plant_associated[0].category == '1'"
style="z-index: 0"
:class="`mx-auto my-12 plant-card Vegetables`"
width="100%"
>
<v-img
:src="`${linkIdeal[prop].plant_associated[0].image}`"
width="100%"
height="200"
></v-img>
<v-card-title class="white--text card-title justify-center">
{{ linkIdeal[prop].plant_associated[0].name }}
</v-card-title>
<v-card-actions #click="show = !show" style="cursor: pointer">
<span class="white--text btnDescr">Description</span>
<v-spacer></v-spacer>
<v-btn icon>
<v-icon class="white--text">
{{ show ? 'mdi-chevron-up' : 'mdi-chevron-down' }}
</v-icon>
</v-btn>
</v-card-actions>
<v-expand-transition>
<div v-show="show">
<v-divider></v-divider>
<v-card-text>
<span
class="white--text"
v-html="linkIdeal[prop].description"
></span>
</v-card-text>
</div>
</v-expand-transition>
</v-card>
</v-col>
</v-row>
</template>
Here is my script :
import {
mapGetters
} from "vuex";
export default {
props: {},
data: () => ({
linkIdeal: [],
show: false,
}),
computed: {
console: () => console,
...mapGetters({
plantActive: 'permatheque/getPlant',
}),
},
methods: {
async getAssociatedPlant() {
this.$axios.$get('...')
.then(response => {
//this.$store.commit('permatheque/setPlantAssociations', response)
this.linkIdeal = response
console.log(this.linkIdeal)
}).catch(error => {
console.log(error)
});
},
},
mounted() {
this.getAssociatedPlant()
}
}
Thanks for your answer
You are using 1 show variable as a state for all the cards, their open/close state all depend on that, thus when you toggle this state, all cards act accordingly.
If you want to have an open/close state for every single card, then you should add it to each one (like in their own component) OR you can track the opened cards (e.g. by ID) in an array. Both could be a solution to your problem. (snippet coming to demonstrate)
OPEN/CLOSE STATE TRACKED IN AN ARRAY
Vue.component('ToggleCard', {
props: ['id', 'label', 'open'],
methods: {
onClick() {
this.$emit("update:open")
}
},
template: `
<div
class="cursor-pointer"
:class="{
open: open
}"
#click="onClick"
>
{{ label }} - {{ open }}
</div>
`
})
new Vue({
el: "#app",
data() {
return {
openedCards: [],
cards: [{
id: 0,
label: "CARD 1",
},
{
id: 1,
label: "CARD 2",
},
{
id: 2,
label: "CARD 3",
},
]
}
},
methods: {
isOpen(id) {
return this.openedCards.includes(id)
},
updateOpenedCards(id) {
if (this.isOpen(id)) {
this.openedCards = this.openedCards.filter(cardId => cardId !== id)
} else {
this.openedCards = [...this.openedCards, id]
}
}
},
template: `
<div>
<toggle-card
v-for="card in cards"
:key="card.id"
:id="card.id"
:label="card.label"
:open="isOpen(card.id)"
#update:open="() => updateOpenedCards(card.id)"
></toggle-card>
</div>
`
})
.cursor-pointer {
cursor: pointer;
}
.open {
background: green;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>
OPEN/CLOSE STATE TRACKED IN AN SEPARATE COMPONENTS
Vue.component('ToggleCard', {
props: ['id', 'label'],
data() {
return {
open: false,
}
},
template: `
<div
class="cursor-pointer"
:class="{
open: open
}"
#click="open = !open"
>
{{ label }} - {{ open }}
</div>
`
})
new Vue({
el: "#app",
data() {
return {
cards: [{
id: 0,
label: "CARD 1",
},
{
id: 1,
label: "CARD 2",
},
{
id: 2,
label: "CARD 3",
},
]
}
},
template: `
<div>
<toggle-card
v-for="card in cards"
:key="card.id"
:id="card.id"
:label="card.label"
></toggle-card>
</div>
`
})
.cursor-pointer {
cursor: pointer;
}
.open {
background: green;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app"></div>

Adding item to cart and removing from cart

I have a + button to add item to cart,it works. But at the same time when number increments in cart I need number that says in stock will decrement number in stock that displays it doesn't work …
I need to do the same with - button
I really need the displayed inStock number to change when I add or remove items from cart
Can someone please help me? I'm new at this
Vue.component('product', {
template:
`
<div class="product">
<div class="product-image">
<img :src="image" />
</div>
<div class="product-info">
<h1>{{ product }}</h1>
<p v-if="inStock">In Stock {{inStock}}</p>
<p v-else>Out of Stock</p>
<button #click="addToCart"
:disabled="!inStock"
:class="{ disabledButton: !inStock }"> + </button>
<button #click="removeFromCart"> - </button>
</div>
</div>
`,
data() {
return {
product: 'Hoodie',
image: 'hoodie.jpeg',
inStock: 10,
cart: 0
}
},
methods: {
addToCart: function() {
this.$emit('add-to-cart')
},
removeFromCart: function() {
this.$emit('remove-from-cart')
}
}
})
var app = new Vue({
el: '#app',
data: {
cart: 0,
inStock: 10
},
methods: {
updateCart() {
this.cart += 1,
this.inStock -= 1,
},
removeItem() {
this.cart -= 1,
this.inStock += 1
}
}
})
HTML:
<div class="nav-bar"></div>
<div id="app">
<div class="cart">
<p>Cart({{ cart }})</p>
</div>
<product #add-to-cart="updateCart" #remove-from-cart="removeItem"></product>
</div>
Inside your component, remove the data attributes inStock and cart and props section.
Vue.component('product', {
template:
`
<div class="product">
<div class="product-image">
<img :src="image" />
</div>
<div class="product-info">
<h1>{{ product }}</h1>
<p v-if="inStock">In Stock {{inStock}}</p>
<p v-else>Out of Stock</p>
<button #click="addToCart"
:disabled="!inStock"
:class="{ disabledButton: !inStock }"> + </button>
<button #click="removeFromCart"> - </button>
</div>
</div>
`,
data() {
return {
product: 'Hoodie',
image: 'hoodie.jpeg',
}
},
props: {
inStock: {
type: Number,
default: 0
},
cart : {
type: Number,
default: 0
}
},
methods: {
addToCart: function() {
this.$emit('add-to-cart')
},
removeFromCart: function() {
this.$emit('remove-from-cart')
}
}
})
var app = new Vue({
el: '#app',
data: {
cart: 0,
inStock: 10
},
methods: {
updateCart() {
this.cart += 1,
this.inStock -= 1,
},
removeItem() {
this.cart -= 1,
this.inStock += 1
}
}
})
Then in your parent component, pass the props.
Parent Component (HTML)
<div class="nav-bar"></div>
<div id="app">
<div class="cart">
<p>Cart({{ cart }})</p>
</div>
<!-- changes for props added below -->
<product :cart="cart" :inStock="inStock" #add-to-cart="updateCart" #remove-from-cart="removeItem"></product>
</div>

Vue.js dynamic classes

I have some html using Vue.js here:
<div id="app">
<ul class="navbar-nav">
<li class="nav-item" v-for="tab in tabs">
{{ tab.name }}
</li>
</ul>
</div>
I have the javascript here:
var app = new Vue({
el: '#app',
data: {
tabs: [
{ name: "Home", active: "" },
{ name: "Challenges", active: "active" },
{ name: "Scoreboard", active: "" },
{ name: "About", active: "" }
]
}
});
I want to set class to tabs.active since I'm using bootstrap. How can I do that?
Add
v-bind:class="tab.active"
So your code should look like this:
var app = new Vue({
el: '#app',
data: {
tabs: [{
name: "Home",
active: ""
},
{
name: "Challenges",
active: "active"
},
{
name: "Scoreboard",
active: ""
},
{
name: "About",
active: ""
}
]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<ul class="navbar-nav">
<li class="nav-item" v-for="tab in tabs" v-bind:class="tab.active">
{{ tab.name }}
</li>
</ul>
</div>
Use a class binding like this:
<li class="nav-item" :class="{active: tab.active === 'active'}" v-for="tab in tabs">
new Vue({
el: '#app',
data: {
tabs: [
{ name: "Home", active: "" },
{ name: "Challenges", active: "active" },
{ name: "Scoreboard", active: "" },
{ name: "About", active: "" }
]
}
});
.active .nav-link {
color: white;
background: blue;
}
<script src="https://unpkg.com/vue#2.5.17"></script>
<div id="app">
<ul class="navbar-nav">
<li class="nav-item" :class="{active: tab.active === 'active'}" v-for="tab in tabs">
{{ tab.name }}
</li>
</ul>
</div>

Vue Dynamic List

I'm creating a basic MTG Deckbuilder using Vue.Js. I'm trying to have the user type the card name into an input box then when the button is clicked, the deck list is update with the card name. Currently,the list add's a blank element for the card instead of the card name. Any ideas?
app.Vue:
<template>
<div id="app">
<deckBuilder #addCard="addCard" :title="title" :card="card" :deck="deck" />
</div>
</template>
<script>
import deckBuilder from './components/deckBuilder'
export default {
name: 'app',
components: {
deckBuilder,
},
data: () => ({
title: 'MTG Deck Builder',
card: {
name: '',
},
deck:[],
}),
methods: {
addCard: function(event,) {
this.deck.push(this.card.name);
},
},
}
</script>
deckBuilder.Vue:
<template>
<div>
<h1>{{ title }}</h1>
<input v-model="card.name" placeholder="Type a Card Name" />
<p> the card is: {{ card.name }}
<button #click="addCard">Add!</button>
<h2>Deck</h2>
<ul>
<li v-for="item in deck">{{ item.card }}</li>
</ul>
</div>
</template>
<script>
export default {
name: 'deckBuilder',
props: ['title', 'card', 'deck'],
methods: {
addCard() {
this.$emit('addCard')
}
},
}
</script>
Because you push string item instead of object
this.deck.push(this.card.name);
Correct template will be {{ item }}, not {{ item.card }}
This is because you are not emitting any data in your $emit
Try this,
In deckbuilder.vue
addCard() {
this.$emit('addCard',this.card.name);
}
In app.vue
addCard: function(cardName){
this.deck.push(cardName);
}
In html, v-for should be this way
<li v-for="item in deck">{{ item }}</li>
Try This
<!-- Menu Content -->
<ul class="nav-list" style="overflow: visible;">
<!-- Items -->
<span v-for="(menuItem, index) in menuItems" :key="index">
<li>
<nuxt-link :to="menuItem.link" :class="menuItem.class">
<i class="bx" :class="menuItem.icon || 'bx-square-rounded'" />
<!-- Link Name -->
<span class="links_name">{{ menuItem.name }}</span>
</nuxt-link>
</li>
</span>
</ul>
<script>
export default {
name: 'SidebarMenu',
menuItems: {
type: Array,
default: () => [
{
link: '/',
name: '_home',
icon: 'bx-home',
class: '',
},
{
link: '/blog',
name: '_blog',
icon: 'bx-edit',
class: '',
},
{
link: '/projects',
name: '_projects',
icon: 'bx-code',
class: ''
},
{
link: '/about',
name: '_about',
icon: 'bx-user',
class: ''
},
],
},
}
</script>

Categories

Resources