How to load Bootstrap-vue "b-table" row data dynamically using "_showDetails"? - javascript

I have bootstrap-vue "b-table" used in my Vue page. Each row has an "view-details" button, that shows additional information about the selected row. I was looking for examples that can send request to backend when user clicks for view-details, that expands the row and shows details retrieved from backend. The "_showDetails" option from bootstrap-vue table seems limited as the examples all use the data that was already loaded along with the main tableland using this way would overload the page as my data for each row is too big.
Are there any examples or even other libs that support such functionality?

You can do this with bootstrap-vue without any problems.
Create a method that gets called when you click your "view details" button, this method will call your backend and insert the data onto your item. Once the data has been retrieved you set _showDetails to true on the item, which will open the details.
You could also open it immediately and show a loading message while the data is retrieved, that's up to you.
new Vue({
el: '#app',
created() {
// Get initial data
fetch('https://reqres.in/api/users')
.then(response => response.json())
.then(json =>
/* Map and use only some of the data for the example */
this.items = json.data
.map(user => {
return {
id: user.id,
first_name: user.first_name,
last_name: user.last_name
}
}))
},
data() {
return {
items: [],
fields: ['id', 'first_name', 'last_name', {
key: 'actions',
label: ''
}]
}
},
methods: {
toggleDetails(item) {
if (item._showDetails) { // if details are open, close them
item._showDetails = false
} else if (item.details) { // if details already exists, show the details
this.$set(item, '_showDetails', true)
} else {
fetch(`https://reqres.in/api/users/${item.id}`)
.then(response => response.json())
.then(json => {
const user = json.data;
item.details = {
email: user.email,
avatar: user.avatar
}
this.$set(item, '_showDetails', true)
})
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.5.0/dist/bootstrap-vue.min.js"></script>
<link href="https://unpkg.com/bootstrap-vue#2.5.0/dist/bootstrap-vue.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap#4.3.1/dist/css/bootstrap.min.css" rel="stylesheet" />
<div id="app">
<b-container>
<b-table :items="items" :fields="fields">
<template v-slot:cell(actions)="{ item }">
<b-btn #click="toggleDetails(item)">
Show details
</b-btn>
</template>
<template v-slot:row-details="{ item : { details: { email, avatar }}}">
<b-card>
<b-img :src="avatar" fluid></b-img>
{{ email }}
</b-card>
</template>
</b-table>
</b-container>
</div>

Related

Can't access sub-object in Vue JS 3

I'm pretty new in VueJS and am stuck on the following problem:
I have a template in which a click on a button loads a new template through router.push and also sends an ID as data along.
The template:
<template>
<div>
{{ content.description }} // Works fine
{{ content.subobject.logo }} // Logo not found
</div>
</template>
In the new template that is being loaded I have the following function for saving the received ID into data:
created: function() {
this.ID = this.$route.params.data.toString()
},
then I have a function in methods which uses this ID to get data via axios/get:
methods: {
getContent: function() {
axios.get("https://api-url.com/" + this.ID)
.then((response) => {
this.content = response.data.data
console.log(response);
}).catch(error => {
console.log("ERRR:: ", error.response.data)
});
}
},
this function is called in mounted:
mounted: function() {
this.getContent()
}
My data function:
data: function() {
return {
ID: '',
content: [] as any
}
The data that is being returned by the API looks something like this:
title: "this is the title"
description: "Lorem Ipsum"
subobject: {
logo: "Logo URL"
}
When i use {{ content.title }} or {{ content.description }} in my template it shows up fine. As soon as I use {{ content.subobject.logo }} I'll get an error "logo" not found.
The funny thing is, when I have the template opend up and add the {{ content.subobject.logo }} after the page has loaded, save it, and it hot-reloads, it shows up fine?!
It seems like the data is not "available" on first load - but how can that be, if {{ content.title }} works fine?
Thanks a lot for any ideas!
The data is initially not available which means that content is still without inner field values, in order to avoid that add a conditional rendering like :
<div v-if="content.subobject">{{ content.subobject.logo }}</div>
you could also do :
data: function() {
return {
ID: '',
content: null
}
}
<template>
<template v-if="content">
<div >{{ content.subobject.logo }}</div>
<div >{{ content.title }}</div>
</template>
</template>

Change autocomplete selected item programmatically in Vue

I am not advance in Vue, suppose we have :
<v-autocomplete v-model="defaultUser"
:hint="`User: ${defaultUser.username}`"
:items="users"
:item-text="item =>`${item.firstName} - ${item.lastName}`"
item-value="userId"
label="Related user"
persistent-hint
return-object
dense
single-line outlined
:filter="userFilter"></v-autocomplete>
and data :
data: () => ({
users: [],
defaultUser: { userId: 0, username: 'select user', firstName: '', lastName: '' },
.....
by below snipped code nothing happened in UI, in the other words I want to change the selected item by code but nothing happened:
axios.get('api/user/relatedusers')
.then(response => {
if (response.status === 200 && response.data.id !== 0) {
this.defaultUser.userId = response.data.relatedId;//Here is nothing happened
}
}).catch(err => {
});
why this does not work if every variables are under Vue control, I mean bind and observable.
It seems that you should find a user by id and then assign him to this.defaultUser:
this.defaultUser = this.users.find(x => x.userId === response.data.relatedId)

Pull refresh does not update the list

My card does not get the latest data from firestore even with pull refresh implemented in quasar
<q-pull-to-refresh #refresh="refresh">
<q-card
class="q-ma-md"
bordered
v-for="announcement in announcements"
:key="announcement.key"
>
<q-card-section>
<div class="text-h6">{{announcement.TITLE}}</div>
<div class="text-subtitle2">{{announcement.CONTENT}}</div>
</q-card-section>
</q-card>
</q-pull-to-refresh>
here is my script and methods
data() {
return {
announcements: [],
};
},
//methods
retrieveAnnouncements() {
firebase
.firestore()
.collection("announcement")
.get()
.then(snapShot => {
snapShot.forEach(element => {
const { TITLE, CONTENT, AUTHOR } = element.data();
//add retrieved data in announcement
this.announcements.push({
key: element.id,
TITLE,
CONTENT,
AUTHOR
});
});
});
},
here is my refresh method that tries to update the card of the current page
refresh(done) {
setTimeout(() => {
(this.announcements = null), done();
}, 1000);
},
created() {
this.retrieveAnnouncements();
}
Does your refresh function call retrieveAnnouncements?
It looks like it's only called on created

Vuejs not updating list but updating obect

I am learning Vuejs and I am stuck. Why can I see the messages get added to the object (in Chrome Vue debugger) yet it is not added to the div that contains the list?
My Vue Component:
<template>
<div id="round-status-message" class="round-status-message">
<div class="row">
<div class="col-xs-12" v-for="sysmessage in sysmessages" v-html="sysmessage.message"></div>
</div>
</div>
</template>
<script>
export default {
props: ['sysmessages'],
methods: {
scrollToTop () {
this.$el.scrollTop = 0
}
}
};
</script>
My Vue instance:
$(document).ready(function()
{
Vue.component('chat-system', require('../components/chat-system.vue'));
var chatSystem = new Vue({
el: '#system-chat',
data: function () {
return {
sysmessages: []
};
},
created() {
this.fetchMessages();
Echo.private(sys_channel)
.listen('SystemMessageSent', (e) => {
this.sysmessages.unshift({
sysmessage: e.message.message,
});
this.processMessage(e);
});
},
methods: {
fetchMessages() {
axios.get(sys_get_route)
.then(response => {
this.sysmessages = response.data;
});
},
processMessage(message) {
this.$nextTick(() => {
this.$refs.sysmessages.scrollToTop();
});
// updateGame();
}
}
});
});
My template call in HTML:
<div id="system-chat">
<chat-system ref="sysmessages" v-on:systemmessagesent="processMessage" :sysmessages="sysmessages" :player="{{ Auth::user() }}"></chat-system>
</div>
There are no compile or run time errors and I can see records added to the props in the vue chrome tool. I can also see empty HTML elements added to the div.
What have I missed?
UPDATE: My record structures:
response.data is an array of objects, each like this:
{"data":[
{"id":100,
"progress_id":5,
"message":"start message",
"action":"welcome"
},
{"id"....
e.message.message contains the text message entry, so just a string.
I am trying to access the message variable in each object during the fetchMessages method.
You're adding objects with sysmessage as the property.
this.sysmessages.unshift({
sysmessage: e.message.message,
});
But you are trying to view
v-for="sysmessage in sysmessages" v-html="sysmessage.message"
Based on your update, the code should be:
this.sysmessages.unshift({
message: e.message.message,
});
And you can leave the template as
v-html="sysmessage.message"

Vue.js consume json

My problem is with this json.
http://dev-rexolution.pantheonsite.io/api/noticias
I need to consume with vuejs 2 only the first element of the array to be able to display it, working with the console I worked but with no vuejs.
This console log work: console.log(response.data[0].title[0].value);
<template>
<div class="Box Box--destacado1">
<div class="Media Media--rev">
<div class="Media-image">
</div>
<div class="Media-body">
<span class="Box-info">{{ noticias[0].field_fecha[0].value}}</span>
<h3 class="Box-title">
{{ /*noticias[0].title[0].value */}}
</h3>
<p class="Box-text">{{/*noticias[0].field_resumen[0].value*/}}</p>
</div>
</div>
</template>
<script>
import axios from 'axios';
export default {
data: () => ({
noticias: [],
errors: []
}),
// Fetches posts when the component is created.
created() {
axios.get(`http://dev-rexolution.pantheonsite.io/api/noticias`)
.then(response => {
// JSON responses are automatically parsed.
this.noticias = response.data
})
.catch(e => {
this.errors.push(e)
})
}
}
</script>
You're probably running into an issue where your template is attempting to show data that doesn't exist until the AJAX request has completed.
I would set a flag to indicate when the data is available and toggle the display using v-if. For example
Template
<div class="Media-body" v-if="loaded">
Script
data () {
loaded: false,
noticias: [],
errors: []
}
and in your created hook
.then(response => {
this.loaded = true
this.noticias = response.data
})
Alternatively, set up your initial noticias array with some dummy data
noticias: [{
title: [{ value: null }]
field_fecha: [{ value: null }]
field_resumen: [{ value: null }]
}]

Categories