How to populate a Vuetify Select using data from axios - vue.js

I need to populate a Vuetify select, but there is a problem with it, my Get method returns data, but the vuetify select only show something like this:
The text shows valid data:
[ { "id": 1 }, { "id": 2 } ]
And to populate the Select i follow the documentatioin adding :items="entidades" and :item-text="entidades.id" and :item-value="entidades.id"
<v-select :items="entidades" :item-text="entidades.id" :item-value="entidades.id" single-line auto prepend-icon="group_work" label="Seleccionar Grupo"></v-select>
This is my code form script
`data() {
return(){
entidades: [{
id: ''
}],
}
}`
I already tried to put 0, but it's the same result.
My axios.get method.
axios.get('http://localhost:58209/api/GetEntidades', {
headers:{
"Authorization": "Bearer "+localStorage.getItem('token')
}
})
.then(response => {
console.log(response)
this.entidades = response.data;
})
.catch(error => {
console.log(error.response)
});
Thank you so much

item-text and item-value are the name of the properties each item will display and use as value, respectively. So use item-text="id" item-value="id":
<v-select :items="entidades" item-text="id" item-value="id" single-line auto prepend-icon="group_work" label="Seleccionar Grupo"></v-select>
Demo:
new Vue({
el: '#app',
data () {
return {
entidades: [ { "id": 1 }, { "id": 2 } ]
}
}
})
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'>
<link rel='stylesheet' href='https://unpkg.com/vuetify#1.0.10/dist/vuetify.min.css'>
<script src='https://unpkg.com/vue/dist/vue.js'></script>
<script src='https://unpkg.com/vuetify#1.0.10/dist/vuetify.min.js'></script>
<div id="app">
<v-app>
<v-container>
<v-select :items="entidades" item-text="id" item-value="id" single-line auto prepend-icon="group_work" label="Seleccionar Grupo"></v-select>
</v-container>
</v-app>
</div>

Related

Vue.js v-autocomplete v-model new data

<v-autocomplete v-if="first.title == 'host'"
:items="host"
v-model="selected_host"
item-value="host_n"
outlined
hide-details
dense
></v-autocomplete>
I'd like to input new text which is not included in items.
autocomplete is just suggestion to user.
But I can't input new data in v-autocomplete. Whenever I write new data, it was deleted.
You should use v-combobox (doc here) instead of v-autocomplete if you want the user to add its own value
If you want to deal with multiple values, you can use the multiple attributes and passing an array to the v-model instead of a string (or an object if you use the return-object param)
new Vue({
el: '#app',
vuetify: new Vuetify(),
computed: {
tagsSorted() {
return this.tags.sort()
}
},
data: () => ({
host: [{
host_n: 'Foo',
},
{
host_n: 'Bar',
}
],
first: {
title: 'host'
},
selected_host: ''
}),
methods: {
sendData() {
console.log(this.selected_host)
}
}
})
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#2.6.4/dist/vuetify.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify#2.6.4/dist/vuetify.min.css" />
<div id="app" data-app>
<v-combobox v-if="first.title == 'host'" :items="host" v-model="selected_host" item-value="host_n" item-text="host_n" outlined hide-details dense></v-combobox>
<v-btn #click="sendData">Send data</v-btn>
</div>

Vue - how can i add a button to each row in a Vuetify datatable?

I'm new to Vue and i'm dealing with datatables. I'm using Vuetify's datatables to create a component that, on page load, sends a request to my backend, receives some data and shows that data on a datatable.
This is my current code:
<template>
<v-data-table
:headers="headers"
:items="balances"
:items-per-page="5"
class="elevation-1"
></v-data-table>
</template>
<script>
export default {
data() {
return {
search: '',
headers: [
{ text: 'Asset', value: 'symbol' },
{ text: 'Amount', value: 'amount' },
],
balances: [],
}
},
mounted() {
this.fetchData()
},
methods: {
fetchData() {
fetch('MYURL')
.then(response => response.json())
.then(data => {
this.balances = data;
})
}
}
}
</script>
The problem i'm facing now is adding a button to each row in the table, and this button should send a request to my backend with that row's data, so i need to add a button that, when clicked, can fetch the row's data. Is there any way to do that? I tried looking into Vuetify's docs but i didn't found much about a task like this one.
You can add a new column, set value to action for example, and add a slot in the table as follows:
new Vue({
el:"#app",
vuetify: new Vuetify(),
data() {
return {
search: '',
headers: [
{ text: 'Asset', value: 'symbol' },
{ text: 'Amount', value: 'amount' },
{ text: 'Send', value: 'action' }
],
balances: [
{ symbol: "$", amount: 100 },
{ symbol: "$", amount: 200 },
],
}
},
methods: {
sendRequest(rowData) {
console.log(rowData)
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script><link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<v-app id="app">
<v-data-table
:headers="headers"
:items="balances"
:items-per-page="5"
class="elevation-1"
>
<template v-slot:item.action="{ item }">
<v-btn #click="sendRequest(item)">
Send
</v-btn>
</template>
</v-data-table>
</v-app>

setting up v-autocomplete with search function

Trying to setup v-autocomplete, without a watcher, the flow would be:
Type a string, value is accepted by function
Function searches api for string and returns a list
List is put into "entries"
Computed property "tagsFound" is reevaluated.
"tagsFound" are displayed (since they are :items)
The main difference between the docs here and my code is my attempt to do this without a watcher rather with a simple function.
Relevant code:
<v-autocomplete
v-model="newTag"
:items="tagsFound"
:loading="loading"
:search-input.sync="search"
color="white"
hide-no-data
hide-selected
:placeholder="$t('search_terms.new_tag')"
></v-autocomplete>
...
data() {
return {
newTag: '',
entries: [],
....
methods: {
...
async search(term){
this.query.term = term
this.entries = await this.searchTerms(this.query)
},
...
computed: {
tagsFound(){
return this.entries
}
}
Expected behavior is search for the term typed and display the results as a dropdown.
Actual behavior is that it does not search and therefore does not display anything.
The sync modifier effectively makes a prop behave like v-model, so just like with v-model there's a prop and an event. The value needs to be a property, not a method, so :search-input.sync="search" doesn't make sense if search is a method.
The tagsFound computed property in your example isn't really doing anything. If you're just going to return entries you might as well just use entries directly in your template.
Not sure why you would want to do this without a watch but it can be done, either by splitting search-input.sync into a prop/event pair or by using a computed property with a getter and setter. The example below uses the latter approach.
function fakeServer (search) {
return new Promise(resolve => {
setTimeout(() => {
resolve([
'Red', 'Yellow', 'Green', 'Brown', 'Blue', 'Pink', 'Black'
].filter(c => c.toLowerCase().includes(search.toLowerCase())))
}, 1000)
})
}
new Vue({
el: '#app',
data () {
return {
newTag: '',
entries: [],
queryTerm: ''
}
},
computed: {
search: {
get () {
return this.queryTerm
},
set (searchInput) {
if (this.queryTerm !== searchInput) {
this.queryTerm = searchInput
this.loadEntries()
}
}
}
},
created () {
this.loadEntries()
},
methods: {
async loadEntries () {
this.entries = await fakeServer(this.queryTerm || '')
}
}
})
<link href="https://unpkg.com/vuetify#1.5.16/dist/vuetify.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons" rel="stylesheet">
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vuetify#1.5.16/dist/vuetify.js"></script>
<div id="app">
<v-app>
<v-autocomplete
v-model="newTag"
:items="entries"
:search-input.sync="search"
></v-autocomplete>
</v-app>
</div>
In this part, you bind search-input to an async method, this is wrong. You need to bind search-input to a data field and create a watch over it.
<v-autocomplete
:search-input.sync="search"
></v-autocomplete>
Define your component like below:
data: function(){
return {
newTag: '',
entries: [],
searchInput: null
}
},
watch: {
searchInput(val){
this.entries = await this.searchTerms(val)
}
}
And v-autocomplete template:
<v-autocomplete
v-model="newTag"
:items="tagsFound"
:loading="loading"
:search-input.sync="searchInput"
color="white"
hide-no-data
hide-selected
:placeholder="$t('search_terms.new_tag')"
></v-autocomplete>
This is a working example I created on CodePen

Vue v-for list does not update after data changed

The idea is simple:
The Vue instance loads groups from an API.
This groups are shown using a v-for syntax.
The groupdata is formatted properly, and added to app.groups using .push function, which should update the v-for list.
However, the v-for list will not update.
When I change v-for="group in groups" (loaded externally) to v-for="group in people" (already in the app), it does give output.
HTML
<div id="app" class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Realtime Socket Chat</div>
<div class="panel-body" v-if="dataReady" v-for="group in groups"> #{{ group.name }}
<a v-bind:href="group.link" class="pull-right">
<div class="btn btn-xs btn-primary">
Join
</div>
</a>
</div>
</div>
</div>
</div>
Vue
var app = new Vue({
el: "#app",
data: {
groups: [],
people: [{name: 'hi'}, {name: 'lol'}]
},
mounted: function() {
this.load()
},
methods: {
load: function() {
axios.get('http://example.com/groups')
.then(function (response) {
console.log(response.data.groups);
response.data.groups.forEach(function(group) {
app.groups.push(group);
});
// app.groups.forEach(function (group) {
// group.link = '/g/' + group.id + '/join';
// });
// console.log(response.data.groups);
console.log(this.groups); //outputs [{...}, {...}] so this.groups is good
})
.catch(function (error) {
this.errors.push(error);
console.log(error);
})
}
}
});
API
{
"groups": [
{
"id": 1,
"name": "Photography Chat",
"created_at": "2017-11-26 08:50:16",
"updated_at": "2017-11-26 08:50:16"
},
{
"id": 2,
"name": "Media Chat",
"created_at": "2017-11-26 08:50:16",
"updated_at": "2017-11-26 08:50:16"
}
]
}
It seems like app is undefined when your load function is executed. So, using ES6 arrow function syntax, your load function should look like this:
load: function() {
axios.get('http://example.com/groups')
.then(response => {
let groups = response.data.groups || []
groups.forEach(group => {
this.groups.push(group)
})
console.log(this.groups)
})
.catch(error => {
this.errors.push(error)
console.log(error)
})
}
A fact I left out in the question (because I assumed it would not matter) was that I am working within the Laravel framework, Laravel automatically imports Vuejs within main.js. Which does not play nice when Vue is loaded in additionally. I removed main.js and it works.

on-change doesn't work on v-select

I tried to use a v-select who display all countries. so i did :
<v-select on-change="updateCountryId" label="country_name" :options="countries" ></v-select>
it works great and display my countries but the function updateCountryId doesn't seems to work
methods: {
updateCountryId: function() {
alert('ok');
}
}
but i never see the ok
to import vue-select I did :
<script src="/js/vue-select/vue-select.js"> </script>
i use it in a twig file so in my vue-select.js i rewrite what i found on https://unpkg.com/vue-select#1.3.3 but replace the {{ }} by <% %>
ps : i already tried v-on:change, #change and onChange
and my code looks like that (i skip thing i judge useless)
<div id="General">
<div class="form-group">
<label>Pays :</label>
<v-select onChange="updateCountryId" label="country_name" :options="countries" ></v-select>
</div>
.
.
.
<script src="/js/vue-select/vue-select.js"> </script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/vue/1.0.13/vue.min.js"></script>
<script>
Vue.config.delimiters = ['<%', '%>'];
Vue.component('v-select', VueSelect.VueSelect);
var vm = new Vue({
el: "#General",
data: {
countries: [],
},
filters: {
},
methods: {
updateCountryId: function () {
console.log('ok');
alert('ok');
},`
You are missing the colon :
Vue.component('v-select', VueSelect.VueSelect);
new Vue({
el: '#app',
data: {
options: ['one', 'two', 'three'],
selected: ''
},
methods: {
updateCountryId: function() {
alert('ok');
}
}
});
<script src="https://unpkg.com/vue#latest"></script>
<!-- use the latest release -->
<script src="https://unpkg.com/vue-select#latest"></script>
<div id="app">
<v-select :on-change="updateCountryId" label="country_name" :options="options" :searchable="false" ></v-select>
</div>
Update
you need to use unpkg.com/vue-select#2.0.0 because version 1 is not compatible with the current version of Vuejs
Ok, this was really causing me some headache, it seems it has changed again on version 3. Per the documentation (https://vue-select.org/guide/upgrading.html#index-prop-replaced-with-reduce), they removed these 3 functions: onChange, onInput, onSearch in favor of using an event: #input
export default {
name: 'app',
methods: {
changedValue: function() {
alert("A new value was selected");
}
}
}
<v-select
options: ['one', 'two', 'three']
selected: ''
#input="changedValue" >
</v-select>
you can do this
<v-select :options="etat_nip" v-model="etat_nip_selected"></v-select>
and add the v-model "etat_nip_selected " in watch like this
watch:{
'etat_nip_selected' : function (val, oldval) {
console.log(val);
}
},
for more informations https://v2.vuejs.org/v2/guide/computed.html#Watchers
Vue.component('v-select', VueSelect.VueSelect);
new Vue({
el: '#app',
data: {
options: ['one', 'two', 'three'],
selected: ''
},
methods: {
updateCountryId: function() {
alert('ok');
}
}
});
<script src="https://unpkg.com/vue#latest"></script>
<!-- use the latest release -->
<script src="https://unpkg.com/vue-select#latest"></script>
<div id="app">
<v-select :on-change="updateCountryId" label="country_name" :options="options" :searchable="false" ></v-select>
</div>
It worked when I use #input not #change