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...
Related
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);
}
},
};
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
Hi hope you will help me on this
I'm working on Angular 10 and full calendar v5 and I want to know how can I add an event into the day when clicking on it
export class CalendarComponent implements OnInit{
nomaction;
constructor(public dialog: MatDialog) { }
ngOnInit(): void {
}
calendarOptions: CalendarOptions = {
initialView: 'dayGridMonth',
weekends: true,
dateClick: this.handleDateClick.bind(this), // bind is important!
events: [
{ title: 'event 1', date: '2020-08-20' },
{ title: 'event 2', date: '2020-08-21' }
]
};
handleDateClick(arg) {
const dialogRef = this.dialog.open(AddeventComponent, {
width: '250px',
data: {nomaction: this.nomaction}
});
dialogRef.afterClosed().subscribe(result => {
this.nomaction = result.nomaction;
this.calendarOptions.events = [{ title: this.nomaction, date: arg.dateStr }];//a code for adding an event into the day
console.log('action',this.nomaction);
});
}
toggleWeekends() {
this.calendarOptions.weekends = !this.calendarOptions.weekends
}
}
this.calendarOptions.events is not an array so I couldn't use push to add the object !
How can I add it without losing my first data !
Add on your calendar options this :
calendarOptions: CalendarOptions = {
initialView: 'dayGridMonth',
weekends: true,
dateClick: this.handleDateClick.bind(this), // bind is important!
events: [
{ title: 'event 1', date: '2020-08-20' },
{ title: 'event 2', date: '2020-08-21' }
],
dateClick:function (info) {
console.log("See day infos: ",info);
}
};
I let you the documentation here
I'm new when using materialUI table in react.js, I want to try using react-material table but I got lost as how can I show my data in the table, Let say I have 28 data and in fact it already show the right number in the pagination but the data itself doesn't show anything. this is the documentation link for react-material table Check this.
I already read several topic about this but all of them using tableRow, tableHead, and etc.
this is my component code:
import React, { Component } from 'react';
import MaterialTable from 'material-table';
import { history } from '../../../../Helpers/history';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { orderActions } from '../../../../Actions/orderActions';
import { withStyles } from '#material-ui/core/styles';
// Component
import './tabledata.css';
const styles = theme => ({
'#global': {
body: {
backgroundColor: theme.palette.common.white,
},
},
});
class Tabledata extends Component {
constructor(props) {
super(props);
// const { orders } = this.props;
this.state = {
columns: [
{ title: 'Nama Pemesanan', field: 'name' },
{ title: 'Status', field: 'status' },
{ title: 'Estimasi Pengerjaan (Hari)', field: 'estimate', type: 'numeric' },
{ title: 'Jumlah Pesanan (pcs)', field: 'unit', type: 'numeric' },
{ title: 'Harga (Rp)', field: 'price', type: 'numeric' },
],
data: [
{
id: 2,
name: 'lala',
status: 'Penyablonan',
estimate: 8,
unit: 36,
price: '36.000.000',
},
],
}
}
componentDidMount() {
if(localStorage.getItem('auth')) {
const { dispatch } = this.props;
dispatch(orderActions.getAllOrder());
// history.push('/dashboard');
}
}
componentWillReceiveProps(newProps){
this.setState({ loading: newProps.loading }); // remove the loading progress when logged in or fail to log in
}
handleChange = prop => event => {
this.setState({ [prop]: event.target.value });
};
change(data){
console.log("Check ID : ", data);
}
render(){
const { orders } = this.props;
console.log("test console : ", orders)
return (
<div className="tabledata-order">
<div className="row item-section">
<div className="col">
<div className="card">
<div className="card-body">
<MaterialTable
title="Daftar Pesanan"
columns={this.state.columns}
key={orders._id}
data={orders}
/>
</div>
</div>
</div>
</div>
</div>
);
}
}
Tabledata.propTypes = {
classes: PropTypes.object.isRequired
};
const mapStateToProps = (state) => {
const { orders } = state.orderPage;
return {
orders
};
}
const connectedTableDataPage = withRouter(connect(mapStateToProps, '', '', {
pure: false
}) (withStyles(styles)(Tabledata)));
export { connectedTableDataPage as Tabledata };
As you can see, this material table have a component like this
<MaterialTable
title="Daftar Pesanan"
columns={this.state.columns}
key={orders._id}
data={orders}
/>
As you can see, in the bottom of the image you can see 1-5 of 28 and in my console there is exactly 28 data but the table itself doesn't show any data
can someone help me? how can I show the data in orders and this is the example of the image json that I have:
Finally I can fix this problem, this answer for you who have facing the same problem with react-material table if your data doesn't show but it show in console.log. you must check the field in column
this.state = {
columns: [
{ title: 'Nama Pemesanan', field: 'name' },
{ title: 'Status', field: 'status' },
{ title: 'Estimasi Pengerjaan (Hari)', field: 'estimate', type: 'numeric' },
{ title: 'Jumlah Pesanan (pcs)', field: 'unit', type: 'numeric' },
{ title: 'Harga (Rp)', field: 'price', type: 'numeric' },
],
data: [
{
id: 2,
name: 'lala',
status: 'Penyablonan',
estimate: 8,
unit: 36,
price: '36.000.000',
},
],
}
let say, json that I got have city, color, and weight then you must state the column field as such:
this.state = {
columns: [
{ title: 'detail Address', field: 'city' },
{ title: 'color', field: 'color' },
{ title: 'weight', field: 'weight' },
],
}
and for the MaterialTable you can just put all the variable you have like this
<MaterialTable
title="Daftar Pesanan"
columns={this.state.columns}
key={orders._id}
data={orders}
/>
and you can get the data like I show you below
I hope this answer can help you who have a hard time with react-material table
I am working the react-data-grid library to create an filterable datatable in react. All of their examples use the depreciated React.createClass method, and I am trying to refactor to the ES6 Class Components.
Specifically, I am trying to refactor the Filterable Grid example:
demo
source
gist of non-refactored adaption that is working
My refactored code looks like this:
import React from 'react'
import ReactDataGrid from 'react-data-grid'
const { Toolbar, Data: { Selectors } } = require('react-data-grid-addons')
class FilterableTable extends React.Component {
constructor(props) {
super(props);
this._columns = [
{
key: 'id',
name: 'ID',
width: 80
},
{
key: 'task',
name: 'Title',
editable: true
},
{
key: 'priority',
name: 'Priority',
editable: true
},
{
key: 'issueType',
name: 'Issue Type',
editable: true
},
{
key: 'complete',
name: '% Complete',
editable: true
},
{
key: 'startDate',
name: 'Start Date',
editable: true
},
{
key: 'completeDate',
name: 'Expected Complete',
editable: true
}
];
this.state = { rows: this.createRows(1001), filters: {} };
console.log(this.state);
}
getRandomDate = (start, end) => {
return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toLocaleDateString();
}
createRows = () => {
let rows = [];
for (let i = 1; i < 1000; i++) {
rows.push({
id: i,
task: 'Task ' + i,
complete: Math.min(100, Math.round(Math.random() * 110)),
priority: ['Critical', 'High', 'Medium', 'Low'][Math.floor((Math.random() * 3) + 1)],
issueType: ['Bug', 'Improvement', 'Epic', 'Story'][Math.floor((Math.random() * 3) + 1)],
startDate: this.getRandomDate(new Date(2015, 3, 1), new Date()),
completeDate: this.getRandomDate(new Date(), new Date(2016, 0, 1))
});
}
return rows;
}
getRows = () => {
return Selectors.getRows(this.state);
}
getSize = () => {
return this.getRows().length;
}
rowGetter = ( rowIdx ) => {
let rows = this.getRows();
return rows[rowIdx];
}
handleFilterChange = ({ filter }) => {
let newFilters = Object.assign({}, this.state.filters);
if (filter.filterTerm) {
newFilters[filter.column.key] = filter;
} else {
delete newFilters[filter.column.key];
}
this.setState({ filters: newFilters });
}
onClearFilters = () => {
// all filters removed
this.setState({filters: {} });
}
render() {
return (
<ReactDataGrid
columns={this._columns}
rowGetter={this.rowGetter}
enableCellSelect={true}
rowsCount={this.getSize()}
minHeight={800}
toolbar={<Toolbar enableFilter={true}/>}
onAddFilter={this.handleFilterChange}
onClearFilters={this.onClearFilters} />);
}
}
export default FilterableTable
Issue:
An issue arises when I click the filter button - a new header row is rendered (via the Toolbar component), but there is no input field. This screenshot shows the two examples side by side - my ES6 version on top and the createClass version on the bottom:
I am not sure what is causing this, but have a feeling it might be due to the way I am importing Toolbar ? Any help or a point in the right direction would be greatly appreciated ! (As well as any other suggestions re refactoring this component.)
To enable filtering for a given column, you need to set filterable=true for that column. So, add filterable:true to each object in this._columns. For more info, check http://adazzle.github.io/react-data-grid/examples.html#/filterable-grid.
this._columns = [
{
key: 'id',
name: 'ID',
width: 80
},
{
key: 'task',
name: 'Title',
editable: true,
filterable:true
},
{
key: 'priority',
name: 'Priority',
editable: true,
filterable:true
},
{
key: 'issueType',
name: 'Issue Type',
editable: true,
filterable:true
},
{
key: 'complete',
name: '% Complete',
editable: true,
filterable:true
},
{
key: 'startDate',
name: 'Start Date',
editable: true,
filterable:true
},
{
key: 'completeDate',
name: 'Expected Complete',
editable: true,
filterable:true
}
];