Vuetify, v-for checkbox with search field. Strange behavior on the checkbox - vuejs2

I'm making a list of person to select with a search bar to find the person name. I'm using computed and filter to search the list. But there's strange behavior on my checklist. I don't know what happen. Please check the codepen link above. Try searching then delete the search.
https://codepen.io/rahmatfajar15/pen/OqPqRy?editors=1010
template:
<v-layout column fill-height>
<v-flex>
<v-text-field
v-model="pattern"
box
hide-details
label="Cari Peserta..."
prepend-inner-icon="search"
clear-icon="close"
clearable
/>
</v-flex>
<v-layout column>
<div
v-for="item in filteredPeserta"
>
<v-layout row class="text-xs-left">
<div class="xs2 justify-center align-center">
<v-checkbox
height="16"
v-model="tempPeserta"
:value="item.id"
/>
</div>
<v-layout xs10 column justify-center>
<pre class="body-2">{{ item.name }}</pre>
</v-layout>
</v-layout>
</div>
</v-layout>
</v-layout>
script:
new Vue({
el: '#app',
data: () => ({
pattern: '',
tempPeserta: [],
listPeserta: [
{
id: '1',
name: 'Agung'
},
{
id: '2',
name: 'Bucin'
},
{
id: '3',
name: 'Chandra'
},
{
id: '4',
name: 'Dedek'
},
{
id: '5',
name: 'Enok'
},
{
id: '6',
name: 'Fajar'
},
{
id: '7',
name: 'Galih'
},
{
id: '8',
name: 'Hayo'
},
{
id: '9',
name: 'Ilsa'
},
]
}),
computed: {
filteredPeserta () {
return this.listPeserta.filter(item => {
return item.name.toLowerCase().indexOf(this.pattern.toLowerCase()) > -1
})
}
}
})

You need to add key when using v-for because Vue will reuse list component (document)
<div
v-for="item in filteredPeserta"
:key="item.id"
>
....
</div>

Related

How can bind change of object data instantly in Vue.js?

<div
v-if="!item.editNickname"
#click="item.editNickname=true, item.tmpNickname=item.nickname"
>{{item.nickname}}</div>
<v-text-field
v-model="item.tmpNickname"
v-if="item.editNickname||!item.nickname"
outlined
dense
hide-details
single-line
v-on:keyup.enter="saveNickname(item)"
/>
Here is my code.
I want to edit nickname in data table.
If user click nickname(div), text field will show up.
But this code cannot bind instantly(Actually value is binded correct, but UI is not react).
Can I make UI react without other action?
=====================================================
+INFO
This code block is in 'v-data-table' which basic component of vuetify.
The item is an Object.
You can do as below, I'm thinking tmpNickname is not one of the property that you are binding to the data table. See below for the sample code.
You can find the working code here
Template Code:
<div id="app">
<v-app id="inspire">
<v-data-table
:headers="headers"
:items="desserts"
class="elevation-1"
>
<template v-slot:item.nickname="{ item }">
<div v-if="!item.editable" #click="item.editable = true; item['tmpnickname'] = item.nickname">{{ item.nickname }}</div>
<v-text-field
v-model="item['tmpnickname']"
v-if="item.editable"
outlined
dense
hide-details
single-line
v-on:keyup.enter="saveNickname(item)"
/>
</template>
</v-data-table>
</v-app>
</div>
Script Code:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
headers: [
{
text: 'Col 1',
value: 'name',
},
{ text: 'Nick name', value: 'nickname' }
],
desserts: [
{
name: 'Row 1',
nickname: 'Name 1',
editable: false
},
{
name: 'Row 2',
nickname: 'Name 2',
editable: false
},
{
name: 'Row 3',
nickname: 'Name 3',
editable: false
}
],
}
},
methods: {
saveNickname (item) {
item.editable = false;
item.nickname = item.tmpnickname;
}
},
})

Vuetify Autocomplete with slots, no autocomplete suggestion when typing

I'm trying to make a small tool where someone would fill in some data, this would be either a name or id and the field displays an autocomplete list. (The end result would contain 100+ results, an autocomplete function is needed.)
I've tried to use Vuetify's autocomplete, but I'm struggling to let it filter correctly.
I'm using the following code provided by Vuetify, without the Edit button (https://vuetifyjs.com/en/components/autocompletes#custom-filter-on-autocomplete) - and I was able to add in the ID and show it in the results with a scoped slot.
However, if you type something into the input field, it doesn't show any suggestions at all.
I've been looking at this for a few hours and I must be overlooking something. I emptied the slots, checked the method, changed the || and went back to them. I have no clue at this moment.
Codepen fiddle
HTML:
<div id="app">
<v-app id="inspire">
<v-card
class="overflow-hidden"
color="blue lighten-1"
dark
>
<v-toolbar
flat
color="blue"
>
<v-icon>mdi-account</v-icon>
<v-toolbar-title class="font-weight-light">Title</v-toolbar-title>
</v-toolbar>
<v-card-text>
<v-combobox
:items="states"
:filter="customFilter"
color="white"
label="State"
clearable
>
<template slot="selection" slot-scope="data">
{{ data.item.id }} - {{ data.item.abbr }} {{ data.item.name }}
</template>
<template slot="item" slot-scope="data">
{{ data.item.id }} - {{ data.item.abbr }} {{ data.item.name }}
</template>
</v-combobox>
</v-card-text>
</v-card>
</v-app>
</div>
Vue:
new Vue({
el: '#app',
vuetify: new Vuetify(),
data () {
return {
model: null,
states: [
{ name: 'Florida', abbr: 'FL', id: '1' },
{ name: 'Georgia', abbr: 'GA', id: '2' },
{ name: 'Nebraska', abbr: 'NE', id: '3' },
{ name: 'California', abbr: 'CA', id: '4' },
{ name: 'New York', abbr: 'NY', id: '5' },
],
}
},
methods: {
customFilter (item, queryText, itemText) {
const filterName = item.name.toLowerCase()
const filterAbbr = item.abbr.toLowerCase()
const filterId = item.id.toLowerCase()
const searchText = queryText.toLowerCase()
return
filterName.indexOf(searchText) > -1 ||
filterAbbr.indexOf(searchText) > -1 ||
filterId.indexOf(searchText) > -1
},
},
})
Just use a single line for the last return and it works
return filterName.indexOf(searchText) > -1 || filterAbbr.indexOf(searchText) > -1 || filterId.indexOf(searchText) > -1;
or
return (
filterName.indexOf(searchText) > -1 ||
filterAbbr.indexOf(searchText) > -1 ||
filterId.indexOf(searchText) > -1
)

Vue.Draggable not letting me move items between lists

Trying to follow this tutorial, but with bi-directional dragging between containers. Reducing the problem to the minimal set of code, I'm able to sort within a list but not between lists. I was under the impression from the documentation that setting both draggables to the same group name would enable it, but that doesn't seem to be the case.
So, what do I need to do in order to just allow items to be moved from one list to another? Here's the code I've tried (which, again, does perfectly for rearranging within the same list)
<template>
<v-container fill-height fluid grid-list-md mt-0 class='about'>
<v-layout column fill-height>
<h1>This is an about page</h1>
<v-layout row fill-height>
<v-flex xs4>
<draggable class='dragArea' v-model='peopleList'>
<div v-for='person in peopleList' :key='person.id' :options='{group: "people"}'>{{ person.name }}</div>
</draggable>
</v-flex>
<v-flex xs4>
<draggable class='dragArea' v-model='employeeList'>
<div v-for='person in employeeList' :key='person.id' :options='{group: "people"}'>{{ person.name }}</div>
</draggable>
</v-flex>
</v-layout>
</v-layout>
</v-container>
</template>
<script>
import draggable from 'vuedraggable'
export default {
name: 'About',
data () {
return {
employees: [{ id: 6, name: 'Pete' },
{ id: 7, name: 'Pat' }],
people: [
{ id: 1, name: 'Bob' },
{ id: 2, name: 'Mary' },
{ id: 3, name: 'Jane' },
{ id: 4, name: 'Alex' },
{ id: 5, name: 'Jim' }
]
}
},
components: { draggable },
computed: {
employeeList: {
get () {
return this.employees
},
set (value) {
this.employees = value
}
},
peopleList: {
get () {
return this.people
},
set (value) {
this.people = value
}
}
}
}
</script>
<style>
div.dragArea {
border: 1px solid black;
min-width: 100px;
}
</style>
The options parameter applies to the draggable component, not to the children of that element. If you add options to draggable it works as you expect.
<draggable class='dragArea' v-model='peopleList' :options='{group: "people"}'>
<div v-for='person in peopleList' :key='person.id'>{{ person.name }}</div>
</draggable>
The syntax changed in 2.20. You're supposed to use group="<name>" attribute now:
<draggable class="dragArea" v-model="peopleList" group="people">
<div v-for="person in peopleList" :key="person.id">{{ person.name }}</div>
</draggable>

I want to create dynamic fields using Vue.js and Vuetify

Here is my vuejs file, I want to create dynamic fields like text box, check box, radio button, drop down, text area etc. I have tried but I have got vue source code.
<template>
<v-container>
<v-layout>
<v-flex xs12 sm12>
<v-card>
<v-card-title primary-title>
<v-layout>
<v-flex xs12 sm6 md3 v-for="(item, i) in field_output" :key="i">
{{item.template}}
</v-flex>
</v-layout>
</v-card-title>
</v-card>
</v-flex>
</v-layout>
</v-container>
</template>
Here I have create fields array which contains the all fields which I need. Through create_forms() function I have create forms fields.
<script>
export default {
data() {
return {
fields: [{
type: 'text',
text: 'CSP Address',
default_value: '',
meta_id: 'csp_address'
},
{
type: 'text',
text: 'CSP Name',
default_value: '',
meta_id: 'csp_name'
},
{
type: 'radio',
text: 'CSP Gender',
default_value_one: 'male',
default_value_two: 'female',
meta_id: 'csp_gender'
},
{
type: 'check_box',
text: 'CSP Agree',
default_value: false,
meta_id: 'csp_aggree'
}
],
field_output:null
}
},
created: function(){
this.create_forms()
},
methods:{
create_forms: function(){
var field_output = [];
this.fields.forEach(function (item, key) {
var input_field;
switch(item.type){
case 'text':
input_field = '<v-text-field type="text" v-model="input_value.'+item.meta_id+'" label="'+item.text+'" outline></v-text-field>';
break;
case 'radio':
input_field = '<v-radio-group v-model="input_value.'+item.meta_id+'"><v-radio :label="'+item.default_value_one+'" :value="'+item.default_value_one+'"></v-radio><v-radio :label="'+item.default_value_two+'" :value="'+item.default_value_two+'"></v-radio></v-radio-group>';
break;
case 'check_box':
input_field = ' <v-checkbox :label="'+item.text+'" v-model="input_value.'+item.meta_id+'"></v-checkbox>';
break;
case 'select':
break;
case 'textarea':
break;
}
field_output.push({id: key+1, template:input_field});
})
this.field_output = field_output;
console.log(this.field_output);
}
}
}
</script>
My result is :
I need text field, radio button, check box etc. Not vue code. Please help me
I would suggest using VueJS <component/> and load required form field:
This is a small working example, you can change it to your needs.
Template:
<template>
<v-flex>
<component :is="item.type" :label="item.text" v-for="(item, i) in fields" :key="i" v-model="values[item.meta_id]">
<component v-if="item.children && item.children.length > 0" :is="children.type" :value="children.value" :label="children.text" v-for="(children, j) in item.children" :key="j"/>
</component>
{{ JSON.stringify(values) }}
</v-flex>
</template>
Change your fields array to:
<script>
export default {
data(){
return {
values: {
csp_address: 'default value',
csp_name: 'default value',
csp_gender: 'male',
csp_aggree: true
},
fields: [
{
type: 'v-text-field',
text: 'CSP Address',
meta_id: 'csp_address'
},
{
type: 'v-text-field',
text: 'CSP Name',
meta_id: 'csp_name'
},
{
type: 'v-radio-group',
text: 'CSP Gender',
children: [
{
type: 'v-radio',
value: 'male',
text: 'Male',
},
{
type: 'v-radio',
value: 'female',
text: 'Female',
}
],
meta_id: 'csp_gender'
},
{
type: 'v-checkbox',
text: 'CSP Agree',
meta_id: 'csp_aggree'
}
]
}
}
}
</script>
What you are doing right now is printing out a string which vuejs won't recogize as html.
As shown in the docs here: https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML
you can use the v-html directive to print out raw html:
<div v-html="{{ item.template }}"></div>

Vue js v-model different checkboxes

I'm a bit new with Vue Js. I'm trying to obtain the boolean value of each checkbox from a Vue component, but when I check one, the rest ones are checked as well, so I can check just one. I've try it with computed but no results.
<v-card>
<v-layout row wrap class="text-xs-center" v-for="ingredient in ingredients" :key="ingredient.id">
<v-layout column>
<v-flex xs6>
<v-checkbox color="light-blue lighten-2" v-bind:label="`${ingredient.name}`" v-model="checked" light></v-checkbox>
</v-flex>
</v-layout>
<v-layout column>
<v-flex xs6>
<v-subheader>{{ingredient.price}} €</v-subheader>
</v-flex>
</v-layout>
</v-layout>
</v-card>
export default {
data: () => ({
checked: [],
checked1: '',
ingredients: [{
id: 1,
name: "tomato",
price: 2
}, {
id: 2,
name: "Cheese",
price: 2.0
}, {
id: 3,
name: "Frankfurt",
price: 2.25
}, {
id: 4,
name: "Mushrooms",
price: 1.6
}, {
id: 5,
name: "Pepper",
price: 2.5
}, {
id: 1,
name: "Ham",
price: 2.75
}],
}),
computed: {
checked() {
return this.checked
}
}
}
Try setting a checked value on each ingredient item:
ingredients: [{
id: 1,
name: "tomato",
price: 2,
checked: false
}]
And then you can set the value on the checkbox in the for-loop like this:
<v-checkbox v-model="ingredient.checked"></v-checkbox>
Simply bind :id and :value to an array
<div v-for="item, i in items>
<input type="checkbox" :id="i" :value="i" v-model="checked" />
</div>
export default {
data() {
return: {
checked: [],
items: []
};
},
created() {
axios.get('my-data').then(resp => this.items = resp.data.items);
}
}