CDK Drag&Drop nested lists - javascript

I have two objects, Users and Info.
I intend to present users in different columns (individualize them) and within each User I intend to put the respective information where the User ID is the same as the IDUser in the info object. Basically, I intend to present the Obejto Info information within the list of each user, respectively.
At the moment I have two lists (users and info) I want to drag and drop between placing them vertically and horizontally, but without success.
Someone can help me solve this problem in order to pass the cards from one column to another (from user to user).
Example: In the column named Name1 I intend to place the card with the text Expand in the column named Name2.
Thank you
DEMO
html
<div style="width:100%; height:100%; display:flex; justify-content:center">
<div *ngFor="let usr of Users" style="width: 20%;">
<div class="card">
<div class="card-header" style="display: flex; align-items: center; justify-content: center;">
<span>{{usr.name}}</span>
</div>
<div class="card-body" style="height:100%" cdkDropList
cdkDropListOrientation="vertical" [cdkDropListData]="Info"
(cdkDropListDropped)="drop($event)">
<div *ngFor="let item of Info">
<div *ngIf="usr.id == item.idUser" cdkDrag>
<div class="card">
<div class="card-header" style="padding: 0px;">
<span>{{item.text}}</span>
</div>
<div class="card-body" style="padding: 0px;position: relative;">
<span>{{item.text}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
.ts
Users = [
{ id: 1, name: "Name1" },
{ id: 2, name: "Name2" },
{ id: 3, name: "Name3" }
];
Info = [
{ idUser: 1, text: "Expand1" },
{ idUser: 1, text: "Expand11" },
{ idUser: 2, text: "Expand2" },
{ idUser: 2, text: "Expand22" },
{ idUser: 3, text: "Expand33" },
{ idUser: 3, text: "Expand33" }
];
drop(event: CdkDragDrop<string[]>) {
console.log("TO", event.previousContainer.data[event.previousIndex]);
console.log("FROM", event.previousContainer.data[event.currentIndex]);
if (event.previousContainer === event.container) {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex
);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}

You can do multiple changes to your approach to solve this issue:
You technically just have a single data source for data and that will not work so transform your data structure so that each user will have an array to UserInfo items.
Use cdkDropListGroup on container element which contains all cdkDropList
and that's all!
import {
Component
} from "#angular/core";
import {
CdkDragDrop,
moveItemInArray,
transferArrayItem
} from "#angular/cdk/drag-drop";
#Component({
selector: "my-app",
templateUrl: "./app.component.html",
styleUrls: ["./app.component.css"]
})
export class AppComponent {
Users = [{
id: 1,
name: "Name1",
items: [{
idUser: 1,
text: "Expand1"
}, {
idUser: 1,
text: "Expand11"
}]
},
{
id: 2,
name: "Name2",
items: [{
idUser: 2,
text: "Expand2"
}, {
idUser: 2,
text: "Expand22"
}]
},
{
id: 3,
name: "Name3",
items: [{
idUser: 3,
text: "Expand33"
}, {
idUser: 3,
text: "Expand33"
}]
}
];
drop(event: CdkDragDrop < string[] > ) {
if (event.previousContainer === event.container) {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex
);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
}
<div style="width:100%; height:100%; display:flex; justify-content:center" cdkDropListGroup>
<div *ngFor="let usr of Users" style="width: 20%;">
<div class="card">
<div class="card-header" style="display: flex; align-items: center; justify-content: center;">
<span>{{usr.name}}</span>
</div>
<div class="card-body" style="height:100%" cdkDropList id="{{usr.id}}" cdkDropListOrientation="vertical" [cdkDropListData]="usr.items" (cdkDropListDropped)="drop($event)">
<div *ngFor="let item of usr.items">
<div cdkDrag>
<div class="card">
<div class="card-header" style="padding: 0px;">
<span>{{item.text}}</span>
</div>
<div class="card-body" style="padding: 0px;position: relative;">
<span>{{item.text}}</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Take a look at this stackblitz forked from yours.

Related

vue.js - Is there any way to render elements in two different divs using one v-for loop?

The goal is to make the output look like this:
<div id="tabs">
<div id="first">
<a>tab 1</a>
<a>tab 2</a>
</div>
<div id="second">
<a>tab 3</a>
</div>
</div>
Currently I'm using this solution (using two v-for loops):
tabs.js (current)
export default {
data() {
return {
tabs: {
first: [{ name: 'tab1' }, { name: 'tab2' }],
second: [{ name: 'tab3' }],
}
}
}
template: `
<div id="tabs">
<div id="first">
<a v-for="tab in tabs.first">{{ tab.name }}</a>
</div>
<div id="second">
<a v-for="tab in tabs.second">{{ tab.name }}</a>
</div>
</div>
`
}
I had an idea to do something like this but it performs more iterations than in the case with two loops:
tabs.js (idea)
export default {
data() {
return {
tabs: {
test: [
{ name: 'tab1', category: 'first' },
{ name: 'tab2', category: 'first' },
{ name: 'tab3', category: 'second' }
]
}
}
}
template: `
<div id="tabs">
<div v-for='category in ["first", "second"]' :id='category' :key='category'>
<template v-for="tab in tabs.test">
<a v-if="tab.category === category">{{ tab.name }}</a>
</template>
</div>
</div>
`
}
I read this topic but it contains slightly different solutions, which unfortunately didn't work in this case.
There's no problem using more than one v-for loops. And there's no problem using nested v-for loops.
The problem I see with your current code is that it's not scalable. You're hard-coding the exact values of your tabs in <template />(e.g: first, second).
The main idea here is to loop through tabs and, inside each tab, to loop through each contents, without the <template> needing to know what the tab is or how many there are.
So that when you change your tabs to, say...
{
tab1: [{ name: 'intro'}],
tab2: [{ name: 'tab2-1' }, { name: 'tab2-2' }],
tab3: [{ name: 'tab3' }]
}
template still works, without needing any change.
To achieve this type of flexibility, you need to use a nested v-for loop:
<div id="tabs">
<div v-for="(items, name) in tabs" :key="name" :id="name">
<a v-for="(item, key) in items" :key="key" v-text="item.name"></a>
</div>
</div>
Demo:
new Vue({
el: '#app',
data: () => ({
tabs: {
tab1: [{
name: 'intro'
}],
tab2: [{
name: 'tab2-1'
}, {
name: 'tab2-2'
}],
tab3: [{
name: 'tab3'
}]
}
})
})
#tabs a { padding: 3px 7px }
<script src="https://v2.vuejs.org/js/vue.min.js"></script>
<div id="app">
<div id="tabs">
<div v-for="(links, name) in tabs" :key="name" :id="name">
<a v-for="(link, key) in links"
:key="key"
:href="`#${link.name}`"
v-text="link.name"></a>
</div>
</div>
</div>
But I'd take it one step further and change the tabs to be an array:
data: () => ({
tabs: [
[{ name: 'intro'}],
[{ name: 'tab1' }, { name: 'tab2' }],
[{ name: 'tab3' }]
]
})
And use :id="'tab-' + name" on tab divs if you really need those unique ids. (Hint: you don't).
It makes more sense to me.
I did not see any harm in using two v-for (one for the object keys and another for the array elements) as far as it is all dynamic. You can give a try to this solution by using of Object.keys() :
new Vue({
el: '#app',
data: {
tabs: {
first: [{ name: 'tab1' }, { name: 'tab2' }],
second: [{ name: 'tab3' }],
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div id="tabs">
<div v-for="tab in Object.keys(tabs)" :key="tab" :id="tab">
<a v-for="tab in tabs[tab]">{{ tab.name }}</a>
</div>
</div>
</div>
You could add a computed property being the .concat from both and loop for it
export default {
data() {
tabs: {
first: [{ name: 'tab1' }, { name: 'tab2' }],
second: [{ name: 'tab3' }],
}
},
computed: {
tabsCombined () {
return this.tabs.first.concat(this.tabs.second)
}
},
template: `
<div id="tabs">
<div v-for='category in tabsCombined' :id='category' :key='category'>
<template v-for="tab in tabs.test">
<a v-if='tab.category === category>{{ tab.name }}</a>
</template>
</div>
</div>
`
}

Clear Filter Functionality Not Working Vue

I'm working on a filtering feature in a Vue application. I'm new to Vue, and I have the filter semi-working. It successfully allows me to select an asset type from the dropdown, and will filter the results accordingly. But what's not working is the clearFilters method.
My goal is to reset the assetType to an empty string and the filterResults array to empty, and my thought was that since checking the length of filterResults, when I clear it it would return to displaying the entire un-filtered array.
What am I doing wrong? Any information would be greatly appreciated.
<template>
<div ref="content">
<div class="container pt-3 text-center">
<div class="filter-container">
<div class="btn-group">
<button
v-ripple="'rgba(255, 255, 255, .2)'"
#click="showAssetType = !showAssetType"
class="btn btn-secondary dropdown-toggle"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
style="max-height: 40px;">
{{assetType ? assetType : 'Asset Type'}}
</button>
<div class="dropdown-menu" :style="'display:' + (showAssetType ? 'block' : 'none') + ';'">
<a class="dropdown-item" #click.prevent="setAssetFilter('all')" href="#!">All Assets</a>
<a class="dropdown-item" #click.prevent="setAssetFilter('USD'); filterByAssetType()" href="#!">USD</a>
<a class="dropdown-item" #click.prevent="setAssetFilter('GBP'); filterByAssetType()" href="#!">GBP</a>
<a class="dropdown-item" #click.prevent="setAssetFilter('CAD'); filterByAssetType()" href="#!">CAD</a>
</div>
</div>
</div>
</div>
<div id="data-table" v-if="filterResults.length > 0">
<div v-for="(transaction, index) in filterResults" :key="index">
<global-history-item>
<template v-slot:header>
<h1 class="date">{{formatDate(transaction.date)}}</h1>
<div class="transaction-header-wrapper">
<p class="transaction-text">{{formatString(transaction.tx_type)}} Transaction</p>
<p class="transaction-text" style="text-align: right">{{transaction.coin_type}}</p>
</div>
</template>
<template v-slot:content>
<global-transaction :transaction='transaction' #updateClassType="updateClassType" />
</template>
</global-history-item>
</div>
</div>
<div id="data-table">
<div v-for="(item, index) in totalHistory" :key="index">
<div v-if="item.tx_type">
<global-history-item>
<template v-slot:header>
<h1 class="date">{{formatDate(item.date)}}</h1>
<div class="transaction-header-wrapper">
<p class="transaction-text">{{formatString(item.tx_type)}} Transaction</p>
</div>
</template>
<template v-slot:content>
<global-transaction :transaction='item' #updateClassType="updateClassType" />
</template>
</global-history-item>
</div>
<div v-else-if="item.invoice_id">
<global-history-item>
<template v-slot:header>
<h1 class="date">{{formatDate(item.date)}}</h1>
<div class="invoice-header-wrapper">
<p class="invoice-text">Invoice Created</p>
<p class="invoice-text">Invoice #{{item.invoice_id}}</p>
</div>
</template>
<template v-slot:content>
<global-invoice :invoice='item' />
</template>
</global-history-item>
</div>
<div v-else>
<global-history-item>
<template v-slot:header>
<h1 class="date">{{formatDate(item.date)}}</h1>
<div class="invoice-header-wrapper">
<p class="invoice-text">Login Event</p>
<br />
</div>
</template>
<template v-slot:content>
<global-account-activity :message='"A successful login to your account was made"' />
</template>
</global-history-item>
</div>
</div>
</div>
</div>
</template>
<script>
... imports removed for brevity
export default {
name: 'Global',
components: { },
props: ['totalHistory', 'printFormat'],
mixins: ['formatDate', 'formatMenuLabel'],
data () {
return {
showAssetType: false,
showClassType: false,
activityType: '',
assetType: '',
filterResults: [],
printMode: false
}
},
methods: {
setAssetFilter (value) {
this.showAssetType = false
this.assetType = value
},
formatString (str) {
const firstLetter = str.charAt(0)
const remainder = str.slice(1)
return firstLetter.toUpperCase() + remainder
},
updateClassType (transactionRecord) {
this.$store.dispatch('updateTransactionType', transactionRecord)
},
updateTransaction (transactionRecord) {
console.log('in updateTransaction', transactionRecord)
this.$store.dispatch('updateTransactionNote', transactionRecord)
},
filterByAssetType () {
const selectedCurrency = this.assetType
if (this.assetType === 'all') {
this.clearFilters()
} else {
this.filterResults = this.totalHistory.filter(function (trans) {
return trans.currency === selectedCurrency
})
}
},
clearFilters () {
return (this.assetType = '') && (this.filterResults = [])
}
}
}
</script>
So if I am not mistaking, you only want the method clearFilters, to work? If so, try:
clearFilters () {
this.assetType = ''
this.filterResults = []
}
The logical AND operator (&&) is not to chain expressions. It’s to do an expression if the first expression is truthy.
First expression && second expression, example
const questionAnswered = true
console.log(questionAnswered && "Hooray!")
// will log "Hooray!" (Expression 2)
If you set questionAnswered to false, it will log false (expression 1)
I agree with Jens rewrite of clearFilters(). The original looked odd to me.
I had started creating a sample component to demonstrate possibly simplifying the filtering process when there were no answers. Since I have finished it and it works, I am posting it.
ClearFilters.vue
<template>
<div class="clear-filters">
<div class="row">
<div class="col-md-6">
<table class="table table-bordered">
<thead>
<tr>
<th>NAME</th>
<th>CURRENCY</th>
</tr>
</thead>
<tbody>
<tr v-for="asset in filteredAssets" :key="asset.id">
<td>{{ asset.name }}</td>
<td>{{ asset.currency }}</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="criteria-label">FILTER CRITERIA:</label>
<select class="form-control" v-model="currentCriteria">
<option v-for="(criteria, index) in criteriaOptions" :key="index" :value="criteria">{{ criteria }}</option>
</select>
</div>
<button type="button" class="btn btn-secondary" #click="resetFilter">Reset</button>
</div>
</div>
</div>
</template>
<script>
import assets from './clear-filters-data.js';
export default {
data() {
return {
assets: assets,
criteriaOptions: [
'ALL', 'USD', 'GBP', 'CAD'
],
currentCriteria: 'ALL'
}
},
computed: {
filteredAssets() {
if (this.currentCriteria === 'ALL') {
return this.assets;
}
else {
return this.assets.filter( asset => asset.currency === this.currentCriteria);
}
}
},
methods: {
resetFilter() {
this.currentCriteria = 'ALL';
}
}
}
</script>
<style scoped>
.criteria-label {
font-weight: bold;
}
</style>
Test data:
const assets = [
{
id: 1,
name: 'asset1',
currency: 'USD'
},
{
id: 2,
name: 'asset2',
currency: 'USD'
},
{
id: 3,
name: 'asset3',
currency: 'USD'
},
{
id: 4,
name: 'asset4',
currency: 'GBP'
},
{
id: 5,
name: 'asset5',
currency: 'GBP'
},
{
id: 6,
name: 'asset6',
currency: 'GBP'
},
{
id: 7,
name: 'asset7',
currency: 'CAD'
},
{
id: 8,
name: 'asset8',
currency: 'CAD'
},
{
id: 9,
name: 'asset9',
currency: 'CAD'
},
]
export default assets;

vue.js store data into list from dynamically created fields

dynamically created fields
Hi, the image above shows dynamically created fields I'm using. You can add or delete the fields with the button at the right.
My goal is to
store data that are input to these dynamically created fields into a list
bind the data / display the data at a confirmation page before submitting
The expected result is that when I key in data to these fields, it will display on the confirmation page before submitting the form
I've tried using v-model, but this only works for normal fields. Here's there code for what I have now
<template>
<div>
<div v-for="(line, index) in lines" :key="index" class="row">
<div class="col-lg-6">
<div class="row">
<div class="col-2">
<q-select
v-model="line.countryCode"
label="Country Code"
:options="countryPhoneCodes"
/>
</div>
<div class="col-10">
<q-input
v-model="line.number"
label="Phone Number"
placeholder="5551234567"
type="tel"
value=""
/>
</div>
</div>
</div>
<div class="col-lg-4">
<q-select
v-model="line.phoneUsageType"
label="Type of Usage"
:options="phoneUsageTypes"
/>
</div>
<div class="col-lg-2">
<div class="block float-right">
<q-btn round #click="removeLine(index)" icon="delete" />
<q-btn round v-if="index + 1 === lines.length" #click="addLine" icon="playlist-plus" />
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PhoneNumberLine',
data () {
return {
lines: [],
blockRemoval: true,
phoneUsageTypes: [
{
label: 'Home', value: 'home'
}, {
label: 'Work', value: 'work'
}, {
label: 'Mobile', value: 'mobile'
}, {
label: 'Fax', value: 'fax'
}
],
countryPhoneCodes: [
{
label: '+90',
value: '+90'
}, {
label: '+1',
value: '+1'
}
]
}
},
watch: {
lines () {
this.blockRemoval = this.lines.length <= 1
}
},
methods: {
addLine () {
let checkEmptyLines = this.lines.filter(line => line.number === null)
if (checkEmptyLines.length >= 1 && this.lines.length > 0) {
return
}
this.lines.push({
countryCode: null,
number: null,
phoneUsageType: null
})
},
removeLine (lineId) {
if (!this.blockRemoval) {
this.lines.splice(lineId, 1)
}
}
},
mounted () {
this.addLine()
}
}
</script>
This should be similar to what you are trying to achieve. tweak it to fit your needs. good luck.
const makeLine = (n = 0) => ({
number: n
});
new Vue({
name: "App",
template: `
<div>
<div class="line" v-for="(line, idx) in lines" :key="idx">
<input v-model="line.number" />
<button #click="addLine" v-if="lines.length - 1 === idx">+</button>
<button #click="removeLine(idx)" v-if="lines.length > 1">-</button>
</div>
</div>
`,
data() {
return {
lines: [
makeLine(),
],
}
},
methods: {
addLine() {
this.lines.push(makeLine(this.lines.length));
},
removeLine(idx) {
this.lines = this.lines.filter((_, id) => id !== idx);
}
}
}).$mount("#app");
#app {
display: flex;
flex-direction: column;
}
.line {
display: flex;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app"></div>

How to filter posts in Vue with components and v-bind:class

I'm trying to make an example based on this pen I got from here:
https://codepen.io/conradolandia/pen/YzyPmrv
But I want to use vue-router, I've tried this: (pen: https://codepen.io/conradolandia/pen/vYNERPW)
HTML:
<main class="wrap">
<div id="app">
<router-view></router-view>
</div>
</main>
<template id="post-list-template">
<div class="container">
<div class="row">
<h4>Filter by album:</h4>
<div class="filters">
<button class="btn" v-bind:class="{ active: currentFilter === 'ALL' }" v-on:click="setFilter('ALL')">all</button>
<button class="btn" v-bind:class="{ active: currentFilter === 'art' }" v-on:click="setFilter('art')">art</button>
<button class="btn" v-bind:class="{ active: currentFilter === 'doodles' }" v-on:click="setFilter('doodles')">doodles</button>
<button class="btn" v-bind:class="{ active: currentFilter === 'workshops' }" v-on:click="setFilter('workshops')">workshops</button>
</div>
</div>
<div class="columns is-multiline">
<div class="column is-3" v-if="currentFilter === post.category || currentFilter === 'ALL'" v-bind:key="post.title" v-for="post in posts">
<div class="card post">
<img class="card-img-top" v-bind:src="post.image">
<div class="card-body">
<div class="card-title">{{ post.title }}</div>
<small class="tags">{{ post.category }}</small>
</div>
</div> <!-- .post -->
</div> <!-- .col-md-4 -->
</div> <!-- .row -->
</div> <!-- .container -->
</template>
CSS:
body{
background-color: #ccc;
box-sizing:border-box;
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
}
.post {
margin-bottom: 20px;
}
.post img{ width: 100%;}
.tags {background-color: #ccc; padding: 3px 5px;}
.filters {
margin-bottom: 20px;
}
JS:
var postList = Vue.extend({
template: "#post-list-template",
data: function(){
return {
currentFilter:'ALL',
posts: [
{title: "Artwork", image: "https://picsum.photos/g/200?image=122", category: 'art'},
{title: "Charcoal", image: "https://picsum.photos/g/200?image=116", category: 'art'},
{title: "Sketching", image: "https://picsum.photos/g/200?image=121", category: 'doodles'},
{title: "Acrillic", image: "https://picsum.photos/g/200?image=133", category: 'workshops'},
{title: "Pencil", image: "https://picsum.photos/g/200?image=134", category: 'doodles'},
{title: "Pen", image: "https://picsum.photos/g/200?image=115", category: 'art'},
{title: "Inking", image: "https://picsum.photos/g/200", category: 'workshops'},
{title: "Artwork", image: "https://picsum.photos/g/200?image=121", category: 'art'},
{title: "Charcoal", image: "https://picsum.photos/g/200?image=115", category: 'art'},
{title: "Sketching", image: "https://picsum.photos/g/200?image=124", category: 'doodles'},
{title: "Acrillic", image: "https://picsum.photos/g/200?image=13", category: 'workshops'},
{title: "Pencil", image: "https://picsum.photos/g/200?image=14", category: 'doodles'},
]
}
},
methods: {
setFilter: function(filter) {
this.currentFilter = filter;
}
},
})
// Start a new instance of router (instead of router.map)
var router = new VueRouter({
routes: [
{ path: '/', component: postList }
]
})
// Start a new instance of the Application required (instead of router.start)
new Vue({
el: '#app',
router: router,
})
So far, no luck. The filter kind of works, the first click I make activates a filtering option, but then all filters stop working, and firefox complains with "TypeError: "e is undefined"".
Can somebody point me in the right direction, please? I don't understand why the first codepen link works but the second doesn't.
Clarifying: When I click any filter, filters kind of work, but if I click the "ALL" filter, everything stops working.
Try using a computed function
computed:{
filteredPosts:function(){
if(this.currentFilter==='ALL'){
return this.posts;
}
return this.posts.filter(post=>{
return post.category === this.currentFilter;
})
}
}
You can use filteredPosts instead of posts while looping
<div class="columns is-multiline">
<div class="column is-3" :key="post.title" v-for="post in filteredPosts">
<div class="card post">
<img class="card-img-top" :src="post.image">
<div class="card-body">
<div class="card-title">{{ post.title }}</div>
<small class="tags">{{ post.category }}</small>
</div>
</div> <!-- .post -->
</div> <!-- .col-md-4 -->
</div> <!-- .row -->
You don't need to use any condition while looping, since the computed function will do the job.

How to show correct job name when clicking on a checkbox with Vue JS?

I'm new to Vue JS, I have the following code to show corresponding job title when clicking on a checkbox according to the IDs.
For example, initially there is no job title shown, if John's id = 1, job title "doctor" also has id = 1, then clicking on John should show "doctor". I tried to compare the input user.id against the array job.id, but I don't know how to do this.
Here is my code:
var filter = new Vue({
el: "#filter",
data: {
users: [
{
name: "John",
id: 1
},
{
name: "Tom",
id: 2
}
],
jobs: [
{
title: "doctor",
id: 1
},
{
title: "engineer",
id: 2
}
]
},
methods: {
filterUser: function (userId) {
if (this.jobs.id.includes(userId)) {
// show corresponding job title
};
}
}
})
.sidebar {
border: 1px solid black;
}
.panel {
border: 1px solid grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container">
<div class="row" id="filter">
<div class="col-sm-3 sidebar">
<ul>
<li v-for="user in users">
<input type="checkbox" v-on:change="filterUser(user.id)">
{{ user.name }}
</li>
</ul>
</div>
<div class="col-sm-9 panel">
<ul>
<li v-for="job in jobs">
{{ job.title }}
</li>
</ul>
</div>
</div>
</div>
Instead of changing original 'jobs' you should take another variable 'filterjobs' for complete checked and unchecked process.
var filter = new Vue({
el: "#filter",
data: {
users: [
{
name: "John",
id: 1
},
{
name: "Tom",
id: 2
}
],
jobs: [
{
title: "doctor",
id: 1
},
{
title: "engineer",
id: 2
}
],
filterJobs:[]
},
methods: {
filterUser: function (userId) {
var index = this.filterJobs.findIndex(e => e.id === userId)
if(index >= 0){
//Remove on Uncheck
this.filterJobs.splice(index, 1);
}
else{
var jobIndex = this.jobs.findIndex(e => e.id === userId)
if(jobIndex >= 0){
this.filterJobs.push(this.jobs[jobIndex]);
}
}
}
}
})
.sidebar {
border: 1px solid black;
}
.panel {
border: 1px solid grey;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container">
<div class="row" id="filter">
<div class="col-sm-3 sidebar">
<ul>
<li v-for="user in users">
<input type="checkbox" v-on:change="filterUser(user.id)">
{{ user.name }}
</li>
</ul>
</div>
<div class="col-sm-9 panel">
<ul>
<li v-for="job in filterJobs">
{{ job.title }}
</li>
</ul>
</div>
</div>
</div>
You can do that with find
filterUser: function (userId) {
var job = this.jobs.find(e => e.id == userId);
var jobTitle = job.title;
}

Categories

Resources