Vant Ui Mobile Swipe , DropDown not working - javascript

I use Vant ui Mobile from youzan in the first index step it runs normally for the second or third the text doesn't appear
pen : https://codepen.io/flint002/pen/dyZpGpW?editors=1000
CODE
html
<script src="https://cdn.jsdelivr.net/npm/vue#2.6/dist/vue.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vant#2.12/lib/vant.min.js"></script>
<div id="app">
<van-swipe class="my-swipe" >
<van-swipe-item>
1
<van-dropdown-menu>
<van-dropdown-item v-model="value1" :options="option1" ></van-dropdown-item>
</van-dropdown-menu>
</van-swipe-item>
<van-swipe-item>
2
<van-dropdown-menu>
<van-dropdown-item v-model="value1" :options="option1" ></van-dropdown-item>
</van-dropdown-menu>
</van-swipe-item>
<van-swipe-item>
3
<van-dropdown-menu>
<van-dropdown-item v-model="value1" :options="option1" ></van-dropdown-item>
</van-dropdown-menu>
</van-swipe-item>
</van-swipe>
</div>
js
import "https://cdn.jsdelivr.net/npm/#vant/touch-emulator";
// Render the Button component
new Vue({
el: "#app",
data() {
return {
value1: 0,
option1: [
{ text: "Option1", value: 0 },
{ text: "Option2", value: 1 },
{ text: "Option3", value: 2 },
],
};
},
});
Style
.my-swipe .van-swipe-item {
color: #fff;
font-size: 20px;
line-height: 150px;
text-align: center;
background-color: #39a9ed;
height: 500px;
}

UPDATE
You have to put in the van-dropdown-item following
for Version 2
get-container="body"
for Version 4
teleport="body"
I have updated the Playground. Now it works!
This was not a problem is in the library.
GitHub Issue
I have created an GitHub Issue
Playground
const { createApp, ref } = Vue;
const App = {
setup() {
const index = ref(0);
const onChange = (i) => index.value = i;
return { index, onChange };
},
data() {
return {
value1: 0,
option1: [
{ text: "Option1", value: 0 },
{ text: "Option2", value: 1 },
{ text: "Option3", value: 2 },
]
}
}
}
const app = createApp(App)
app.use(vant);
app.use(vant.Lazyload, {
lazyComponent: true
});
app.mount('#app')
.my-swipe .van-swipe-item {
color: #fff;
font-size: 20px;
line-height: 150px;
text-align: center;
background-color: #39a9ed;
height: 500px;
}
<link
rel="stylesheet"
href="https://fastly.jsdelivr.net/npm/vant#4/lib/index.css"
/>
<div id="app">
Swipe Index: {{index}}
<van-swipe class="my-swipe" #change="onChange">
<van-swipe-item>1
<van-dropdown-menu>
<van-dropdown-item v-model="value1" :options="option1" teleport="body"></van-dropdown-item>
</van-dropdown-menu>
</van-swipe-item>
<van-swipe-item>2
<van-dropdown-menu>
<van-dropdown-item v-model="value1" :options="option1" teleport="body"></van-dropdown-item>
</van-dropdown-menu>
</van-swipe-item>
<van-swipe-item>3
<van-dropdown-menu>
<van-dropdown-item v-model="value1" :options="option1" teleport="body"></van-dropdown-item>
</van-dropdown-menu>
</van-swipe-item>
</van-swipe>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<script src="https://fastly.jsdelivr.net/npm/vant#4/lib/vant.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/#vant/touch-emulator"></script>

Related

Vuetify - Search function in table that jumps to the found row

I have 2 Vuetify data tables without pagination. Every row of the second one got exactly one parent in the first one. If I click on one of those entries in the second one, I want to search for the parent and jump to that row. All I found for now is filtering, but I only want to have that row on top of my table.
Is something like this possible?
We can't really help you without code, even if i've seen that you can't, it should be cool if you could modify some parts of your code like variables and datas ...
However, i'll try to do my best to explain
What you have to do is to reorder your data array binded on your table depending on a given id (or other data) to identify it.
I made a similar exemple of your needs, but i repeat i can't really be exhausitve :
Parent component:
<template>
<div id="app">
<listone :list="listOne" :toggled="toggledParent"></listone>
<listtwo :list="listTwo" v-model="toggledParent"></listtwo>
</div>
</template>
<script>
export default {
name: "App",
data: () => ({
toggledParent: 0,
listOne: [
{
id: 1,
title: "parent1",
},
{
id: 2,
title: "parent2",
},
{
id: 3,
title: "parent3",
},
],
listTwo: [
{
title: "title1",
parent: 3,
},
{
title: "title2",
parent: 1,
},
{
title: "title3",
parent: 2,
},
],
}),
components: {
listone: () => import("#/components/listone"),
listtwo: () => import("#/components/listtwo"),
},
};
</script>
<style>
#app {
font-family: "Avenir", Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
}
</style>
ListOne component :
<template>
<div class="list">
<a v-for="item in treatedList" :key="item.title">
{{ item.title }}
</a>
</div>
</template>
<script>
export default {
name: "listone",
props: {
list: Array,
toggled: Number,
},
computed: {
treatedList: function () {
let tmp = this.list;
let $this = this
return tmp.sort(function (a, b) {
return a.id === $this.toggled ? -1 : b.id === $this.toggled ? 1 : 0;
});
},
},
};
</script>
<style>
.list {
display: flex;
flex-flow: column nowrap;
}
.list > a {
border: 1px solid red;
}
</style>
ListTwo component :
<template>
<div class="list">
<a
v-for="item in list"
:key="item.title"
#click="$emit('input', item.parent)">
{{ item.title }}
</a>
</div>
</template>
<script>
export default {
name: "listtwo",
props: {
list: Array,
toggledParent: Number
},
};
</script>
<style scoped>
.list {
display: flex;
flex-flow: column nowrap;
}
.list > a {
border: 1px solid red;
}
</style>
Try it and say me it helps you as wanted
Demo on codesandbox.io : https://codesandbox.io/s/mutable-thunder-zo8vn?fontsize=14&hidenavigation=1&theme=dark
So without knowing what your data looks like i'll use a standard array of objects without meta data.
What you could do, is use the sort function inside of computed property like below, this will re-organize your list every time you match or filter the list.
(Note: This re-arranges your entire list every time)
Here is a really basic example:
new Vue({
el: "#app",
data: {
search: 'Bananas',
tableData: [
{
item: "Cherries",
price: 3.99,
type: "Fruit"
},
{
item: "Chicken",
price: 6.99,
type: "Meat"
},
{
item: "Bananas",
price: 1.99,
type: "Fruit"
},
{
item: "Cola",
price: 0.99,
type: "Drink"
},
{
item: "Coffee",
price: 2.99,
type: "Drink"
},
]
},
computed: {
getTableData: function() {
return this.tableData.sort((x,y) => { return x.item == this.search ? -1 : y.item == this.search ? 1 : 0; });
}
}
})
table {
background: #ccc;
padding: 20px;
width:50%;
}
table tr {
background: #f1f1f1;
}
table tr td {
padding: 10px;
}
.firstRow {
background: green;
color:white;
}
.searchBar {
padding:20px;
width: 40%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="searchBar">
Search <input type="text" v-model="search">
</div>
<table>
<tr class="firstRow"><td>Item</td> <td>Price</td> <td>Type</td></tr>
<tr v-for="(product, index) in getTableData" :key="index">
<td>{{product.item}}</td>
<td>{{product.type}}</td>
<td>{{product.price}}</td>
</tr>
</table>
</div>

Set up a v-on:click directive inside v-for

I have displayed a list of images with some information. I want those images to be clickable. And when clicked it should show a div with saying "HI!!". I have been trying to add a variable as show:true in Vue data and tried to build some logic that show becomes false when clicked. But I have not been able to achieve it.
Below is the sample code:
template>
<div>
<h1>SpaceX</h1>
<div v-for="launch in launches" :key="launch.id" class="list" #click="iclickthis(launch)">
<div ><img :src="launch.links.patch.small" alt="No Image" title={{launch.name}} /></div>
<div>ROCKET NAME: {{launch.name}} </div>
<div>DATE: {{ launch.date_utc}} </div>
<div>SUCCESS: {{ launch.success}} </div>
<div>COMPLETENESS: {{ launch.landing_success}} </div>
</div>
<!-- <v-model :start="openModel" #close="closeModel" /> -->
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'SpaceXTimeline',
components: {
},
data: () => ({
launches : [],
openModel : false,
show : true,
}),
methods: {
iclickthis(launch) {
// this should load a model search v-model / bootstrap on vue npm install v-model
console.log(launch.name + " is launched");
console.log("DETAILS: "+ launch.details);
console.log("ROCKET INFO: "+ launch.links.wikipedia);
console.log("CREW DETAILS: "+ launch.crew);
console.log("Launchpad Name: "+ launch.launchpad);
this.openModel = true;
},
closeModel () {
this.openModel = false;
}
},
async created() {
const {data} = await axios.get('https://api.spacexdata.com/v4/launches');
data.forEach(launch => {
this.launches.push(launch);
});
}
};
</script>
<style scoped>
.list {
border: 1px solid black;
}
</style>
Thanks, and appreciate a lot.
v-model is a binding and not an element, unless you've named a component that? Is it a misspelling of "modal"?
Either way, sounds like you want a v-if:
<v-model v-if="openModel" #close="closeModel" />
Example:
new Vue({
el: '#app',
components: {},
data: () => ({
launches: [],
openModel: false,
show: true,
}),
methods: {
iclickthis(launch) {
// this should load a model search v-model / bootstrap on vue npm install v-model
console.log(launch.name + ' is launched');
console.log('DETAILS: ' + launch.details);
console.log('ROCKET INFO: ' + launch.links.wikipedia);
console.log('CREW DETAILS: ' + launch.crew);
console.log('Launchpad Name: ' + launch.launchpad);
this.openModel = true;
},
closeModel() {
this.openModel = false;
},
},
async created() {
const {
data
} = await axios.get('https://api.spacexdata.com/v4/launches');
data.forEach(launch => {
this.launches.push(launch);
});
},
})
Vue.config.productionTip = false;
Vue.config.devtools = false;
.modal {
cursor: pointer;
display: flex;
justify-content: center;
position: fixed;
top: 0;
width: 100%;
height: 100vh;
padding: 20px 0;
background: rgba(255, 255, 255, 0.5);
}
img {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<div id="app">
<h1>SpaceX</h1>
<div v-for="launch in launches" :key="launch.id" class="list" #click="iclickthis(launch)">
<div>
<img :src="launch.links.patch.small" alt="No Image" :title="launch.name" />
</div>
<div>ROCKET NAME: {{ launch.name }}</div>
<div>DATE: {{ launch.date_utc }}</div>
<div>SUCCESS: {{ launch.success }}</div>
<div>COMPLETENESS: {{ launch.landing_success }}</div>
</div>
<div v-if="openModel" #click="closeModel" class="modal">
MODAL
</div>
</div>

Form is listening to enter key Vue

I have made a form component (CreateDocument) in Nuxt. Inside this component i made also an autocomplete (AutoCompleteFilters).
When I hit enter inside the autocomplete component, also the CreateDocument is listening to the enter key. But I only want that a specific input field is listing to the enter key event.
This is the CreateDocument component:
<template>
<div>
<Notification :message="notification" v-if="notification"/>
<form method="post" #submit.prevent="createDocument">
<div class="create__document-new-document">
<div class="create__document-new-document-title">
<label>Titel</label>
<input
type="text"
class="input"
name="title"
v-model="title"
required
>
</div>
<div class="create__document-new-document-textarea">
<editor
apiKey="nothing"
v-model="text"
initialValue=""
:init="{
height: 750,
width: 1400
}"
>
</editor>
</div>
<div class="create__document-new-document-extra-info">
<div class="create__document-new-document-tags">
<label>Tags</label>
<AutoCompleteFilters/>
</div>
<div class="create__document-new-document-clients">
<label>Klant</label>
<input
type="text"
class="input"
name="client"
v-model="client"
required
>
</div>
</div>
<Button buttonText="save" />
</div>
</form>
</div>
</template>
<script>
import Notification from '~/components/Notification'
import Editor from '#tinymce/tinymce-vue'
import Button from "../Button";
import { mapGetters, mapActions } from 'vuex'
import AutoCompleteFilters from "./filters/AutoCompleteFilters";
export default {
computed: {
...mapGetters({
loggedInUser: 'loggedInUser',
})
},
middleware: 'auth',
components: {
Notification,
Button,
editor: Editor,
AutoCompleteFilters
},
data() {
return {
title: '',
text: '',
tags: '',
client: '',
notification: null,
}
},
methods: {
...mapActions({
create: 'document/create'
}),
createDocument () {
const documentData = {
title: this.title,
text: this.text,
tags: this.tags,
client: this.client,
userId: this.loggedInUser.userId
};
this.create(documentData).then((response) => {
this.notification = response;
this.title = '';
this.text = '';
this.tags = '';
this.client= '';
})
}
}
}
</script>
And this is the AutoCompleteFilters component:
<template>
<div class="autocomplete">
<input
type="text"
id="my-input"
#input="onChange"
v-model="search"
#keydown.down="onArrowDown"
#keydown.up="onArrowUp"
#keydown.enter="onEnter"
/>
<ul
v-show="isOpen"
class="autocomplete-results"
>
<li
v-for="result in results"
:key="results.id"
class="autocomplete-result"
#click="setResult(result.name)"
:class="{ 'is-active': results.indexOf(result) === arrowCounter }"
>
{{ result.name }}
</li>
</ul>
</div>
</template>
<script>
import {mapActions} from 'vuex'
export default {
data() {
return {
isOpen: false,
results: false,
search: '',
arrowCounter: 0,
filter: null,
position: 0
};
},
methods: {
...mapActions({
getFilterByCharacter: 'tags/getTagsFromDb'
}),
onChange(e) {
this.isOpen = true;
this.position = e.target.selectionStart;
},
setResult(result) {
this.search = result;
this.isOpen = false;
},
getResults(){
this.getTagsByValue(this.search).then((response) => {
this.results = response;
});
},
async getTagsByValue(value){
const filters = {autocompleteCharacter : value};
return await this.getFilterByCharacter(filters);
},
onArrowDown() {
if (this.arrowCounter < this.results.length) {
this.arrowCounter = this.arrowCounter + 1;
}
},
onArrowUp() {
if (this.arrowCounter > 0) {
this.arrowCounter = this.arrowCounter - 1;
}
},
onEnter(evt) {
this.search = this.results[this.arrowCounter].name;
this.isOpen = false;
this.arrowCounter = -1;
}
},
watch: {
search: function() {
this.getResults();
}
},
};
</script>
<style>
.autocomplete {
position: relative;
}
.autocomplete-results {
padding: 0;
margin: 0;
border: 1px solid #eeeeee;
height: 120px;
overflow: auto;
width: 100%;
}
.autocomplete-result {
list-style: none;
text-align: left;
padding: 4px 2px;
cursor: pointer;
}
.autocomplete-result.is-active,
.autocomplete-result:hover {
background-color: #4AAE9B;
color: white;
}
</style>
Just as you did in your form to avoid "natural" form submit and replace it with a custom action:
#submit.prevent="createDocument"
... you have to preventDefault the "natural" event that submits the form when you press Enter while focusing the form.
To do so, just add .prevent to your events in the template:
#keydown.down.prevent="onArrowDown"
#keydown.up.prevent="onArrowUp"
#keydown.enter.prevent="onEnter"

Vue.js add classes from array

I am new to Vue and I am trying to display a list of cards. The cards will be broken out into rows of three. That works, but I want to give each row a different class name based on a list of classes in an array but can't seem to figure out how to do that with what I have right now.
I tried using v-bind:class on the row but not sure if that is the way to go with what I am trying to do.
Here is what my HTML structure looks like:
<div class="row" v-for="i in row”>
<div v-for="(show, index) in rowItems(i)" class="card" v-bind:class="{ new: item.new }">
<img v-bind:src="item.illustration">
<p>{{ item.name }}</p>
</div>
</div>
Here is what I have in Vue. My data is in an object (itemList).
let app = new Vue({
el: '#container',
data: {
rowItems: 3,
items: itemList,
rowClasses: ['row1', 'row2', 'row3', 'row4']
},
computed:{
row:function(){
return Math.ceil(this.items.length / this.rowItems);
},
},
methods:{
rowItems:function(index){
return this.items.slice((index - 1) * this.rowItems, index * this.rowItems)
}
}
});
You can v-bind the class using object syntax like this:
<div :class="{ new: item.new, [rowClasses[index]]: true }">
new Vue({
el: '#app',
data() {
return {
rowCount: 3,
items: [
{ name: 'A', new: false },
{ name: 'B', new: false },
{ name: 'C', new: true },
{ name: 'D', new: false },
],
rowClasses: ['row1', 'row2', 'row3', 'row4']
};
},
computed: {
row() {
return Math.ceil(this.items.length / this.rowCount);
},
},
methods: {
rowItems(index) {
return this.items.slice((index - 1) * this.rowCount, index * this.rowCount);
},
}
})
.card {
border: solid 1px gray;
margin: 10px;
padding: 10px;
}
.new {
background-color: lightyellow;
}
.row1 {
color: red;
}
.row2 {
color: green;
}
.row3 {
color: blue;
}
<script src="https://unpkg.com/vue#2.5.16"></script>
<div id="app">
<div class="row" v-for="i in row">
<div v-for="(item, index) in rowItems(i)"
class="card"
:class="{ new: item.new, [rowClasses[index]]: true }">
<pre>{ new: {{item.new}}, [{{rowClasses[index]}}]: true }</pre>
<p>{{ item.name }}</p>
</div>
</div>
</div>
Or you can call a method that returns such an object:
// <template>
<div :class="getRowClass(item, index)">
// <script>
methods: {
getRowClass(item, index) {
return {
new: item.new,
[this.rowClasses[index]]: true
};
}
}
new Vue({
el: '#app',
data() {
return {
rowCount: 3,
items: [
{ name: 'A', new: false },
{ name: 'B', new: false },
{ name: 'C', new: true },
{ name: 'D', new: false },
],
rowClasses: ['row1', 'row2', 'row3', 'row4']
};
},
computed: {
row() {
return Math.ceil(this.items.length / this.rowCount);
},
},
methods: {
rowItems(index) {
return this.items.slice((index - 1) * this.rowCount, index * this.rowCount);
},
getRowClass(item, index) {
const rowClass = this.rowClasses[index % this.rowClasses.length];
return {
new: item.new,
[rowClass]: true
};
}
}
})
.card {
border: solid 1px gray;
margin: 10px;
padding: 10px;
}
.new {
background-color: lightyellow;
}
.row1 {
color: red;
}
.row2 {
color: green;
}
.row3 {
color: blue;
}
<script src="https://unpkg.com/vue#2.5.16"></script>
<div id="app">
<div class="row" v-for="i in row">
<div v-for="(item, index) in rowItems(i)"
class="card"
:class="getRowClass(item, index)">
<pre>{{getRowClass(item, index)}}</pre>
<p>{{ item.name }}</p>
</div>
</div>
</div>
Or you can do this entirely in CSS, using nth-of-type() and eliminating the need for rowClasses[].
// <style>
.card:nth-of-type(1n) {} // every 1st card
.card:nth-of-type(2n) {} // every 2nd card
.card:nth-of-type(3n) {} // every 3rd card
new Vue({
el: '#app',
data() {
return {
rowCount: 3,
items: [
{ name: 'A', new: false },
{ name: 'B', new: false },
{ name: 'C', new: true },
{ name: 'D', new: false },
],
};
},
computed: {
row() {
return Math.ceil(this.items.length / this.rowCount);
}
},
methods: {
rowItems(index) {
return this.items.slice((index - 1) * this.rowCount, index * this.rowCount);
}
}
})
.card {
border: solid 1px gray;
margin: 10px;
padding: 10px;
}
.new {
background-color: lightyellow;
}
.card:nth-of-type(1n) {
color: red;
}
.card:nth-of-type(2n) {
color: green;
}
.card:nth-of-type(3n) {
color: blue;
}
<script src="https://unpkg.com/vue#2.5.16"></script>
<div id="app">
<div class="row" v-for="i in row">
<div v-for="(item, index) in rowItems(i)"
class="card"
:class="{ new: item.new }">
<pre>.card:nth-of-type({{ index+1 }}n)</pre>
<p>{{ item.name }}</p>
</div>
</div>
</div>

Vue js data binding doesn't work

I'm trying to create a vue component but whenever I want to hide some elements with v-show it doesn't work.
When you click any element on the list I want to hide it and on the click event element.visible is set to false, so in the component template I bind that value to v-show but it wont hide.
I guess it's because element.visible it's kind of nested attribute but I'm not really sure.
var collection = [
{ id: 1, name: 'element 1' },
{ id: 2, name: 'element 2' },
{ id: 3, name: 'element 3' },
{ id: 4, name: 'element 4' },
{ id: 5, name: 'element 5' },
{ id: 6, name: 'element 6' },
{ id: 7, name: 'element 7' },
{ id: 8, name: 'element 8' },
];
var multiselect = {
props: ['collection'],
data: function() {
return {
subscribed: [],
toSubscribe: [],
toUnsubscribe: [],
dataset: []
}
},
mounted: function(){
this.dataset = _.map(this.collection, function(element){
element.visible = true;
return element;
});
},
methods: {
subscribe: function(element){
element.visible = false;
}
}
}
new Vue({
el: '#app',
components: {
'multiselect': multiselect
},
data: {
elements: collection
}
})
.multiselect .list {
border: 1px solid #000;
height: 215px;
max-height: 215px;
overflow: scroll;
}
.multiselect .list .list-element {
text-align: center;
padding: 0.2em;
cursor: pointer;
}
.multiselect .list .list-element:hover {
background-color: #d6dbdf;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.4/lodash.min.js"></script>
<script src="https://unpkg.com/vue#2.5.13/dist/vue.js"></script>
<div id="app">
<multiselect inline-template :collection="elements">
<div class="col-sm-12 multiselect">
<div class="col-sm-5 list">
<div class="col-sm-12">
<div v-for="element in dataset" class="list-element" #click="subscribe(element)" v-show="element.visible">
{{element.name}}
</div>
</div>
</div>
<div class="col-sm-2">
<button class="btn btn-primary btn-fill">
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</button>
<button class="btn btn-primary btn-fill">
<i class="fa fa-arrow-left" aria-hidden="true"></i>
</button>
</div>
<div class="col-sm-5 list">
</div>
</div>
</multiselect>
</div>
As an interesting variation, you don't need to clone the collection elements or set a property on them.
It is enough to have a parallel array of flag, but you have to be careful of the syntax to update them and the flag must be contained in an object in order to be observable.
i.e an array of { visible: true } rather than an array of true.
Ref: Mutation-Methods
var collection = [
{ id: 1, name: 'element 1' },
{ id: 2, name: 'element 2' },
{ id: 3, name: 'element 3' },
{ id: 4, name: 'element 4' },
];
var multiselect = {
props: ['collection'],
data: function() {
return {
visibleFlags: []
}
},
created: function(){
this.collection.forEach(x => {
this.visibleFlags.push({visible: true}); // Vue mutation method
})
},
methods: {
subscribe: function(index){
this.$set(this.visibleFlags, index, false)
}
}
}
new Vue({
el: '#app',
components: {
'multiselect': multiselect
},
data: {
elements: collection
}
})
.multiselect .list {
border: 1px solid #000;
height: 125px;
max-height: 215px;
overflow: scroll;
}
.multiselect .list .list-element {
text-align: center;
padding: 0.2em;
cursor: pointer;
}
.multiselect .list .list-element:hover {
background-color: #d6dbdf;
}
<script src="https://unpkg.com/vue#2.5.13/dist/vue.js"></script>
<div id="app">
<multiselect inline-template :collection="elements">
<div class="col-sm-12 multiselect">
<div class="col-sm-5 list">
<div class="col-sm-12">
<div v-for="(element, index) in collection"
class="list-element" v-show="visibleFlags[index].visible"
#click="subscribe(index)">
{{element.name}}
</div>
</div>
</div>
</div>
</multiselect>
</div>
The problem is that you are modifying an already-responsive object. Vue cannot detect property additions.
It's obscured by the fact that you're copying via map, and assigning it to a new array, but it's an array of references to responsive objects, to each of which you have added the visible property. If you examine the data items in the parent, you'll see that it gets visible added, too.
The minimal fix is to use Object.assign to create a new object and copy properties into it. This way all properties are inserted into a non-responsive object, which is then made responsive during assignment.
mounted: function(){
this.dataset = _.map(this.collection, function(element){
return Object.assign({}, element, {visible: true});
});
},
You could do this in created, since you don't need the DOM element.

Categories