I created a simple component
<template>
<div class="MoneyInput1 col-grow block">
<div class="block text-left q-py-md">
<label class="label-1">
{{ props.jLabel }}
</label>
</div>
<q-field
:model-value="props.modelValue"
borderless
#update:modelValue="e => {$emit('update:modelValue', e)}"
>
{{ props.modelValue }}
<template v-slot:control="{ id, emitValue }">
<input
:id="id"
v-money="moneyFormatForDirective"
class="input-1 money-input basis-medium"
model-value="modelValue"
#change.self="e => emitValue(e.target.value)"
>
</template>
</q-field>
</div>
</template>
with the moneyFormat as the following
const moneyFormatForDirective = {
decimal: ',',
thousands: '.',
prefix: '$ ',
precision: 2,
masked: false,
};
The problem is that it triggers two updates, one setting the value from the parent, which is sent with v-model. The following sets it to $0,00
I saw that it could be possible to be done with v-model.lazy, but with the #change I have no idea.
I'm using buefy to create a table with input filters in columns.
This is what it looks like:
<b-table
:data="cars"
:sticky-header="true"
:selected.sync="selected"
>
<template slot-scope="props">
<template v-for="column in columns">
<b-table-column :key="column.id" v-bind="column">
<template
v-if="column.searchable"
slot="searchable"
slot-scope="props"
>
<b-input
v-model="props.filters[props.column.field]"
placeholder="Search..."
icon="magnify"
size="is-small"
/>
</template>
{{ props.row[column.field] }}
</b-table-column>
</template>
</template>
</b-table>
...
...
data () {
return {
selected: null,
columns: [
{
field: 'constructor',
label: 'Constructor',
searchable: true
},
....
]
}
I would like to be able to clear the searched fields.
Any suggestions to achieve this please?
Your b-input is bound to props.filters[props.column.field], so it means that you should be able to add an icon to reset this value:
<b-input
v-model="props.filters[props.column.field]"
...
icon-right="close-circle"
icon-right-clickable
#icon-right-click="props.filters[props.column.field] = ''"
>
Please let me know if that works.
I'm starting to learn vue js and currently implementing a basic crud application. I successfully display 1 record in the table but having a problem when the record count is 2 or more.
I used vuesax serverside table to render the data and here's my code for the template
<vs-table
v-model="selected"
pagination
max-items="10"
search
:data="examiner">
<template slot="header">
<div class="d-flex align-items-center justify-content-between w-100 add-account">
<h3>
Examiner List
</h3>
</div>
</template>
<template slot="thead">
<vs-th sort-key="email">
Fullname
</vs-th>
<vs-th sort-key="Username">
Address
</vs-th>
<vs-th sort-key="User Role">
Email
</vs-th>
<vs-th sort-key="action">
Action
</vs-th>
</template>
<template slot-scope="{data}">
<vs-tr :data="row" :key="indextr" v-for="(row, indextr) in data" >
<vs-td :data="data[indextr].firstname">
{{ data[indextr].firstname }} {{ data[indextr].lastname }}
</vs-td>
<vs-td :data="data[indextr].address">
{{ data[indextr].address }}
</vs-td>
<vs-td :data="data[indextr].email">
{{data[indextr].email}}
</vs-td>
<vs-td>
<div class="d-flex">
<vs-button class="mr-1" color="primary" data-placement="top" data-toggle="tooltip"
title="Edit Examiner"
#click="editUser(row)"
vs-type="border" size="small" icon="edit"/>
<vs-button class="mr-1" color="danger" data-placement="top" data-toggle="tooltip"
title="Delete Examiner"
vs-type="border" size="small" icon="delete"/>
</div>
</vs-td>
</vs-tr>
</template>
</vs-table>
Here's my code for the script
<script>
import axios from "../../axios";
export default {
name: "examiner",
data() {
return {
host: window.location.host,
edit: false,
examiner: [],
selected: []
}
},
mounted() {
this.fetchUsers()
console.log(this.examiner)
},
methods: {
fetchUsers() {
axios.get('../api/getExaminer')
.then(response => {
this.examiner = response.data
})
.catch(error => console.log(error))
},
editUser(row) {
this.edit = true;
console.log(row)
}
}
}
</script>
Currently whenever I'm trying to load a data I'm receiving this error
I've just had this issue. it appears that if the :data prop is null or not iterable it will show this error.
In my case, the data prop became at some point null. for you I suggest the following:
First, use a computed value for data prop that returns an empty array in case there is an error.
make sure that your response.data is really an array or iterable object
I want to pass the data from b-card component to multiselect-vue and use it with tag/Input event
this is my multiselect component
<multiselect
class="display-controls"
track-by="id"
:value="value"
:multiple="isMultiple"
:placeholder="placeholder"
:options="options"
:options-limit="20"
:internal-search="internalSearch"
:selectLabel="$t('selectLabel')"
:taggable="isTaggable"
:customLabel="$utils.handleCustomLabel"
:max="handleMax"
:tagPlaceholder="$t('msTagPlaceholder')"
:loading="isSearching"
#input="handleInput"
#search-change="handleSearchChange"
#close="handleClose"
#remove="handleTagPlaceholders"
#tag="handleTag"
#open="$utils.msHandleOpen"
open-direction="bottom"
:showLabels="false"
>
This is my b-card that contain option that i want to pass the data
<b-card id="result-modal" align="left" #click="handleFormResultClick(entity.name || entity.title)" v-for="entity in options" :key="entity.id" :title="entity.name || entity.title" no-body class="overflow-hidden" style="max-width: 100%; border: none; cursor: pointer">
<!-- Option for Book -->
<b-row v-if="isBook" align-v="center" no-gutters>
<b-col v-if="languageComponent === 'En'" align-self="center" md="12">
<b-card-body class="card-list" style="padding-right: 0; padding-left: 0">
<b-card-text v-if="entity.title_en" id="list-modal">
<span v-html="highlightChar(entity.title_en)"></span>
<b-card-text v-if="entity.primary_publisher.name_en" class="list-in-indo">
Published by : {{ entity.primary_publisher.name_en }} in {{ entity.year_published }}
</b-card-text>
<b-card-text v-else class="list-in-indo">
Published by : {{ entity.primary_publisher.name }} in {{ entity.year_published }}
</b-card-text>
</b-card-text>
<b-card-text v-else-if="!entity.title_en" id="list-modal">
<span v-html="highlightChar(entity.title)"></span>
<b-card-text v-if="entity.primary_publisher.name_en" class="list-in-indo">
Published by : {{ entity.primary_publisher.name_en }} in {{ entity.year_published }}
</b-card-text>
<b-card-text v-else class="list-in-indo">
Published by : {{ entity.primary_publisher.name }} in {{ entity.year_published }}
</b-card-text>
</b-card-text>
</b-card-body>
</b-col>
<b-col v-if="languageComponent === 'Id'" align-self="center" md="12">
<b-card-body class="card-list" style="padding-right: 0; padding-left: 0">
<b-card-text v-if="entity.title_ind" id="list-modal">
<span v-html="highlightChar(entity.title_ind)"></span>
<b-card-text v-if="entity.primary_publisher.name_ind" class="list-in-indo">
Penerbit : {{ entity.primary_publisher.name_ind }}, pada {{ entity.year_published }}
</b-card-text>
<b-card-text v-else class="list-in-indo">
Penerbit : {{ entity.primary_publisher.name }}, pada {{ entity.year_published }}
</b-card-text>
</b-card-text>
<b-card-text v-else-if="!entity.title_ind" id="list-modal">
<span v-html="highlightChar(entity.title)"></span>
<b-card-text v-if="entity.primary_publisher.name_ind" class="list-in-indo">
Penerbit : {{ entity.primary_publisher.name_ind }}, pada {{ entity.year_published }}
</b-card-text>
<b-card-text v-else class="list-in-indo">
Penerbit : {{ entity.primary_publisher.name }}, pada {{ entity.year_published }}
</b-card-text>
</b-card-text>
</b-card-body>
</b-col>
</b-row>
</b-card>
This is what i've tried for Input and Tag to choose from the multiselect list, and handleFormResultClick method to choose the query from b-card and pass it into the multiselect component
handleInput (query) {
this.$emit('input', query)
this.$emit('selected', query)
console.log(query)
},
handleTag (query) {
const obj = {
id: `${this.model.charAt(0)}_${this.$utils.genRandomString()}`,
isCustom: true,
}
const title = _.startCase(query)
if (this.model === 'or' || this.model === 'conference' || this.model === 'organisation') {
obj.name = title
} else {
obj.title = title
}
if (this.isMultiple) {
const inputValMulti = this.value.push(obj)
this.searchQuery = ''
console.log(inputValMulti)
} else {
const inputValSolo = this.handleInput(obj)
this.searchQuery = ''
console.log(inputValSolo)
}
},
handleFormResultClick (query) {
const searchEntitySubmit = query
clearTimeout()
setTimeout(() => {
this.$emit('selected', query)
this.taggingSubmit = searchEntitySubmit
this.handleTag(value)
console.log(value)
}, 100)
this.showModalEntityResult = false
},
For some context the main function (handleFormResultClick ) is designed for
get the value from b-card data, and
pass it into the multiselect (whether it's single or multiple tag
How can i achieve that?
Thanks for the help!
You can pass the data either through vuex or through eventBus. You didn't show logic for your vuex strore, but you showed emits, so I'll show the eventBus logic. I have skipped any data transformation logic, I show just how you can pass the data.
In your main.js file you need to declare your eventBus. it must be declared before the Vue app is declared.
export const eventBus = new Vue(); // this must come before creating Vue app
new Vue({
el: '#app',
render: h => h(App)
})
In both your components you need to import the eventBus:
import {eventBus} from '<path to main.js>'
In the b-card component you emit the data in a method of your choosing, I used handleFormResultClick for this example:
handleFormResultClick () {
eventBus.$emit('selected', query) // where query is the data you want to pass
}
In the multiselect component you need to set up a listener for your event using created lifecycle hook. The $on method takes as a parameter a callbcak function where you have access to the data passed from the other component and can process them there:
created() {
eventBus.$on('selected', (query) => {
// process your query data in this callback function
})
}
I know that in VueJS I can loop through an array:
<span v-for="(element, index) in list">{{ element }}</span>
But what if I wanted a list that is comma separated? For example, if list = ["alice", "bob", "chuck"], then the above would output:
<span>alice</span><span>bob</span><span>chuck</span>
What I want, though, is:
<span>alice</span>, <span>bob</span>, <span>chuck</span>
Is this possible?
If all you care about is comma separation, use Javascript's built-in join method:
{{ list.join(', ') }}
For arrays of objects, you could do something like this:
{{ list.map(entry => entry.title).join(', ') }}
You can use conditional rendering to hide last , like following:
var demo = new Vue({
el: '#demo',
data: function() {
return {
lists: ['Vue', 'Angular', 'React']
};
}
})
<script src="https://vuejs.org/js/vue.min.js"></script>
<div id="demo">
<span v-for="(list, index) in lists">
<span>{{list}}</span><span v-if="index+1 < lists.length">, </span>
</span>
</div>
You could do it using a v-if attribute with a condition over the first argument, avoiding the usage of .length:
var app = new Vue({
el: '#app',
data: {
list: ['john', 'fred', 'harry']
}
})
<script src="https://vuejs.org/js/vue.min.js"></script><div id="app">
<span v-for="(element, index) in list">
<span v-if="index != 0">, </span><span>{{ element }}</span>
</span>
</div>
What I ended up doing instead was:
<span v-for="element in list" class="item">
<span>{{ element }}</span>
</span>
And in CSS:
.item + .item:before {
content: ", ";
}
Solution using "template"
<template v-for="(element, index) in list">
<span>{{element}}</span><template v-if="index + 1 < list.length">, </template>
</template>
If you wanted to do it the JS way, you can just do a computed property; you could even continue the span method.
computed {
listCommaSeparated () { return this.list.join(', '); },
listCommaSpans () { return '<span>' + this.list.join('</span><span>') + '</span>'; },
},
This would definitely be the preferred way from a rendering performance standpoint.
Just adding another alternative which I prefer to use:
<span v-for="(item, index) in list">
{{ item }}{{ (index+1 < list.length) ? ', ' : '' }}
</span>
My component:
<template>
<ul v-if="model.length">
<li v-for="item in model">{{item}}</li>
</ul>
</template>
<style scoped>
ul {
list-style: none;
}
li {
display: inline-block;
}
li:not(:last-child)::after {
content: ", ";
}
</style>
<script>
export default {
props: ['model']
};
</script>
Its possible sample
<span v-for="(item,i) in items">
{{(item !='' && i !=0) ? ',' : ''}} {{item.title}}
</span>
If you do want control over how the dom looks (e.g. actually want to achieve the dom structure that you asked about), you can create a functional component like so:
<script>
// RenderList.vue
export default {
functional: true,
render(createElement, context) {
// Read the list of entries by accessing the prop "list"
const listEntries = context.props.list;
// Return a custom list of elements for each list entry.
// Only return a `,` if it's not the last entry.
return listEntries.map((listElement, idx) => {
return [
createElement("span", listElement),
idx < listEntries.length - 1 ? ", " : "",
];
});
},
};
</script>
You would use this component like so:
<template>
<RenderList :list="['alice', 'bob', 'chuck']" />
</template>
May I suggest using i > 0 as check?
I've wrapped the separator so that {{ ' ' }} can be used for just having a space and avoiding span treated as being empty.
<span
v-for="(item, i) in list"
:key="i">
<span v-if="i>0">{{ ', ' }}</span>
<span class="text-nowrap">{{ item }}</span>
</span>
or
<span
v-for="(item, i) in list"
:key="i">
<!-- if not wrapped in a span will leave a space before the comma -->
<span>{{ (i > 0 ? ', ' : '') }}</span>
<span class="text-nowrap">{{ item }}</span>
</span>
There are different views where using :after or :before to have a comma is not a good idea with respect to browser not handling it as a string when the window is resized.
If we try to use conditional operator in each iteration to check whether it is the first or the last element, it would be an overhead if we have large number of items. Also the conditions will be re-evaluated whenever we have change detection.
To overcome these 2 things, we can enclose the comma in a separate element and hide it using CSS :last-child selector as
<template v-for="item in list">
<span class="item">
{{item}}
<span class="comma">
,
</span>
</span>
</template>
and in CSS
.item:last-child .comma {
display: none;
}