Vue Dynamic List - javascript

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>

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)
}
}

Vue CLI: Project list with component

I'm completely new to VueJS and am trying to create a project tile list with different data values per tile. I use Vue CLI. I created a component which is my template for one project tile.
component TheProjectTile.vue :
<template>
<router-link to="{{ project.url }}">
<div
class="row project-container"
style="background-color: {{ project.backgroundcolor }};"
v-scrollanimation
>
<div class="column column-60">
<h2>{{ project.title }}</h2>
<div class="button">view</div>
</div>
<div class="column">
<img src="#/assets/img/{{ project.image }}" alt="{{ project.title }}" />
</div>
</div>
</router-link>
</template>
<script type="text/javascript">
export default {
props: { project: Object },
data() {
return {}
}
}
</script>
Then I have my View on my Vue CLI application where I want to render the project tiles and where I want to give the data to the tiles:
View where the projects should be shown
<template>
<div id="projekte">
<section class="container">
<div id="projects">
<projectlist v-for="project in projects" :project="project" />
</div>
</section>
</div>
</template>
<script>
import TheProjectTile from './components/TheProjectTile'
export default {
components: {
projectlist: TheProjectTile
},
data() {
return {
projects: [
{
url: '/projekte/client1',
backgroundcolor: '#005ca9',
title: 'Website client 1',
img: 'client1.png'
},
{
url: '/projekte/client2',
backgroundcolor: '#c10b25',
title: 'Website client 2',
img: 'client2.png'
}
]
}
}
}
</script>
What do I need to change that it works? :/
Please take a look at following snippet:
You need to bind data with v-bind or :,
in v-for loop you need key
Vue.component('projectList', {
template: `
<a :to="project.url">
<div
class="row project-container"
:style="{'background-color': project.backgroundcolor}"
>
<div class="column column-60">
<h2>{{ project.title }}</h2>
<div class="button">view</div>
</div>
<div class="column">
<img :src="'#/assets/img/'+project.image" :alt="project.title" />
</div>
</div>
</a>
`,
props: { project: Object },
})
new Vue({
el: '#demo',
data() {
return {
projects: [{url: '/projekte/client1', backgroundcolor: '#005ca9', title: 'Website client 1', img: 'client1.png'}, {url: '/projekte/client2', backgroundcolor: '#c10b25', title: 'Website client 2', img: 'client2.png'}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="demo">
<div id="projekte">
<section class="container">
<div id="projects">
<!-- 👇 key -->
<project-list v-for="(project, index) in projects" :key="index" :project="project" />
</div>
</section>
</div>
</div>

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>

VueDraggable send request to DB while drag and drop

I need a help for vuedraggable component. I have three columns. (Photo inserted) I want to drag BoardUserCard between columns and want to send PUT request to database for changing "lead_status_id" related to column dropped. How can I achieve this ? I can not find any example about apis in documentation.
<template>
<div class="board">
<div class="boards">
<div class="boards-cards leads">
<div class="board-card-header ">
<h3>
Leads
</h3>
<span>
{{ allLeads.length }}
</span>
</div>
<draggable
ghost-class="ghost"
:list="allLeads"
class="board-card-body"
:options = "{group:allLeads}"
group="leads"
#change="handleChange"
>
<BoardUserCard
v-for="item in allLeads"
:key="item.name"
:name="item.name"
:email="item.email"
:img="item.img"
:status="item.status"
/>
</draggable>
</div>
<div class="boards-cards contacted">
<div class="board-card-header ">
<h3>
Contacted
</h3>
<span>
{{ contactedLeads.length }}
</span>
</div>
<draggable
ghost-class="ghost"
:list="contactedLeads"
class="board-card-body"
:options = "{group:contactedLeads}"
group="leads"
#change="handleChange"
>
<BoardUserCard
v-for="item in contactedLeads"
:key="item.name"
:name="item.name"
:email="item.email"
:img="item.img"
:status="item.status"
/>
</draggable>
</div>
<div class="boards-cards converted">
<div class="board-card-header ">
<h3>
Converted
</h3>
<span>
{{ convertedLeads.length }}
</span>
</div>
<draggable
ghost-class="ghost"
:list="convertedLeads"
class="board-card-body"
:options = "{group:convertedLeads}"
group="leads"
#change="handleChange"
>
<BoardUserCard
v-for="item in convertedLeads"
:key="item.name"
:name="item.name"
:email="item.email"
:img="item.img"
:status="item.status"
/>
</draggable>
</div>
</div>
</div>
</template>
<script>
import BoardUserCard from "#/components/BoardUserCard.vue";
import draggable from "vuedraggable";
export default {
name: "Dashboard",
components: {
BoardUserCard,
draggable,
},
data() {
return {
showModal: false,
allLeads: [
{
name: "Richard",
email: "Richard#gmail.com",
img: "avatar-small.svg",
status: "all"
},
{ name: "Rachael", email: "Rachael#gmail.com", img: "leads.svg", status: "all" },
{ name: "Matt", email: "Matt#gmail.com", img: "user-avatar.svg",status: "all" },
{ name: "Brad", email: "Brad#gmail.com", img: "leads.svg", status: "all"},
],
contactedLeads: [
{
name: "Jeniffer",
email: "Jeniffer#gmail.com",
img: "avatar-small.svg",
status: "contacted"
},
],
convertedLeads: [
{ name: "Mike", email: "Mike#gmail.com", img: "leads.svg", status: "converted" },
],
};
},
methods: {
openModal() {
this.showModal = true;
},
closeModal() {
this.showModal = false;
},
handleChange(event){
console.log(event)
}
},
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
All I need to add data attribute in component data-id="4"
<draggable
ghost-class="ghost"
:list="convertedLeads"
class="board-card-body"
:options = "{group:convertedLeads}"
group="leads"
#end="handleChange"
data-id="4"
>
And access data-id attribute in handleChange function
handleChange(event){
console.log(event.from.getAttribute("data-id"))
console.log(event.to.getAttribute("data-id"))
}
`

Separate Array push in Vuejs

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>

Categories

Resources