I am trying to create a card builder using Vue draggable. I have a row full of cardElements and these can be dragged to the card builder. The card builder is a rectangle made up of individual "buckets" of lists. Here is what it looks like:
Card builder Layout
Here is the script to generate the elements list:
import draggable from 'vuedraggable'
export default {
name: "clone",
display: "Clone",
order: 2,
components: {
draggable
},
data() {
return {
cardElements: [
{ name: "Logo", id: 1 },
{ name: "Stamp", id: 2 }
],
arrA: []
};
},
methods: {
log: function(evt) {
window.console.log(evt);
}
}
};
You can see that the cardElements are correctly rendered from script and this is how they are rendered in the HTML:
<draggable class="dragArea list-group" :list="cardElements" :group="{ name: 'people', pull: 'clone', put: false }" #change="log">
<div class="list-group-item" v-for="element in cardElements" :key="element.name">
{{ element.name }}
</div>
</draggable>
These are draggable and I can change their order like so:
Changed Order of items
Each "bucket" on the card is declared as an array like so (this is only for the top left space on the card builder, each square is a different number):
data() {
return {
cardElements: [
{ name: "Logo", id: 1 },
{ name: "Stamp", id: 2 }
],
arrA: []
};
}
<draggable class="dragArea list-group" :list="arrA" group="cardItem" #change="log">
<div class="lvl1-1 bucket empty" v-for="element in arrA" :key="element.name">
{{ element.name }}
</div>
</draggable>
But when I drag an element from the cardElements list to the arrA list, it doesn't move and I'm not sure why. I can get it working in the example code supplied here, but not when I change it to my own code.
The issue was that I had the group defined as :group="{ name: 'people', and then was calling it as group="cardItem" so I changed :group="{ name: 'people', to this :group="{ name: 'cardItem', and it worked
Related
How can I implement dynamic event handling in Vue.js when using a dynamic list of elements?
I have a list of items, each represented by a component, and I want to attach a unique event listener to each item in the list. The event listener should perform a specific action based on the item's unique data.
The issue I am facing is that I am not able to bind the event listener to the specific item using v-on directive, as the list is generated dynamically and the number of items can change. I have tried using v-for with v-on, but it attaches the same event listener to all the items in the list.
I have also researched using $listeners and $attrs, but I am not sure if that is the best solution for my use case.
Here is an example of my current code:
<template>
<div>
<item-component v-for="item in items" :key="item.id" v-on="uniqueEventListeners(item)" />
</div>
</template>
<script>
export default {
data() {
return {
items: [
{ id: 1, name: "item 1" },
{ id: 2, name: "item 2" },
{ id: 3, name: "item 3" }
]
};
},
methods: {
uniqueEventListeners(item) {
return {
click: () => {
console.log(`Clicked on item with id: ${item.id}`);
}
};
}
}
};
</script>
What is the best way to achieve dynamic event handling with a dynamic list of items in Vue.js? And also how can I make sure that the event is unique for each item.
You can do something like this:
<template>
<div>
<item-component v-for="item in items" :key="item.id" :data-id="item.id" v-on="item.events" />
</div>
</template>
<script>
export default
{
data()
{
return {
items: [
{
id: 1,
name: "item 1",
events:
{
click: this.handleClick,
mouseenter: this.handleMouseEnter,
mousemove: this.handleMouseMove,
}
},
{
id: 2,
name: "item 2",
events:
{
click: this.handleClick,
}
},
{
id: 3,
name: "item 3",
events:
{
mousemove: this.handleMouseMove,
}
},
]
};
},
methods:
{
handleClick(event)
{
console.log("CLICK", event.target.dataset.id);
},
handleMouseEnter(event)
{
console.log("MOUSE ENTER", event.target.dataset.id);
},
handleMouseMove(event)
{
console.log("MOUSE MOVE", event.target.dataset.id);
},
}
};
</script>
You should make sure that your item-component is emitting the events that you're listening for.
I have quasar tabs that are being rendered in v-for loop.
Problem is that when I provide array as prop from parent, then my tabs stop working to toggle whereas it works with local array.
<div v-for="test in tests">
<q-tabs
v-model="test.status"
align="justify"
>
<q-tab
v-for="(tab, tabIndex) in tabs"
:key="tabIndex"
:name="tab.value"
>
{{ tab.name }}
</q-tab>
</q-tabs>
</div>
<script>
export default {
props: ['tests']
data (){
return {
tabs: [
{
name: 'Required',
value: 'required'
},
{
name: 'Not Required',
value: 'not-required'
}
]
}
}
Tests Data
[
{
id: "test 1"
name: 'TEST 1'
status: 'required'
},
{
id: "test 2"
name: 'TEST 2'
status: 'not-required'
}
]
Expected result
Toggle of tabs must work when component is provided with props data to iterate.
I'm retrieving a data set that has a few fields as a list included. The results need to be shown in a Buefy table (https://buefy.org/documentation/table) and I would like to show the list items as separate tags (https://buefy.org/documentation/tag/) in the table cell.
The code below simulates the issue. The result of this is showing the data in the second column as plain text Value1,Value2,Value3.
Not only does this look bad, but because there are no spaces between the values, it makes the table too wide for the screen and other columns are not visible anymore because of it.
I would like it to look something like this in the List cell:
The code to reproduce:
<template>
<b-table :data="data" :columns="columns"></b-table>
</template>
<script>
export default {
data() {
return {
data: [
{ 'id': 1, 'list': ["Value1","Value2","Value3"] },
{ 'id': 2, 'list': ["Value1","Value2","Value3"] },
{ 'id': 3, 'list': ["Value1","Value2","Value3"] }
],
columns: [
{
field: 'id',
label: 'ID',
},
{
field: 'list',
label: 'List',
}
]
}
}
}
</script>
Try out the following custom rendering and add the class helper mr-2 to make space between tags :
<b-table :data="data">
<b-table-column field="id" label="ID" centered v-slot="props">
{{props.row.id}}
</b-table-column>
<b-table-column field="list" label="List" centered v-slot="props">
<span v-for="item in props.row.list" class="tag mr-2">
{{item}}
</span>
</b-table-column>
</b-table>
Live demo
I cant pass data to props in VueJS.
Here is my code:
const projects = [{ id: 1, name: 'First', img: "https://randomwordgenerator.com/img/picture-generator/53e0d7414855ac14f1dc8460962e33791c3ad6e04e5074417d2e72d2964cc6_640.jpg" },
{ id: 2, name: 'Second', img: "https://randomwordgenerator.com/img/picture-generator/paper-1100254_640.jpg" },
{ id: 3, name: 'Third', img: "https://randomwordgenerator.com/img/picture-generator/5fe2d4414352b10ff3d8992cc12c30771037dbf85254794075287cd69145_640.jpg" },
{ id: 4, name: 'Forth', img: "https://randomwordgenerator.com/img/picture-generator/5fe1d3414256b10ff3d8992cc12c30771037dbf8525478487c2f79d5924e_640.jpg" }
]
const Project = {
props: ['img', 'name'],
template: `
<div class="container projectbox">
<div class="textandimage"> Name: {{ projects.name }} </div>
</div>
`,
data() {
return {
projects
}
}
}
img:undefined
name:undefined
Please help.
Projects is a list (Array) of Objects. if you want to access an Object in the list, you need to reference its position. for example:
<div class="textandimage"> Name: {{ projects[0].name }} </div>
This will access the first Object in your list, and return the value of the key name
EDIT: for-loop
If you want to loop through the data to the template, do something like this:
<div v-for="(item, index) in projects" class="container projectbox" :key="index">
<div class="textandimage"> Name: {{ item.name }} </div>
</div>
Hope that makes more sense.
I am trying to make a custom list filter on input using computed property. In one file I create a widget, in another I use it. Here is the code from the widget creation file:
<template>
<input value="Гарантийный случай"
v-model="searchText"
:class="{'w-autocomplete__input_completed': completed}"
ref="input"
#click="areOptionsVisible = !areOptionsVisible"/>
<div v-if="areOptionsVisible"
:style="{maxHeight: maxHeight, overflow: 'auto', zIndex: zIndex}"
class="w-autocomplete__items">
<div v-for="option in options" class="w-autocomplete__item_first" >
{{ option.name }}
<div v-for="item in option.children" class="w-autocomplete__item"
:class="{'w-autocomplete__item_active': currentIndex === item}"
#mouseenter="setActive(item)"
#keyup.up="changeCurrent('up', item)"
#keyup.down="changeCurrent('down', item)"
#click="doChoose(item)">
{{ item.name }}
</div>
</div>
</div>
</template>
<script>
export default {
name: 'dropdown',
props: {
placeholder: {
type: String,
required: false,
default: '',
},
options: {
type: Array,
default(){
return []
}
},
},
data: function () {
return {
counter: 0,
currentIndex: null,
completed: false,
chosenItem: null,
areOptionsVisible: false,
searchText: '',
data: [],
}
},
computed: {
options(){
return this.props.options.filter(elem => {
return elem.name.toLowerCase().includes(this.searchText.toLowerCase());
});
},
},
.......
}
</script>
This is how I pass the array to this list in another file:
<template>
........
<div class="complaint-form__line-item">
<div class="form-group">
<label>Гарантийный случай</label>
<dropdown :options="options" />
</div>
</div>
........
</template>
<script>
........
export default {
name: 'complaint-form',
components: {LockedImport, UploadFiles, CarNumberInput, Autocomplete, Dropdown},
props: {
......
}
},
data() {
const complaint = new Complaint();
return {
........
options: [
{name: 'Выход детали из строя в процессе эксплуатации', value: null,
children: [{name: 'Увеличение зазора, люфт (дробь/стуки)', value: 53},
{name: 'Обрыв детали', value: 54}]},
{name: 'Поломка при установке', value: null},
{name: 'Брак до установки', value: null,
children: [{name: 'Недокомплект', value: 55},
{name: 'Заводской брак (замятия, отсутствие резьбы, пробой пыльника и т.д.)',
value: 56}]},
],
}
},
Tell me please why computed doesn't work? Only I add computed and the list is not displayed at all when clicking on the field, but should. That is, it breaks down completely. I want to be filtered when entering text in input
Vue.js cannot have more than one element inside a <template> tag, so I would suggest that you enclose the whole code of the dropdown component within a <div> tag or something of the sort.
Also, and this is just a comment, I would suggest that you use the focus event for the input because with click it will still be showing even if you aren't focusing on the input.