Dynamically mark dates in react-native-calendars - reactjs

I'am trying to mark dates in react-native-calendars that i get from an api call. Can someone please help?
<Calendar
markingType={'multi-dot'}
markedDates={this.state.dates}
/>
In constructor, I am maintaining
this.state = {dates : []}
I have invoked the function marked() where I am mapping over the data and pushing the dates into another array and then doing a setState as
this.setState({
dates : {
[attendance] : [
{
key: 'vacation',
color: 'blue',
selectedDotColor: 'red'
}
]
}
})
I'am sharing the code I am at liberty to.
P.S : I'am new to this.
Thanks in andvance

please use this library it's easy to customization with custom date styles "react-native-calendar-picker"

Make sure that markedDates param is immutable. If you change markedDates object content but the reference to it does not change calendar update will not be triggered.
Please try;
markedDates={{
'2019-12-9': {
periods: [
{ startingDay: false, endingDay: true, color: '#5f9ea0' },
{ startingDay: false, endingDay: true, color: '#ffa500' },
{ startingDay: true, endingDay: false, color: '#f0e68c' },
]
},
'2019-12-9': {
periods: [
{ startingDay: true, endingDay: false, color: '#ffa500' },
{ color: 'transparent' },
{ startingDay: false, endingDay: false, color: '#f0e68c' },
]
},
}}

I actually had to do the exact same thing recently with react-native-calendars. Here is a simplified version of the function I wrote to create marked dates:
createMarkedDates = (dates) => {
let markedEvents = {};
let numEvents = {};
let uniqueDates = [...new Set(dates)]; //remove duplicate event dates
dates.forEach(function (count) { //if multiple events on one date, determine how many events are on each date
numEvents[count] = (numEvents[count] || 0) + 1;
});
uniqueDates.forEach(function (date) {
let dots = [];
let markedData = {};
for (let i = 0; i < numEvents[date]; i++) {
dots.push(event); //add dots for as many events are on that day
}
markedData['dots'] = dots; //set the array of dots
markedEvents[date] = markedData; //add markers to marked dates
});
};
this.setState({markedDates: markedEvents});
}
dates is an array of dates that is being passed from the API.
This should output you a marked date object with the markings for each date, and also if you need it, it will put multiple dots on a day if it appears more than once in your array.
Also, I believe your dates need to be in ISO date format (YYYY-MM-DD) for react-native-calendars to mark the dates.
I hope this example helps!

Related

custom legend hide() does not remove data labels

I am building a project using React with a doughnut and bar chart. Working with Chart.js 3.xx.
I am trying to make my custom legend functional. I want to make data fractions disappear when the user clicks my legend items - like in the native legend, and optimally also remove the data and make the chart present it's updated data after removal.
I also use data labels to present percentage of the data on the fractions.
import ChartDataLabels from 'chartjs-plugin-datalabels';
I came across this topic: ChartJS - Show/hide data individually instead of entire dataset on bar/line charts
and used this suggested code there:
function chartOnClick(evt) {
let chart = evt.chart
const points = chart.getElementsAtEventForMode(evt, 'nearest', {}, true);
if (points.length) {
const firstPoint = points[0];
//var label = myChart.data.labels[firstPoint.index];
//var value = myChart.data.datasets[firstPoint.datasetIndex].data[firstPoint.index];
let datasetIndex = firstPoint.datasetIndex, index = firstPoint.index;
if (firstPoint.element.hidden != true) {
chart.hide(datasetIndex, index);
} else {
chart.show(datasetIndex, index);
}
}
}
options: { // chart options
onClick: chartOnClick
}
It almost works, but the hide() method doesn't remove the fraction's percentage data label when activated, whereas when clicking the native legend it does remove it entirely.
I tried looking in the plugin's docs but didn't manage to find how to remove a single label.
How can I achieve what I am looking for?
EDIT:
Options Object:
export const doughnutOptsObj = {
onClick: chartOnClick,
responsive: true,
maintainAspectRatio: false,
layout: { padding: { top: 16, bottom: 16 } },
hoverOffset: 32,
plugins: {
legend: {
display: true,
position: 'bottom',
},
datalabels: {
formatter: (value, dnct1) => {
let sum = 0;
let dataArr = dnct1.chart.data.datasets[0].data;
dataArr.map((data) => {
sum += Number(data);
});
let percentage = ((value * 100) / sum).toFixed() + '%';
return percentage;
},
color: ['#fbfcfd'],
font: { weight: 'bold' },
// display: false, <-- this works and makes all of the data labels disappear
},
},
};
It seems that the onClick function is working properly.
I have tried the attached code, leveraging on toggleDataVisibility API, and it's working as requested (codepen: https://codepen.io/stockinail/pen/abKNJqJ):
function chartOnClick(evt) {
let chart = evt.chart
const points = chart.getElementsAtEventForMode(evt, 'nearest', {}, true);
if (points.length) {
const firstPoint = points[0];
chart.toggleDataVisibility(firstPoint.index);
chart.update();
}
}

Regarding displaying ui-calendar events

Hello all i am designing a leave management website with angularjs and ui-calendar.If a user takes a leave ,the values are taken from the database and displayed as an event in the calendar.Now what i want to do is ,if the user is not absent on particular day,it should be displayed as present event.Hope the following image helps understanding better.
Now vikki is taking leave on friday.I want to mark other dates as an event displaying in different color saying he s present.I need this to be in the week view.Please let me know if there is any way to do this thing.Following is my code
app.factory('calendarSer', ['$http','$rootScope', 'uiCalendarConfig', function ($http,$rootScope, uiCalendarConfig) {
return {
displayCalendar: function($scope) {
$calendar = $('[ui-calendar]');
var date = new Date(),
d = date.getDate(),
m = date.getMonth(),
y = date.getFullYear();
$scope.changeView = function(view) {
$calendar.fullCalendar('changeView', view);
};
/* config object */
$scope.uiConfig = {
calendar: {
lang: 'da',
height: 450,
editable: true,
selectable: true,
header: {
left: 'month basicWeek basicDay',
center: 'title',
right: 'today prev,next'
},
eventClick: function(date, jsEvent, view) {
$scope.alertMessage = (date.title + ' was clicked ');
alert("clicked" + date.title);
},
select: function(start, end, allDay) {
var obj = {};
obj.startAt = start.toDate();
obj.startAt = new Date(obj.startAt).toUTCString();
obj.startAt = obj.startAt.split(' ').slice(0, 4).join(' ');
obj.endAt = end.toDate();
obj.endAt = new Date(obj.endAt).toUTCString();
obj.endAt = obj.endAt.split(' ').slice(0, 4).join(' ');
$rootScope.selectionDate = obj;
$("#modal1").openModal();
calendar.fullCalendar('unselect');
},
eventRender: $scope.eventRender
}
};
$scope.events = [];
$scope.eventSources = [$scope.events];
$http.get("rest/leave/list", {
cache: true,
params: {}
}).then(function(data) {
$scope.events.slice(0, $scope.events.length);
angular.forEach(data.data, function(value) {
console.log(value.title);
$scope.events.push({
title: value.title,
description: value.description,
start: value.startAt,
end: value.endAt,
allDay: value.isFull,
stick: true
});
});
});
}
}
}]);
Thanking you
You need to also create the events array which would display the user is present. However, if you try to create the array in the front-end, then you would not know the other user information to fill the calendar.
"rest/leave/list" : will return that vikki is on leave, however what if the other user that has not taken any leave and is not returned in this array? how will you be able to fill the calendar saying user is present all the other days?
$scope.events.push({
title: value.title,
description: value.description,
start: value.startAt,
end: value.endAt,
allDay: value.isFull,
stick: true
});
$scope.eventSources = [$scope.events];
You are filling the events and binding it to the eventSources.
So you need to return something like below from the reponse "rest/leave/list":
{
title: "vikki",
description: "description",
startAt: "2017-05-05 00:00",
endAt: "2017-05-05 23:59",
isFull: true,
leave: true <- This will say he is absent
},
{
title: "vikki",
description: "description",
//The start and end date time will control the block that will be booked in the calendar
startAt: "2017-06-05 00:00",
endAt: "2017-01-06 23:59",
isFull: true,
leave: false <- This will say he is present
//This array will book the calendar from May-06 to end of the month.
//If you want the past, then create one in the past and send it from
//server
}
In the above array, you need to create separate rows for absent and present. For example , 1st row consist of January month where the user has not taken any leaves, so you create a row with Start date Jan 01 and End date Jan 30, In Feb, the user has taken one leave on say 5th. So you create three rows, row 1 with Feb 01 to Feb 04 as present, row 2 with Feb 05 as absent, and row 3 with Feb 06 - Feb 31 as present
Using the variable "leave" from the array, in the frontend you can change the colour. You can refer it from this how to achieve it.
Jquery Full calendar and dynamic event colors

Can a subgrid be exported in angular ui-grid

I'm using the grid from http://ui-grid.info/ in a project. I've created a hierarchical grid, which works nicely, but when I do an export, it only exports the data from the top-level grid.
This is by design and is standard functionality for the grid, so there's no point in me putting up any example code. Any example from http://ui-grid.info/docs/#/tutorial will do.
Is there a way to export the subgrid (preferably both the main grid AND the subgrid together as they appear in the grid)?
Sadly the answer is no.
As you can see here the function getData iterates through all rows and then through all columns, adding to an array of extractedFields the columns to be extracted and aggregating those in an array of extractedRows.
This means that no data, other than what's defined in gridOptions' columnDef will be read, converted and extracted.
By design, subgrid information are stored inside a property of any row entity's subGridOptions but this property is never accessed inside of the exporter feature.
The motivation behind this behaviour is that expandable grid feature is still at an alpha stage, so, supporting this in other features is not a compelling priority.
Furthermore, adding subgrid to a CSV could be quite hard to design, if we wanted to provide a general solution (for example I don't even think it would be compliant to CSV standard if you had different number of columns in the main grid and in subgrids).
That said, ui-grid is an open source project, so, if you have a working design in mind, feel free to open a discussion about it on the project gitHub page or, even better, if you can design a working (and tested) solution and create a pull request, even better!
I managed to get it working, although if I had the time I would do it a bit better than what I've done by actually creating a branch of the code and doing it properly, but given time constraints, what I've got is working nicely.
FYI, here's the way I ended up getting it to do what I wanted:
In my grid options, I turned off the CSV export options in the grid menu (because I've only implemented the changes for PDF).
I made a copy of exporter.js, named it custom.exporter.js and changed my reference to point to the new file.
In custom.exporter.js, I made a copy of the getData function and named it getGridRows. getGridRows is the same as getData, except it just returns the rows object without all the stuff that gets the columns and so on. For now, I'm coding it to work with a known set of columns, so I don't need all that.
I modified the pdfExport function to be as follows:
pdfExport: function (grid, rowTypes, colTypes) {
var self = this;
var exportData = self.getGridRows(grid, rowTypes, colTypes);
var docContent = [];
$(exportData).each(function () {
docContent.push(
{
table: {
headerRows: 1,
widths: [70, 80, 150, 180],
body: [
[{ text: 'Job Raised', bold: true, fillColor: 'lightgray' }, { text: 'Job Number', bold: true, fillColor: 'lightgray' }, { text: 'Client', bold: true, fillColor: 'lightgray' }, { text: 'Job Title', bold: true, fillColor: 'lightgray' }],
[formattedDateTime(this.entity.JobDate,false), this.entity.JobNumber, this.entity.Client, this.entity.JobTitle],
]
}
});
var subGridContentBody = [];
subGridContentBody.push([{ text: 'Defect', bold: true, fillColor: 'lightgray' }, { text: 'Vendor', bold: true, fillColor: 'lightgray' }, { text: 'Status', bold: true, fillColor: 'lightgray' }, { text: 'Sign off', bold: true, fillColor: 'lightgray' }]);
$(this.entity.Defects).each(function () {
subGridContentBody.push([this.DefectName, this.DefectVendor, this.DefectStatus, '']);
});
docContent.push({
table: {
headerRows: 1,
widths: [159, 150, 50, 121],
body: subGridContentBody
}
});
docContent.push({ text: '', margin: 15 });
});
var docDefinition = {
content: docContent
}
if (self.isIE()) {
self.downloadPDF(grid.options.exporterPdfFilename, docDefinition);
} else {
pdfMake.createPdf(docDefinition).open();
}
}
No, there is no direct way to export subgrid. rather you can create youur own json data to generate csv file.
Please check the below code
function jsonToCsvConvertor(JSONData, reportTitle) {
//If JSONData is not an object then JSON.parse will parse the JSON string in an Object
var arrData = typeof JSONData !== 'object' ? JSON.parse(JSONData) : JSONData,
csv = '',
row,
key1,
i,
subGridData;
//Set Report title in first row or line
csv += reportTitle + '\r\n\n';
row = '';
for (key1 in arrData[0]) {
if(key1 !== 'subGridOptions' && key1 !== '$$hashKey'){
row += key1 + ',';
}
}
csv += row + '\r\n';
for (i = 0; i < arrData.length; i++) {
row = '';
subGridData = '';
for (key1 in arrData[i]) {
if(key1 !== 'subGridOptions' && key1 !== '$$hashKey'){
row += '"' + arrData[i][key1] + '",';
}
else if(key1 === 'subGridOptions'){
//csv += row + '\r\n';
subGridData = writeSubGridData(arrData[i][key1].data);
}
}
csv += row + '\r\n';
csv = subGridData ? csv + subGridData + '\r\n' : csv;
}
if (csv === '') {
console.log('Invalid data');
}
return csv;
}
//Generates subgrid Data to exportable form
function writeSubGridData(subgridData){
var j,
key2,
csv = '',
row = '';
for (key2 in subgridData[0]){
if(key2 !== '$$hashKey'){
row += key2 + ',';
}
}
csv = row + '\r\n';
for (j=0; j < subgridData.length ; j++){
row = '';
for(key2 in subgridData[j]){
if(key2 !== '$$hashKey'){
row += '"' + subgridData[j][key2]+ '",';
}
}
csv += row + '\r\n';
}
return csv;
}
jsonToCsvConvertor(exportData, 'New-Report');

How to make Angular ui grid expand all rows initially?

I am using ui grid to show a list of data and I am trying to initially expand all rows.
I am trying to do this in the onRegisterApi event:
scope.GridOptions =
{
data: properties,
columnDefs:
[
{ name: "Full Address", field: "FullAddress" },
{ name: "Suburb", field: "Suburb" },
{ name: "Property Type", field: "PropertyType" },
{ name: "Price", field: "Price", cellFilter: 'currency'},
{ name: "Status", field: "Status" },
{ name: "Sale Type", field: "SaleType" },
{ name: "Date Created", field: "CreateDate", cellFilter: "date:'dd/MM/yyyy HH:mma'"}
],
expandableRowTemplate: 'template.html',
expandableRowHeight: 200,
onRegisterApi: (gridApi) =>
{
scope.gridApi = gridApi;
gridApi.expandable.on.rowExpandedStateChanged(scope,(row) =>
{
if (row.isExpanded) {
this.scope.GridOptions.expandableRowScope = row.entity;
}
});
gridApi.expandable.expandAllRows();
}
};
But the code above does not work. It looks like when I call expandAllRows() the rows are not rendered yet.
In my case, the following worked:
$scope.gridOptions = {
...
onRegisterApi: function(gridApi) {
$scope.gridApi = gridApi;
$scope.gridApi.grid.registerDataChangeCallback(function() {
$scope.gridApi.treeBase.expandAllRows();
});
}
};
I find I can expand all rows by using rowsRendered event:
gridApi.core.on.rowsRendered(scope,() => {
if (!gridApi.grid.expandable.expandedAll && !initialized)
{
gridApi.expandable.expandAllRows();
initialized = true;
}
});
I have used a variable initialized to identify if this is the first time rows are rendered as I only want to expand all rows initially.
None of the above worked for me for all of my grid use cases.
$scope.gridApi.grid.registerDataChangeCallback(function() {
if($scope.gridApi.grid.treeBase.tree instanceof Array){
$scope.gridApi.treeBase.expandAllRows();
}
});
The following works in every case I have tested. DataChangeCallback is called twice (for some unknown reason) on initial page load. The first time, gridApi.grid.treeBase.tree is an object which causes the issue with gridApi.grid.treeBase.tree.forEach above:
None of these answers worked for me, the following did:
scope.gridApi.core.on.rowsRendered(null, () => {
scope.gridApi.treeBase.expandAllRows();
});
The following worked for me, but no guarantee that it won't break anything... (looks good in my tests):
You need to change the source code, for example in ui-grid.js, i.e. the one your are deploying with your app:
In the addOrUseNode: function(...) inside the createTree: function(...) simply change COLLAPSED to EXPANDED for newNodes:
addOrUseNode: function (grid, row, parents, aggregationBase) {
...
var newNode = { state: uiGridTreeBaseConstants.EXPANDED, row: row, parentRow: null, aggregations: newAggregations, children: [] };
...
}
In module.service('uiGridTreeBaseService'... initializeGrid: function(grid) set grid.treeBase.expandAll from false to true (to let the tree know that all rows are expanded on initialitation)
[looks this is optional for the treeView]: Do the same In module.service('uiGridExpandableService', ['gridUtil', function (gridUtil) {...} in initializeGrid: function (grid). Change grid.expandable.expandedAll from false to true

highcharts : set title on exporting

I'm looking a way to:
hide title on the HTML page result
show title on the highcharts graph when I export it (PDF,PNG,JPEG or print)
I don't know how to proceed. There is someone able to help me?
You can define this parameter in exporting.
http://api.highcharts.com/highcharts#exporting.chartOptions
http://jsfiddle.net/BdHJM/
exporting:{
chartOptions:{
title: {
text:'aaaaa'
}
}
},
put this function in your document ready function below is a code for changing highcharts print prototype and just for the patch or to make it work put rangeSelector option in your exporting and set it to false as mentioned below you can set it to your needs in future
Highcharts.wrap(Highcharts.Chart.prototype, 'print', function (proceed) {
var applyMethod = function (whatToDo, margin) {
this.extraTopMargin = margin;
this.resetMargins();
this.setSize(this.container.clientWidth , this.container.clientHeight , false);
this.setTitle(null, { text: 'SET TITLE HERE' :'});
this.rangeSelector.zoomText[whatToDo]();
$.each(this.rangeSelector.buttons, function (index, button) {
button[whatToDo]();
});
};
if (this.rangeSelector) {
var extraMargin = this.extraTopMargin;
applyMethod.apply(this, ['hide', null]);
var returnValue = proceed.call(this);
applyMethod.apply(this, ['show', extraMargin]);
this.setTitle(null, { text: '' });
} else {
return proceed.call(this);
this.setTitle(null, { text: '' });
this.yAxis[0].setExtremes();
} }
});
and in chart option set this (change it according to you need to, i am just putting my code for reference
)
exporting: {
scale: 1,
sourceWidth: 1600,
sourceHeight: 900,
chartOptions: {
rangeSelector: {
enabled: false
},
}

Resources