I am calling fetchData() method from computed property. I don't know this is the correct way or not. I have also another dependability in Watch function. fetchData() will also call when expertId will change.
I can call fetchData() function using watch or computed property it works though I am confused this process is correct or not. But, the problem is in my Computed property! after fetching data fullCalendar is reloading, and then somehow this.dateInfo is overwriting and, calling computed property again and again. Just like a recursion. Making call continuously.
import FullCalendar from "#fullcalendar/vue";
import dayGridPlugin from "#fullcalendar/daygrid";
import timeGridPlugin from "#fullcalendar/timegrid";
import deLocale from "#fullcalendar/core/locales/de";
export default {
components: {
FullCalendar,
},
props: {
expertId: Number | String,
leadToOpen: Number | String,
config: Object,
defaultView: {
type: String,
default: "timeGridWeek",
},
header: {
type: Object,
default() {
return {
left: "title",
center: "timeGridWeek dayGridMonth dayGrid",
right: "today prev,next",
};
},
},
goTo: {
type: Date,
default: null,
},
},
watch: {
expertId(newId, oldId) {
if (history.pushState) {
var newurl =
window.location.protocol +
"//" +
window.location.host +
window.location.pathname +
`?user=${newId}`;
window.history.pushState({ path: newurl }, "", newurl);
}
this.fetchData();
},
// dateInfo(){
// this.fetchData();
// }
},
data() {
return {
events: {
type: Array,
default(){
return{
id: 'a',
title: 'my event',
start: '2020-10-10'
}
}
},
dateInfo: null,
busy: false,
displayAppointment: null,
displayOwner: null,
eventTypes: [
{ name: "Kundentermin", color: "#32bb60" },
{ name: "Termin bei Lead", color: "#db0630" },
{ name: "Termin ohne Kunde/Lead", color: "#3f888f" },
{ name: "Privater Termin (akzeptiert)", color: "#4682B4" },
{ name: "Privater Termin (offen)", color: "#505050" },
{ name: "Ehemaliger Termin", color: "#cdcdcd" },
],
showEdit: false,
showInfo: false,
showModal: false,
leadId: null,
locale: "de",
locales: [deLocale],
calendarOptions: {
headerToolbar: this.header,
plugins: [dayGridPlugin, timeGridPlugin],
initialView: "timeGridWeek",
eventClick: this.eventClickHandler,
events: null,
slotMinTime: "07:00:00",
slotMaxTime: "21:00:00",
locale: "de",
locales: [deLocale],
ref: "calendar",
eventDisplay: "block",
displayEventTime: false,
height: "auto",
allDaySlot: false,
buttonText: {
dayGrid: "Tag",
},
lazyFetching: true,
datesSet: (dateInfo) => {
this.dateInfo = dateInfo; // using this vale in Computed property
}
},
};
},
methods: {
async fetchData() {
this.busy = true;
const response = await axios.get("/api/users/" + this.expertId + "/startTime/" + this.dateInfo.startStr + "/endTime/" + this.dateInfo.endStr);
this.events = response.data;
this.calendarOptions.events = response.data;
this.busy = false;
},
},
computed: {
myDateInfo: function(){
let v = this.dateInfo;
this.fetchData(); // I need to call fetchData(), when this.dateInfo will change.
},
},
mounted() {
this.fetchData();
if (this.$props["leadToOpen"]) {
this.leadId = this.leadToOpen;
this.showModal = true;
}
if (this.goTo) {
this.$refs.calendar.getApi().gotoDate(this.goTo);
}
},
};
Related
We are facing issue while implementing "€" symbol for currency, for "$" it works fine. Code snippet:
Working fine with below code:
import { D3BarChart } from 'vue-d3-charts';
export default {
name: "D3Chart",
components: {
D3BarChart,
},
props: {
aemdata: {
type: Object,
required: true,
},
billingdata: {
type: Object,
required: true,
},
},
data() {
return {
topUpColor : '#D3D3D3',
deductionColor : '#696969',
chart_config: {
key: 'monthYear',
values: ['topUp', 'deduction'],
axis: {
yTicks: 10,
yFormat: '$',
},
color: {
keys: {
'topUp': '#D3D3D3',
'deduction': '#696969',
},
},
},
};
},
}
Working screenshot:
But when we are using below code:
import { D3BarChart } from 'vue-d3-charts';
export default {
name: "D3Chart",
components: {
D3BarChart,
},
props: {
aemdata: {
type: Object,
required: true,
},
billingdata: {
type: Object,
required: true,
},
},
data() {
return {
topUpColor : '#D3D3D3',
deductionColor : '#696969',
chart_config: {
key: 'monthYear',
values: ['topUp', 'deduction'],
axis: {
yTicks: 10,
yFormat: '€',
},
color: {
keys: {
'topUp': '#D3D3D3',
'deduction': '#696969',
},
},
},
};
},
}
It is throwing Below error
"An error occurred while showing the error page Unfortunately an error
occurred and while showing the error page another error occurred
Error details: TypeError: this.chart.destroyChart is not a function
Go back to home"
I'm trying to implement the Timeline calendar from Fullcalendar with Vuejs, but the calendar is initializing before the data is ready. It works if I navigate to other pages and comeback.. all the data is there. I've created the methods: getEmployees() and getApprovedAbsences(), to create the array with the data needed.
I'm fairly new to Vue js, so any help would be appreciated. Thanks
Code:
<template>
<div class="admin-calendar">
<FullCalendar :options="calendarOptions" />
</div>
</template>
<script>
import FullCalendar from '#fullcalendar/vue'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction'
import resourceTimelinePlugin from '#fullcalendar/resource-timeline'
import ptLocale from '#fullcalendar/core/locales/pt';
import moment from "moment";
export default {
components: { FullCalendar },
props: {
getAbsencesRequests: {
type: Array,
},
employees: {
type: Array,
},
},
data() {
return {
calendarOptions: {
plugins: [ resourceTimelinePlugin ],
headerToolbar: {
left: 'today prev,next',
center: 'title',
right: 'resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth'
},
locales: [ ptLocale ],
locale: 'pt',
aspectRatio: 1.6,
initialView: 'resourceTimelineDay',
resourceGroupField: 'department',
resourceAreaHeaderContent: 'Colaboradores',
handleWindowResize: false,
height: 400,
resources: this.getEmployees,
events: this.getApprovedAbsences,
}
}
},
methods: {
async getApprovedAbsences() {
let absenceList = []
this.getAbsencesRequests.forEach(absence => {
if (absence.status === "APPROVED") {
absence.periods.forEach((period) => {
absenceList.push({
start: moment(period.validFromLocaleDate, "DD/MM/YYYY").format("YYYY-MM-DD"),
end: moment(period.validToLocaleDate, "DD/MM/YYYY").format("YYYY-MM-DD"),
title: absence.absenceName,
resourceId: absence.requesterId,
});
});
}
})
return absenceList
},
async getEmployees() {
let employeeList = []
this.employees.forEach(employee => {
employeeList.push({
id: employee.id,
department: employee.department["id"] === "" ? "SEM DEPARTAMENTO ATRIBUÍDO" : employee.department["name"],
title: employee.name,
})
})
return employeeList
}
},
}
</script>
You could add an if statement to check if data is ready. Something like this:
<template>
<div class="admin-calendar">
<FullCalendar
v-if="employeeList && absenceList"
:options="calendarOptions" />
</div>
</template>
This would only load FullCalendar component after resources and events are not null.
Now, change data to this:
data() {
return {
employeeList: null,
absenceList: null,
calendarOptions: {
plugins: [ resourceTimelinePlugin ],
headerToolbar: {
left: 'today prev,next',
center: 'title',
right: 'resourceTimelineDay,resourceTimelineWeek,resourceTimelineMonth'
},
locales: [ ptLocale ],
locale: 'pt',
aspectRatio: 1.6,
initialView: 'resourceTimelineDay',
resourceGroupField: 'department',
resourceAreaHeaderContent: 'Colaboradores',
handleWindowResize: false,
height: 400,
resources: this.getEmployees,
events: this.getApprovedAbsences,
}
}
}
And change load methods to store data in component variables:
methods: {
async getApprovedAbsences() {
let tmpAbsenceList = []
this.getAbsencesRequests.forEach(absence => {
if (absence.status === "APPROVED") {
absence.periods.forEach((period) => {
tmpAbsenceList.push({
start: moment(period.validFromLocaleDate, "DD/MM/YYYY").format("YYYY-MM-DD"),
end: moment(period.validToLocaleDate, "DD/MM/YYYY").format("YYYY-MM-DD"),
title: absence.absenceName,
resourceId: absence.requesterId,
});
});
}
})
absenceList = tmpAbsenceList
},
async getEmployees() {
let tmpEmployeeList = []
this.employees.forEach(employee => {
tmpEmployeeList.push({
id: employee.id,
department: employee.department["id"] === "" ? "SEM DEPARTAMENTO ATRIBUÍDO" : employee.department["name"],
title: employee.name,
})
})
employeeList = tmpEmployeeList
}
},
And finally, call getMethods within created():
async created() {
await this.getApprovedAbsences()
await this.getEmployees()
}
This should load everything first, and then call FullCalendar. It should guarantee that everything is set up before loading the component. Try it and check if this idea works for you...
In callback function I can print the value in consoleLog. But, can not get that value in computed property. It shows undefined. Completely stack here.
props: {
startDate: Date, // declare prop here
expertId: Number | String,
leadToOpen: Number | String,
config: Object,
defaultView: {
type: String,
default: "timeGridWeek",
},
header: {
type: Object,
default() {
return {
left: "title",
center: "timeGridWeek dayGridMonth dayGrid",
right: "today prev,next",
};
},
},
goTo: {
type: Date,
default: null,
},
},
data() {
return {
events: {
type: Array,
default(){
return{
id: 'a',
title: 'my event',
start: '2020-10-10'
}
}
},
busy: false,
displayAppointment: null,
displayOwner: null,
eventTypes: [
{ name: "Kundentermin", color: "#32bb60" },
{ name: "Termin bei Lead", color: "#db0630" },
{ name: "Termin ohne Kunde/Lead", color: "#3f888f" },
{ name: "Privater Termin (akzeptiert)", color: "#4682B4" },
{ name: "Privater Termin (offen)", color: "#505050" },
{ name: "Ehemaliger Termin", color: "#cdcdcd" },
],
showEdit: false,
showInfo: false,
showModal: false,
leadId: null,
locale: "de",
locales: [deLocale],
calendarOptions: {
headerToolbar: this.header,
plugins: [dayGridPlugin, timeGridPlugin],
initialView: "timeGridWeek",
eventClick: this.eventClickHandler,
events: null,
slotMinTime: "07:00:00",
slotMaxTime: "21:00:00",
locale: "de",
locales: [deLocale],
ref: "calendar",
eventDisplay: "block",
displayEventTime: false,
height: "auto",
allDaySlot: false,
buttonText: {
dayGrid: "Tag",
},
lazyFetching: true,
datesSet: function (dateInfo) { /////// here is the call back function ////////
this.startDate = dateInfo.start;
console.log( this.startDate);
}
},
};
},
computed: {
dateRange: function(){
return this.startDate; // undefined
}
},
The problem is your callback function. If you want access to the Vue instance, it has to be an arrow function:
dateSet: (dateInfo) => {
this.startDate = dateInfo.start
}
Inside your callback, this is not the Vue instance.
Could you try with:
computed: {
getDateRange() {
return this.startDate;
}
}
Or maybe you did not provide prop value in outer component
I use https://www.npmjs.com/package/vue-bootstrap4-table#8-filtering with django-rest-framework.
The problem is that this component uses totally different query params for sorting, filtering, etc.
vue-bootstrap4-table
http://127.0.0.1:8000/api/products/?queryParams=%7B%22sort%22:[],%22filters%22:[%7B%22type%22:%22simple%22,%22name%22:%22code%22,%22text%22:%22xxx%22%7D],%22global_search%22:%22%22,%22per_page%22:10,%22page%22:1%7D&page=1
"filters":[{"type":"simple","name":"code","text":"xxx"}],
but Django-rest-framework needs this format:
../?code__icontains=...
Do you know how to make vue-bootrstrap4-table to generate this format?
My app:
new Vue({
el: '#app',
data: {
product_list_url: "{% url "api:product-list" %}",
rows: [],
total_rows:0,
queryParams: {
sort: [],
filters: "",
global_search: "",
per_page: 10,
page: 1,
},
columns: [{
label: "Kód",
name: "code",
filter: {
type: "simple",
placeholder: "code"
},
sort: true,
},
{
label: "Názov",
name: "name",
filter: {
type: "simple",
placeholder: "Enter name"
},
sort: true,
},
],
config: {
checkbox_rows: true,
rows_selectable: true,
{#card_title: "Vue Bootsrap 4 advanced table",#}
server_mode: true,
}
},
mounted() {
this.fetchData();
},
methods: {
onChangeQuery(queryParams) {
this.queryParams = queryParams;
this.fetchData();
},
fetchData() {
let self = this;
axios.get(self.product_list_url, {
params: {
"queryParams": this.queryParams,
"page": this.queryParams.page
}
})
.then(function (response) {
self.rows = response.data.results;
self.total_rows = response.data.count;
})
.catch(function (error) {
console.log(error);
});
}
},
})
Javascript from this Metronic v5.05 theme.
I have a page where I have a datatable printed and it displays fine.
I have put the whole javascript code that I use for display the table
but it is important for me that the tables reloads new data, if there is any.
I think I know how I would build this without datables.js but the guy
that I am building this project for insists I have to use it so I have to.
I have this code to make it work on my page.
//== Class definition
var Dashboard = function() {
//== Hændelser hentes
var datatableIncidents = function() {
if ($('#LOGMSGS').length === 0) {
return;
}
var datatable = $('.m_datatable').mDatatable({
layout: {
theme: 'default',
class: 'm-datatable--brand',
scroll: false,
height: null,
footer: false,
header: true,
height: 400,
smoothScroll: {
scrollbarShown: true
},
spinner: {
overlayColor: '#000000',
opacity: 0,
type: 'loader',
state: 'brand',
message: true
},
icons: {
sort: {asc: 'la la-arrow-up', desc: 'la la-arrow-down'},
pagination: {
next: 'la la-angle-right',
prev: 'la la-angle-left',
first: 'la la-angle-double-left',
last: 'la la-angle-double-right',
more: 'la la-ellipsis-h'
},
rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'}
}
},
sortable: false,
pagination: true,
search: {
// search delay in milliseconds
delay: 400,
// input text for search
input: $('#generalSearch'),
},
data: {
type: 'remote',
source: {
read: {
url: 'http://beredskabsweb.dk/Template/alert-log-json.php'
}
},
pageSize: 20,
saveState: {
cookie: true,
webstorage: true
},
},
layout: {
theme: 'default',
class: '',
scroll: false,
footer: false
},
sortable: true,
filterable: true,
pagination: true,
columns: [
{
field: "alertMessageTime",
title: "Tid",
width: 100,
filterable: true,
template: function(row) {
return '<time>'+row.alertMessageTime+'</time>';
},
},
{
field: "alertMessageText",
title: "Text",
filterable: true,
template: function(row) {
return row.alertMessageText;
},
},
{
field: "alertMessageAuthor",
title: "Forfatter",
width: 240,
filterable: true,
template: function(row) {
return ''+row.MemberUsername+'';
},
},
]
});
}
return {
//== Init demos
init: function() {
// datatables
datatableIncidents();
setInterval( function () { datatableIncidents();},4000);
}
};
}();
//== Class initialization on page load
jQuery(document).ready(function() {
Dashboard.init();
setInterval(Dashboard,2000);
});
As you see i have tried to put this code in the bottom so that it should reload, but it doesn't.
setInterval(Dashboard,2000)
You can use the reload api by metronic. You can see the docs here
http://keenthemes.com/metronic/documentation.html#sec14-5
First, you should export your datatable variable from the class so you can use it for other use like add function to reload the table or etc. I added below line:
return {
datatable: function() {
return datatable;
}
};
After that, you also should create function to reload the table by the variable we just export before and by using reload api by metronic.
reload: function {
demo().datatable().reload();
}
Complete code:
//== Class definition
var Dashboard = function() {
//== Hændelser hentes
var datatableIncidents = function() {
if ($('#LOGMSGS').length === 0) {
return;
}
var datatable = $('.m_datatable').mDatatable({
layout: {
theme: 'default',
class: 'm-datatable--brand',
scroll: false,
height: null,
footer: false,
header: true,
height: 400,
smoothScroll: {
scrollbarShown: true
},
spinner: {
overlayColor: '#000000',
opacity: 0,
type: 'loader',
state: 'brand',
message: true
},
icons: {
sort: {asc: 'la la-arrow-up', desc: 'la la-arrow-down'},
pagination: {
next: 'la la-angle-right',
prev: 'la la-angle-left',
first: 'la la-angle-double-left',
last: 'la la-angle-double-right',
more: 'la la-ellipsis-h'
},
rowDetail: {expand: 'fa fa-caret-down', collapse: 'fa fa-caret-right'}
}
},
sortable: false,
pagination: true,
search: {
// search delay in milliseconds
delay: 400,
// input text for search
input: $('#generalSearch'),
},
data: {
type: 'remote',
source: {
read: {
url: 'http://beredskabsweb.dk/Template/alert-log-json.php'
}
},
pageSize: 20,
saveState: {
cookie: true,
webstorage: true
},
},
layout: {
theme: 'default',
class: '',
scroll: false,
footer: false
},
sortable: true,
filterable: true,
pagination: true,
columns: [
{
field: "alertMessageTime",
title: "Tid",
width: 100,
filterable: true,
template: function(row) {
return '<time>'+row.alertMessageTime+'</time>';
},
},
{
field: "alertMessageText",
title: "Text",
filterable: true,
template: function(row) {
return row.alertMessageText;
},
},
{
field: "alertMessageAuthor",
title: "Forfatter",
width: 240,
filterable: true,
template: function(row) {
return ''+row.MemberUsername+'';
},
},
]
});
return {
datatable: function() {
return datatable;
}
};
}
return {
//== Init demos
init: function() {
// datatables
datatableIncidents();
setInterval( function () { datatableIncidents();},4000);
},
reload: function {
demo().datatable().reload();
}
};
}();
//== Class initialization on page load
jQuery(document).ready(function() {
Dashboard.init();
setInterval(Dashboard.reload(),2000);
});