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>
Related
i have two tasks:
Displaying the items of the item list 3 per row
Add a input field used to edit the title field in the currently selected element (selection should be made by clicking).
So, I made the first task based on this solving V-if inside v-for - display list of items in two columns and now i have a problem with my second task selecting method. It should be working for every item but on click selects an items from every list and can to edit only from first list. I think that problem can be in onItemClick(index) method but don't know why.
Any ideas about that?
Vue.component('item-list', {
template: '#item-list-template',
data() {
return {
items: [{
title: 'item 1'
},
{
title: 'item 2'
},
{
title: 'item 3'
},
{
title: 'item 4'
},
{
title: 'item 5'
},
{
title: 'item 6'
}
],
activeIndex: -1,
rowArray: []
}
},
mounted(){
this.fakeFetchData();
},
methods: {
// new method from example solving
fakeFetchData(){
var cloned = this.items.slice();
while (cloned.length > 0) {
let chunk = cloned.splice(0,3);
this.rowArray.push(chunk);
}
},
onItemClick(index) {
this.activeIndex = this.activeIndex === index ? -1 : index;
},
setActiveItemValue(event) {
const foundItem = this.items[this.activeIndex];
if (!foundItem) return;
return this.items[this.activeIndex].title = event.currentTarget.value;
}
},
computed: {
activeItemValue() {
return this.items[this.activeIndex]?.title ?? '';
}
}
});
Vue.component('item', {
template: '#item-template',
props: {
isActive: Boolean,
title: String
}
});
new Vue({
el: '#app'
});
li.active {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<item-list></item-list>
</div>
<script type="text/x-template" id="item-list-template">
<div>
<input type="text" placeholder="Edit selected items" :value="activeItemValue" #input="setActiveItemValue" />
<div class="items-col">
<ul class="items-list" v-for="(row, rowIndex) in rowArray" :key="rowIndex">
<item v-for="(item, i) in row" :key="i" :title="item.title" :isActive="activeIndex === i" #click.native="onItemClick(i)" />
</ul>
</div>
</div>
</script>
<script type="text/x-template" id="item-template">
<li class="item" :class="{ active: isActive }">{{ title }}</li>
</script>
<style>
.items-list {
display: flex;
}
</style>
I have modified and moved the fakeFetchData() from mounted to inside computed and modified the inner v-for inside the template. Check it out
Vue.component('item-list', {
template: '#item-list-template',
data() {
return {
items: [{
title: 'item 1'
},
{
title: 'item 2'
},
{
title: 'item 3'
},
{
title: 'item 4'
},
{
title: 'item 5'
},
{
title: 'item 6'
}
],
activeIndex: -1,
rowArray: []
}
},
methods: {
// new method from example solving
onItemClick(index) {
this.activeIndex = this.activeIndex === index ? -1 : index;
},
setActiveItemValue(event) {
const foundItem = this.items[this.activeIndex];
if (!foundItem) return;
return this.items[this.activeIndex].title = event.currentTarget.value;
}
},
computed: {
activeItemValue() {
return this.items[this.activeIndex]?.title ?? '';
},
fakeFetchData(){
// ********* Changes done below ************
var cloned = this.items.map((item, index) => {
return {title: item.title, id: index}
});
this.rowArray = [];
while (cloned.length > 0) {
let chunk = cloned.splice(0,3);
this.rowArray.push(chunk);
}
return this.rowArray;
// ******* End of changes ********
},
}
});
Vue.component('item', {
template: '#item-template',
props: {
isActive: Boolean,
title: String
}
});
new Vue({
el: '#app'
});
li.active {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<item-list></item-list>
</div>
<script type="text/x-template" id="item-list-template">
<div>
<input type="text" placeholder="Edit selected items" :value="activeItemValue" #input="setActiveItemValue" />
<div class="items-col">
<ul class="items-list" v-for="(row, rowIndex) in fakeFetchData" :key="rowIndex">
<!-- Changes done --><item v-for="item in row" :key="item.id" :title="item.title" :isActive="activeIndex === item.id" #click.native="onItemClick(item.id)" />
</ul>
</div>
</div>
</script>
<script type="text/x-template" id="item-template">
<li class="item" :class="{ active: isActive }">{{ title }}</li>
</script>
<style>
.items-list {
display: flex;
}
</style>
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 have an object that will be modified on a click event, however it seems a refresh or clicking on another element is required for the object to actually update. What do I need to do so that the object is updated without a manual refresh or clicking on something else?
My code:
<template>
<div class="userTable">
<input type="text" v-model="query" placeholder="Search for a user" #focus="dimUsers()" #blur="undimUsers()" #keyup="selectedUser()">
<ul>
<li v-for="user in userList.users" :key="user.localized_name">
<img v-bind:src="user.portrait" class="userPortrait" :class="{'selectedUser': selectedUserPortrait.includes(user.portrait), 'dimmed': searching}" #click="loadUser(user)">
</li>
</ul>
</div>
</template>
....
props: {
userList
}
data: function () {
return {
userSelected: {
"name": '',
"portrait": '',
},
searching: false,
query: '',
selectedUserPortrait = []
}
}
methods: {
loadUser: function (user) {
this.userSelected = user
return;
}
dimUsers: function () {
this.searching = true
return;
}
undimUsers: function () {
this.searching = false,
this.selectedUserPortrait = []
this.query = ''
return;
},
selectedUser: function () {
this.selectedUserPortrait = [];
for (let i=0; i<userList.users.length; i++) {
if (this.userList.users[i].localized_name.toLowerCase().includes(this.query.toLowerCase())) {
this.selectedUserPortrait.push(this.userList.users[i].portrait)
} else {
this.selectedUserPortrait.splice(i, 1);
}
} return;
}
}
It's not entirely clear what you expect to see happen, but this code works as I expect. Does it work as you expect?
new Vue({
el: '#app',
data: {
userList: {
users: [{
portrait: 'https://via.placeholder.com/50?text=p1',
localized_name: 'one'
},
{
portrait: 'https://via.placeholder.com/50?text=p2',
localized_name: 'two'
},
{
portrait: 'https://via.placeholder.com/50?text=p3',
localized_name: 'three'
},
{
portrait: 'https://via.placeholder.com/50?text=p4',
localized_name: 'four'
},
{
portrait: 'https://via.placeholder.com/50?text=p5',
localized_name: 'five'
},
]
},
userSelected: {
"name": '',
"portrait": '',
},
searching: false,
query: ''
},
computed: {
selectedUserPortrait() {
return this.query ?
this.userList.users.filter((u) =>
u.localized_name.toLowerCase().includes(this.query.toLowerCase())
).map((u) => u.portrait) : [];
}
},
methods: {
loadUser: function(user) {
this.userSelected = user;
return;
},
dimUsers: function() {
this.searching = true
return;
},
undimUsers: function() {
this.searching = false;
this.query = '';
}
}
});
.selectedUser {
border: solid 2px red;
}
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<div id="app">
<input type="text" v-model="query" placeholder="Search for a user" #focus="dimUsers()" #blur="undimUsers()">
<ul>
<li v-for="user in userList.users" :key="user.localized_name">
<img v-bind:src="user.portrait" class="userPortrait" :class="{'selectedUser': selectedUserPortrait.includes(user.portrait), 'dimmed': searching}" #click="loadUser(user)">
</li>
</ul>
<div>{{userSelected.localized_name}}</div>
</div>
I want to add checkboxes to Vuejs Treeview. So I added a checkbox to the template as this code:
<script type="text/x-template" id="item-template">
<li>
<input type="checkbox" id="checkbox">
<span
:class="{bold: isFolder}"
#click="toggle"
#dblclick="changeType">
{{ model.name }}
<span v-if="isFolder">[{{ open ? '-' : '+' }}]</span>
</span>
<ul v-show="open" v-if="isFolder">
<item
class="item"
v-for="(model, index) in model.children"
:key="index"
:model="model">
</item>
</ul>
</li>
</script>
But I don't know how to link those checkboxes to a model like this example. Please help! Thank you very much!
I think the simplest way to do that is by using VueX.
The store has a common variable for all checkBoxes accessible from everywhere.
When you click on a checkbox, it update the store.
https://jsfiddle.net/u91mxc58/14/
const store = new Vuex.Store({
state: {
checkBoxes:[],
},
mutations: {
updateCheckBoxes(state, value) {
state.checkBoxes = value;
}
}
})
// demo data
var data = {
name: 'My Tree',
children: [
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
},
{ name: 'hello' },
{ name: 'wat' },
{
name: 'child folder',
children: [
{ name: 'hello' },
{ name: 'wat' }
]
}
]
}
]
}
// define the item component
Vue.component('item', {
template: '#item-template',
props: {
model: Object,
},
data: function () {
return {
open: false
}
},
computed: {
isFolder: function () {
return this.model.children &&
this.model.children.length
},
checkBoxes: {
// accesseur
get: function () {
return store.state.checkBoxes;
},
// mutateur
set: function (newValue) {
store.commit('updateCheckBoxes', newValue);
}
}
},
methods: {
toggle: function () {
if (this.isFolder) {
this.open = !this.open
}
},
changeType: function () {
if (!this.isFolder) {
Vue.set(this.model, 'children', [])
this.addChild()
this.open = true
}
},
addChild: function () {
this.model.children.push({
name: 'new stuff'
})
}
}
})
// boot up the demo
var demo = new Vue({
el: '#demo',
data: function() {
return {
treeData: data
};
},
computed: {
checkBoxes() {
return store.state.checkBoxes;
}
}
})
body {
font-family: Menlo, Consolas, monospace;
color: #444;
}
.item {
cursor: pointer;
}
.bold {
font-weight: bold;
}
ul {
padding-left: 1em;
line-height: 1.5em;
list-style-type: dot;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<!-- item template -->
<script type="text/x-template" id="item-template">
<li>
<input v-model="checkBoxes" type="checkbox" :value="model.name" id="checkbox">
<span
:class="{bold: isFolder}"
#click="toggle"
#dblclick="changeType">
{{ model.name }}
<span v-if="isFolder">[{{ open ? '-' : '+' }}]</span>
</span>
<ul v-show="open" v-if="isFolder">
<item
class="item"
v-for="(model, index) in model.children"
:key="index"
:model="model">
</item>
<li class="add" #click="addChild">+</li>
</ul>
</li>
</script>
<p>(You can double click on an item to turn it into a folder.)</p>
<!-- the demo root element -->
<ul id="demo">
<div>{{ checkBoxes }}</div>
<item
class="item"
:model="treeData">
</item>
</ul>
I am need to take acces to the model fields from the template of the item of a listview. Basically I need to replace the first name with the "valueToAccess" from viewModel. Some Body can help me here.
<div id="app"></div>
<script type="text/x-kendo-template" id="item-template">
#= name #
</script>
<script type="text/x-kendo-template" id="view-template">
<div data-role="listview"
data-bind="source: items"
data-template="item-template">
</div>
</script>
<script>
var viewModel = {
items: new kendo.data.DataSource({
data: [{ name: "item1" }, { name: "item2" }]
}),
valueToAccess: "index",
remove: function(e){
this.items.remove(e.data);
}
};
viewModel.items = new kendo.data.DataSource({
data: [{ name: "item1" }, { name: "item2" }]
});
var view = new kendo.View('view-template', { model: viewModel });
view.render("#app");
</script>
<div id="app"></div>
You can do it by using a dependent property.
<script type="text/x-kendo-template" id="item-template">
<a data-bind="attr: { href: href}, text: name"></a>
</script>
<script>
var viewModel = {
items: new kendo.data.DataSource({
data: [{ name: "item1" }, { name: "item2" }]
}),
valueToAccess: "index",
href: function(item) {
return this.get("valueToAccess") + "/" + item.name;
},
remove: function(e){
this.items.remove(e.data);
}
};
</script>
Here is a live demo: http://jsbin.com/naxiy/1/edit