Related
I'm trying to create a cascading dropdown using vue.js.
I want to set the data on the second dropdown based on the item chosen from the first dropdown.
I don't know how to filter the data based on the chosen item.
I've tried to use computed property but didn't succeed.
I need some help please.
Thanks in advance.
<template>
<b-container class="my-2">
<b-row>
<b-col col="12" md="6" lg="3">
<b-form-group id="fieldset" :label="$t('tradingCalculators.fields.currencyPair')" label-for="currency-first" label-size="lg">
<v-select
id="assetPair"
#click="changeAssetClass(assetPair)"
v-model="assetPair"
:searchable="true"
:options="assetSymbols"
/>
</b-form-group>
</b-col>
<b-col cols="12" md="6" lg="3">
<b-form-group id="fieldset-1" :label="$t('tradingCalculators.fields.currencyPair')" label-for="currency-pair" label-size="lg">
<v-select id="symbolsPair" v-model="symbolsPair" :searchable="true" :options="currencyArray" />
</b-form-group>
</b-col>
</b-row>
</b-container>
</template>
export default {
data() {
assetPair: 'Forex',
symbolsPair: '',
currencyArray: [],
assetsSymbols: [{
text: 'Forex',
id: 1
},
{
text: 'Metal',
id: 2
},
{
text: 'Indices',
id: 3
},
],
symbolsPair: {
1: [{
text: 'AUDCAD',
id: 1,
},
{
text: 'AUDCHF',
id: 2,
},
{
text: 'AUDJPY',
id: 3,
},
],
2: [{
text: 'XAUUSD',
id: 1,
},
{
text: 'XAGUSD',
id: 2,
},
],
3: [{
text: 'GER30Cash',
id: 1,
},
{
text: 'US30Cash',
id: 2,
},
{
text: 'EU50Cash',
id: 3,
},
],
}
},
computed() {
changeAssetClass(e) {
return this.currencyArray.push(this.symbolsPair[e])
}
}
}
One observation : You are updating the source array this.currencyArray on first dropdown select. Hence, the cascading dropdown will not contain the filtered data.
Working Demo :
new Vue({
el: '#app',
data: function() {
return {
assetsSymbols: [{
text: 'Forex',
id: 1
}, {
text: 'Metal',
id: 2
}, {
text: 'Indices',
id: 3
}
],
selectedSymbol: '',
selectedSymbolPair: '',
symbolsPairArr: [],
symbolsPair: {
1: [{
text: 'AUDCAD',
id: 1,
},
{
text: 'AUDCHF',
id: 2,
},
{
text: 'AUDJPY',
id: 3,
},
],
2: [{
text: 'XAUUSD',
id: 1,
},
{
text: 'XAGUSD',
id: 2,
},
],
3: [{
text: 'GER30Cash',
id: 1,
},
{
text: 'US30Cash',
id: 2,
},
{
text: 'EU50Cash',
id: 3,
},
]}
}
},
watch: {
selectedSymbol: function() {
this.symbolsPairArr = [];
if (this.selectedSymbol > 0) {
this.symbolsPairArr = this.symbolsPair[this.selectedSymbol];
}
}
},
mounted() {
this.selectedSymbol = 2;
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div class="cascading-dropdown">
<div class="dropdown">
<span>Symbol :</span>
<select v-model="selectedSymbol">
<option value="">Select a Symbol</option>
<option v-for="symbol in assetsSymbols" :value="symbol.id" :key="symbol.id">{{ symbol.text }}</option>
</select>
</div>
<div class="dropdown">
<span>Symbol Pair:</span>
<select :disabled="!selectedSymbol" v-model="selectedSymbolPair">
<option value="">Select a Pair</option>
<option v-for="pair in symbolsPairArr" :value="pair.id" :key="pair.id">{{ pair.text }}</option>
</select>
</div>
</div>
</div>
Note : I created this snippet to demonstrate you how it will work as per your requirement. You can modify it as per the need if required.
I want to sum every existing and added value to a total sum, which I can always see.
I'm kinda struggling with how to include my existing values and those I want to add afterward.
In IncomeList I have two inputs. One for the incomeReason and with the other I can add the value (newIncomeValue). Every Item in my List contains an id. With sumValue I want to display the total amount, but I'm not sure how to do it
It looks like this:
IncomeItem.vue
<template>
<div class="income-item">
<div class="income-item-left">
<div v-if="!editing" #dblclick="editincome" class="income-item-label"
:class="{ completed : completed }">{{ title }}</div>
</div>
<div class="income-item-right"> {{ value }} </div>
<div class="remove-item" #click="removeincome(income.id)">
×
</div>
</div>
</template>
<script>
export default {
name: 'income-item',
props: {
income: {
type: Object,
required: true,
},
checkAll: {
type: Boolean,
required: true,
}
},
data() {
return {
'id': this.income.id,
'title': this.income.title,
'value': this.income.value,
'completed': this.income.completed,
'editing': this.income.editing,
'beforeEditCache': '',
}
},
watch: {
checkAll() {
// if (this.checkAll) {
// this.completed = true
// } else {
// this.completed = this.income.completed
// }
this.completed = this.checkAll ? true : this.income.completed
}
},
directives: {
focus: {
inserted: function (el) {
el.focus()
}
}
},
methods: {
removeincome(id) {
this.$emit('removedincome', id)
},
}
}
</script>
IncomeList.vue
<template>
<div>
<input type="text" class="income-input" placeholder="What needs to be done" v-model="newIncome" #keyup.enter="addincome">
<input type="text" class="value-input" placeholder="€" v-model="newIncomeValue" #keyup.enter="addValue">
<transition-group name="fade" enter-active-class="animated fadeInUp" leave-active-class="animated fadeOutDown">
<income-item v-for="income in incomesFiltered" :key="income.id" :income="income" :checkAll="!anyRemaining"
#removedIncome="removeincome" #finishedEdit="finishedEdit">
</income-item>
</transition-group>
<div class="extra-container">
<div><label><input type="checkbox" :checked="!anyRemaining" #change="checkAllincomes"> Check All</label></div>
<div>{{ remaining }} items left</div>
</div>
<div class="sum-container">
<div><label> Einkommen: </label></div>
<div>{{ sumValue }} €</div>
</div>
</div>
</template>
<script>
import IncomeItem from './IncomeItem'
export default {
name: 'income-list',
components: {
IncomeItem,
},
data () {
return {
newIncome: '',
newIncomeValue: '',
idForincome: 3,
incomes: [
{
'id': 1,
'title': 'Finish Vue Screencast',
'value': 300,
'completed': false,
'editing': false,
},
{
'id': 2,
'title': 'Take over world',
'value': 315,
'completed': false,
'editing': false,
},
]
}
},
computed: {
remaining() {
return this.incomes.filter(income => !income.completed).length
},
anyRemaining() {
return this.remaining != 0
},
incomesFiltered() {
return this.incomes
},
sumValue() {
var total = parseInt(document.getElementsByClassName('newIncomeValue').value)
return total;
},
},
methods: {
addincome() {
if (this.newIncome.trim().length == 0) {
return
}
this.incomes.push({
id: this.idForincome,
title: this.newIncome,
value: this.newIncomeValue,
completed: false,
})
this.newIncome = ''
this.newIncomeValue = ''
this.this.idForincome++
},
removeincome(id) {
const index = this.incomes.findIndex((item) => item.id == id)
this.incomes.splice(index, 1)
},
checkAllincomes() {
this.incomes.forEach((income) => income.completed = event.target.checked)
},
clearCompleted() {
this.incomes = this.incomes.filter(income => !income.completed)
},
finishedEdit(data) {
const index = this.incomes.findIndex((item) => item.id == data.id)
this.incomes.splice(index, 1, data)
},
//Same for Value
addValue() {
if (this.newIncomeValue.trim().length == 0) {
return
}
this.incomes.push({
id: this.idForincome,
title: this.newIncome,
value: this.newIncomeValue,
completed: false,
})
this.newIncome = ''
this.newIncomeValue = ''
this.this.idForincome++
},
}
}
</script>
If you want to sum the value property of your incomesFiltered, you can use reduce in your computed:
sumValue() {
return this.incomesFiltered.reduce((a, c) => a + c.value, 0);
}
I'm trying to create a checkbox select only one.
<div id="app">
<div v-for="(question, index) in questions">
<input type="checkbox" value="question.value" v-model="additional_grouped" #change="uniqueCheck"> {{question.title}}
</div>
{{ result }}
</div>
My JS looks like the following:
new Vue({
el: '#app',
data() {
return {
additional: [],
additional_grouped: [],
questions: [
{
title: 'A',
value: 0
},
{
title: 'B',
value: 1
},
{
title: 'C',
value: 2
}
]
}
},
computed: {
result: function(){
return this.additional.concat(this.additional_grouped);
}
},
methods: {
uniqueCheck(e){
console.log(e)
this.additional_grouped = [];
if (e.target.checked) {
this.additional_grouped.push(e.target.value);
}
}
}
});
This is the old result.
I'm trying to get results like this.
I can do this by not the v-for method, but I want to do it this way. Because I have a lot of data, How can I checked value in v-for?
Here is my pen: enter link description here
You are missing the value binding (:value), here's your example fixed:
new Vue({
el: '#app',
data() {
return {
additional: [],
additional_grouped: [],
questions: [
{
title: 'A',
value: 0
},
{
title: 'B',
value: 1
},
{
title: 'C',
value: 2
}
]
}
},
computed: {
result: function(){
return this.additional.concat(this.additional_grouped);
}
},
methods: {
uniqueCheck(e){
this.additional_grouped = [];
if (e.target.checked) {
this.additional_grouped.push(e.target.value);
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(question, index) in questions">
<input type="checkbox" :value="question.value" v-model="additional_grouped" #change="uniqueCheck"> {{question.title}}
</div>
{{ result }}
</div>
Documentation
uses :value="question.value" instead of value="question.value"
new Vue({
el: '#app',
data() {
return {
additional: [],
additional_grouped: [],
questions: [
{
title: 'A',
value: 0
},
{
title: 'B',
value: 1
},
{
title: 'C',
value: 2
}
]
}
},
computed: {
result: function(){
return this.additional.concat(this.additional_grouped);
}
},
methods: {
uniqueCheck(e){
this.additional_grouped = [];
if (e.target.checked) {
this.additional_grouped.push(e.target.value);
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-for="(question, index) in questions">
<input type="checkbox" :value="question.value" v-model="additional_grouped" #change="uniqueCheck"> {{question.title}}
</div>
{{ result }}
</div>
If you want to get an array of the values of checked boxes, you should just do this
<div id="app">
<div v-for="(question, index) in questions" :key="index">
<input type="checkbox" v-model="question.checked"> {{question.title}}
</div>
{{ result }}
</div>
and
new Vue({
el: '#app',
data() {
return {
questions: [
{
title: 'A',
value: 0
},
{
title: 'B',
value: 1
},
{
title: 'C',
value: 2
}
]
}
},
computed: {
result: function(){
return this.questions.filter(q => q.checked).map(q => q.value)
}
}
});
I'm making a dynamic admin panel with crud generator with the help of laravel and vue.
I have a table where I'm loading data asynchronously from API. There is an is_featured column in my table which I want to be a switch. So that the user can change the value from the table page instead of going to edit page.
To generate my entire table there is a configuration object that contains which fields to show and the type of that field and other metadata. In the configuration object, there is a field named prerender which is responsible to prerender fields that require calling other API or some editable fields like select dropdown or switch.
To make switch and select fields work, I have an empty object named fieldData.
When a field with type: boolean and prerender: true is found, my code will initialize a property with field.name as property name in field data and fill it with the corresponding values under that field name
this.fieldData[field.name] = {};
this.tableData.forEach(
data => (this.fieldData[field.name][data.id] = data[field.name])
);
BUT THE SWITCH AND SELECT ARE NOT WORKING HERE
So I need help.
Here's my entire code for reference
<template>
<div class="app-container">
<el-row :gutter="20" style="display: flex; align-items: center;">
<el-col :span="10">
<h1 style="text-transform: capatilize;">{{ resourceName }}</h1>
</el-col>
<el-col :span="14" style="display: flex; justify-content: flex-end; align-items: center">
<el-input
v-model="navigation.search"
placeholder="Search anything here"
prefix-icon="el-icon-search"
style="width: 300px; margin: 0 10px;"
#keydown.enter.native="handleGlobalSearch"
/>
<FilterPannel
style="margin: 0 10px"
:filter-pannel-obj="filterPannelObj"
#set-filter="handleFilterVals"
#reset-filter="getTableData({})"
/>
<Import
:url="`/api/${resourceName}/upload`"
#import-success="handleImportSucces"
#import-error="handleImportError"
/>
<Export :url="`/api/${resourceName}/export`" :selected-ids="selected.map(el => el.id)" />
<el-button
type="info"
icon="el-icon-delete"
#click="$refs['table'].clearSelection()"
>Clear Selection</el-button>
<el-button type="danger" icon="el-icon-delete" #click="handleMultipleDelete">Delete Selected</el-button>
</el-col>
</el-row>
<el-row>
<el-table
ref="table"
v-loading="loading.tableData"
:data="tableData"
border
:row-key="getRowKeys"
#sort-change="handleSortChange"
#selection-change="handleSelectionChange"
>
<el-table-column type="selection" label="Selection" reserve-selection />
<el-table-column label="Actions" width="200">
<template slot-scope="scope">
<div style="display: flex; justify-content: space-around;">
<el-button
icon="el-icon-view"
type="primary"
circle
#click="$router.push(`/${resourceName}/view/${scope.row.id}`)"
/>
<el-button
icon="el-icon-edit"
type="success"
circle
#click="$router.push(`/${resourceName}/edit/${scope.row.id}`)"
/>
<el-button
icon="el-icon-delete"
type="danger"
circle
#click="handleDeleteClick(scope.row.id)"
/>
</div>
</template>
</el-table-column>
<el-table-column
v-for="field in fieldsToShow"
:key="field.name"
:prop="field.name"
:label="field.name.replace('_',' ')"
sortable="custom"
>
<template slot-scope="scope">
<div
v-if="field.type=='multilangtext'"
class="cell"
>{{ JSON.parse(scope.row[field.name])[$store.state.app.language] }}</div>
<div v-if="field.type=='text'" class="cell">{{ scope.row[field.name] }}</div>
<el-tag v-if="field.type=='tag'">{{ scope.row.type }}</el-tag>
<img v-if="field.type=='image'" :src="scope.row.icon" width="100px" height="100px" />
<div v-if="field.type=='oneFrom'" class="cell">
<el-tag
:key="scope.row[field.name]"
>{{field.multilang ? scope.row[field.name][$store.state.app.language] : scope.row[field.name]}}</el-tag>
</div>
<div v-if="field.type=='manyFrom'" class="cell">
<el-tag
style="margin: 5px"
v-for="(item, index) in scope.row[field.name]"
:key="`${field.multilang ? item[$store.state.app.language] : item}+${index}`"
>{{field.multilang ? item[$store.state.app.language] : item}}</el-tag>
</div>
<div v-if="field.type=='boolean'" class="cell">
{{scope.row.id}} =>
{{field.name}} =>>
{{scope.row[field.name]}} =>>>
{{fieldData[field.name][scope.row.id]}}
<el-switch
:key="`switch${scope.row.id}`"
v-model="fieldData[field.name][scope.row.id]"
:active-value="1"
:inactive-value="0"
></el-switch>
</div>
<div v-if="field.type=='select'" class="cell">
<el-select :key="`select${scope.row.id}`" v-model="fieldData[field.name][scope.row.id]" placeholder="Select">
<el-option
v-for="item in field.options"
:key="item"
:label="item"
:value="item"
></el-option>
</el-select>
</div>
</template>
</el-table-column>
</el-table>
</el-row>
<el-row>
<pagination
style="padding: 0;"
:total="paginationData.total"
:page.sync="paginationData.current_page"
:limit.sync="paginationData.per_page"
#pagination="handlePagination"
/>
</el-row>
</div>
</template>
<script>
import Pagination from '#/components/Pagination';
import FilterPannel from '#/components/FilterPannel';
import Export from './components/Export'; // ? not needed
import Import from './components/Import';
import axios from 'axios';
import Resource from '#/api/resource';
const resourceName = 'coupons';
const ResourceApi = new Resource(resourceName);
export default {
name: 'CategoryList',
components: {
Pagination,
FilterPannel,
Export,
Import,
},
data() {
return {
resourceName: resourceName,
language: 'en',
tableData: [],
fieldData: {},
fieldsToShow: [
{ name: 'title', type: 'multilangtext' },
// { name: 'description', type: 'multilangtext' },
{ name: 'code', type: 'text' },
// { name: 'expiry_date', type: 'text' },
{ name: 'type', type: 'tag' },
{
name: 'store_id',
type: 'oneFrom',
url: '/api/stores/',
foreignKey: 'store_id',
attrName: 'name',
multilang: true,
prerender: true,
},
{
name: 'tags',
type: 'manyFrom',
url: '/api/tags?idsarr=',
foreignKey: 'tags',
attrName: 'name',
multilang: true,
prerender: true,
},
{
name: 'brands',
type: 'manyFrom',
url: '/api/brands?idsarr=',
foreignKey: 'brands',
attrName: 'name',
multilang: true,
prerender: true,
},
// { name: 'brands', type: 'text' },
{ name: 'is_featured', type: 'boolean', prerender: true },
{
name: 'status',
type: 'select',
options: ['publish', 'draft', 'trash'],
prerender: true,
},
],
paginationData: {
current_page: 0,
last_page: 0,
per_page: 0,
total: 0,
},
navigation: {
page: 1,
limit: 10,
sort: '',
'sort-order': 'asc',
filters: '',
search: '',
},
filters: '',
selected: [], // ? for selection
loading: {
tableData: false,
},
allData: [],
filterPannelObj: {
title: {
default: '',
type: 'Input',
label: 'Title',
},
description: {
default: '',
type: 'Input',
label: 'Description',
},
promo_text: {
default: '',
type: 'Input',
label: 'Promo Text',
},
type: {
default: [],
type: 'checkbox',
label: 'Type',
src: [
{ value: 'coupon', label: 'Coupon' },
{ value: 'offer', label: 'Offer' },
],
},
code: {
default: '',
type: 'Input',
label: 'Code',
},
store_id: {
default: [],
type: 'select',
label: 'Store',
src: [],
multiple: true,
},
brands: {
default: [],
type: 'select',
label: 'Brands',
src: [],
multiple: true,
},
tags: {
default: [],
type: 'select',
label: 'Tags',
src: [],
multiple: true,
},
cats: {
default: [],
type: 'select',
label: 'Categories',
src: [],
multiple: true,
},
},
};
},
watch: {
async 'navigation.search'(newVal, oldVal) {
await this.handleGlobalSearch();
},
},
async created() {
await this.getTableData({});
this.allData = await ResourceApi.list({ limit: -1 });
// to fill filter dialog selects
// To get brands
this.filterPannelObj.brands.src = (await axios.get(
`/api/brands?limit=-1`
)).data.map(({ name, id }) => ({
label: JSON.parse(name)[this.$store.state.app.language],
value: id,
}));
// To get tags
this.filterPannelObj.tags.src = (await axios.get(
`/api/tags?limit=-1`
)).data.map(({ name, id }) => ({
label: JSON.parse(name)[this.$store.state.app.language],
value: id,
}));
// To get categories
this.filterPannelObj.cats.src = (await axios.get(
`/api/categories?limit=-1`
)).data.map(({ name, id }) => ({
label: JSON.parse(name)[this.$store.state.app.language],
value: id,
}));
// To get stores
this.filterPannelObj.store_id.src = (await axios.get(
`/api/stores?limit=-1`
)).data.map(({ name, id }) => ({
label: JSON.parse(name)[this.$store.state.app.language],
value: id,
}));
},
methods: {
printScope(x) {
console.log('TCL: printScope -> x', x);
},
async getTableData(query) {
this.loading.tableData = true;
const responseData = await ResourceApi.list(query);
this.tableData = responseData.data;
this.paginationData = this.pick(
['current_page', 'last_page', 'per_page', 'total'],
responseData
);
Object.keys(this.paginationData).forEach(
key => (this.paginationData[key] = parseInt(this.paginationData[key]))
);
await this.handlePrerender();
this.loading.tableData = false;
},
async handlePrerender() {
this.fieldsToShow.forEach(async field => {
if (field.prerender) {
switch (field.type) {
case 'oneFrom': {
await this.setRelatedFieldName(field);
break;
}
case 'manyFrom': {
await this.setRelatedFieldName(field);
break;
}
case 'boolean': {
this.fieldData[field.name] = {};
this.tableData.forEach(
data => (this.fieldData[field.name][data.id] = data[field.name])
);
break;
}
case 'select': {
this.fieldData[field.name] = {};
this.tableData.forEach(
data => (this.fieldData[field.name][data.id] = data[field.name])
);
break;
}
}
}
});
},
// utils
pick(propsArr, srcObj) {
return Object.keys(srcObj).reduce((obj, k) => {
if (propsArr.includes(k)) {
obj[k] = srcObj[k];
}
return obj;
}, {});
},
// ? remember to refactor the parameter id
async setRelatedFieldName({
name,
type,
url,
foreignKey,
attrName,
multilang,
}) {
this.tableData.forEach(async data => {
if (type === 'oneFrom') {
data[name] = (await axios.get(`${url}${data[foreignKey]}`)).data[
attrName
];
if (multilang) {
data[name] = JSON.parse(data[name]);
}
} else if (type === 'manyFrom') {
data[name] = (await axios.get(`${url}${data[foreignKey]}`)).data.map(
idata => (multilang ? JSON.parse(idata[attrName]) : idata[attrName])
);
}
});
},
// Sort
async handleSortChange(change) {
this.navigation.sort = change.prop;
if (change.order === 'ascending') {
this.navigation['sort-order'] = 'asc';
} else if (change.order === 'descending') {
this.navigation['sort-order'] = 'desc';
}
await this.getTableData(this.navigation);
},
// Pagination
async handlePagination(obj) {
// obj page obj containing {page: ..., limit: ...}
this.navigation.page = obj.page;
this.navigation.limit = obj.limit;
await this.getTableData(this.navigation);
},
// Global Search
async handleGlobalSearch() {
await this.getTableData(this.navigation);
},
// ? Skipped for now
// Filters
async handleFilterVals(filterparams) {
console.log('TCL: handleFilterVals -> filterparams', filterparams);
this.navigation.filters = JSON.stringify(filterparams.filters);
this.navigation.sort = filterparams.sort.field;
this.navigation.sort = 'name';
this.navigation['sort-order'] = filterparams.sort.asc ? 'asc' : 'desc';
await this.getTableData(this.navigation);
},
async handleDeleteClick(id) {
ResourceApi.destroy(id)
.then(res => {
this.$message.success('Delete Successfully');
this.getTableData({ page: this.paginationData.current_page });
})
.error(err => {
this.$message.error(err);
});
},
// Selection methods
handleSelectionChange(selection) {
this.selected = selection;
},
getRowKeys(row) {
return row.id;
},
// Multiple Delete
handleMultipleDelete() {
axios
.delete(
`/api/${this.resourceName}/delete-multiple?ids=${this.selected
.map(item => item.id)
.join(',')}`
)
.then(async () => {
this.$message.success('Records deleted successfully');
await this.getTableData({ page: this.paginationData.current_page });
if (this.tableData.length === 0) {
await this.getTableData({
page: this.paginationData.current_page,
});
}
this.$refs.table.clearSelection();
})
.catch();
},
// Import Events
handleImportSucces() {
this.$message.success('New Data Imported');
this.getTableData({});
},
handleImportError(err) {
this.$message.error('There were some errors. CHK console');
console.log(err);
},
},
};
</script>
<style lang="scss" scoped>
</style>
I guess this is a reactive issue. The value of dict and actually not affecting the feildData dict.
changes -
this.fieldData[field.name] = {};
replace this with
self.$set(self.fieldData,field.name,{});
and
this.fieldData[field.name][data.id] = data[field.name] // to
//Replace
self.$set(self.fieldData[field.name],data.id, data[field.name]);
I think this will fix the issue.Instead of using = use $set for value assignment.
Codepen - https://codepen.io/Pratik__007/pen/gObGOKx
I've create a new directive to use the jQuery Plug-In Select2 with vue.js as written down on the vue.js example page.
But I don't want to just output the value of the selected option. To store the selections I try to bind my custom method create to the #change event.
Inside the directive, the Select2 will trigger the change event for the select input field while it updates, but nevertheless it still doesn't call my custom method.
Is there some hidden magic? I've tried to read the source code of vue.js but can't find something that puts me in the right direction.
Vue.directive('select', {
twoWay: true,
priority: 1000,
params: ['options'],
bind: function() {
var self = this;
$(this.el)
.select2({
data: this.params.options
})
.on('change', function() {
self.set(this.value);
});
},
update: function(value) {
$(this.el).val(value).trigger('change');
},
unbind: function() {
$(this.el).off().select2('destroy');
}
});
var vm = new Vue({
el: '#items',
data: {
items: [],
new_item: '',
options: [{
id: 1,
text: 'First'
}, {
id: 2,
text: 'Second'
}, {
id: 3,
text: 'Third'
}, {
id: 4,
text: 'Fourth'
}, {
id: 5,
text: 'Fifth'
}]
},
methods: {
create: function() {
var self = this,
label = '';
this.options.map(function(item) {
if (self.new_item == item.id)
label = item.text;
});
var obj = {
id: self.new_item,
name: label
};
this.items.push(obj);
this.new_item = '';
}
}
});
select {
min-width: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/vue/1.0.24/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<div id="items">
<ul>
<li v-for="item in items">{{ item.id }} – {{ item.name }}</li>
</ul>
<select v-select="new_item" #change="create" :options="options">
<option value="0">--Select--</option>
</select>
</div>
Maybe you can add watcher to your new_item variable like this. So you can do something when new_item value change.
I myself still searching how to trigger #change after select2 change method, but no clue til now.
Vue.directive('select', {
twoWay: true,
priority: 1000,
params: ['options'],
bind: function() {
var self = this;
$(this.el)
.select2({
data: this.params.options
})
.on('change', function() {
self.set(this.value);
});
},
update: function(value) {
$(this.el).val(value).trigger('change');
},
unbind: function() {
$(this.el).off().select2('destroy');
}
});
var vm = new Vue({
el: '#items',
data: {
items: [],
new_item: '',
options: [{
id: 1,
text: 'First'
}, {
id: 2,
text: 'Second'
}, {
id: 3,
text: 'Third'
}, {
id: 4,
text: 'Fourth'
}, {
id: 5,
text: 'Fifth'
}]
},
methods: {
create: function() {
var self = this,
label = '';
this.options.map(function(item) {
if (self.new_item == item.id)
label = item.text;
});
var obj = {
id: self.new_item,
name: label
};
this.items.push(obj);
this.new_item = '';
}
},
watch:{
new_item:function(){
alert(this.new_item);
}
}
});
select {
min-width: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/vue/1.0.24/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/js/select2.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.3/css/select2.min.css" rel="stylesheet" />
<div id="items">
<ul>
<li v-for="item in items">{{ item.id }} – {{ item.name }}</li>
</ul>
<select v-select="new_item" #change="create" :options="options">
<option value="0">--Select--</option>
</select>
</div>