Angular not detecting change to first element in array - arrays

I'm trying to display a list of dates for the current week in an Angular app. I want to allow users to view previous weeks at the click of a button, so I'm using an Observable to update the array of dates, and attempting to display the updated array.
All items are updated in the view, except for the first item in the array. Plunker example here
I've tried using *ngFor and the async pipe, as well as explicitly creating elements for each item in the array (like below). Both have the same issue. I'm struggling to find a solution.
//our root app component
import {Component, NgModule, VERSION} from '#angular/core'
import {BrowserModule} from '#angular/platform-browser'
import 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
#Component({
selector: 'my-app',
template: `
<button (click)="previousWeek()">Prev Week</button>
<div>{{dates[0]}}</div>
<div>{{dates[1]}}</div>
<div>{{dates[2]}}</div>
`,
})
export class App {
name:string;
dates: Date[];
public $datesSource: Observable<Date[]>;
private datesSource: Subject<Date[]>;
constructor() {
this.datesSource = new Subject<Date[]>();
this.datesSource$ = this.getDatesWithObservable();
this.datesSource$.subscribe((dates) => {
console.log(dates);
this.dates = dates;
})
this.setDates(new Date());
}
setMonday(date: Date): Date {
const day = date.getDay() || 7;
if (day !== 1) {
date.setHours(-24 * (day - 1));
}
return date;
}
setDates(date: Date): void {
const dates = [
new Date(),
new Date(),
new Date(),
new Date(),
new Date(),
new Date(),
new Date()
];
const monday = this.setMonday(date);
dates[0] = monday;
const mondayDate = monday.getTime();
dates.forEach((date, idx) => {
console.log(idx);
date.setTime(monday.getTime() + (idx * 24 * 60 * 60 * 1000));
});
this.addDates(dates);
}
addDates(dates: Date[]): void {
this.datesSource.next(dates);
}
getDatesWithObservable(): Observable<Date[]> {
return this.datesSource.asObservable();
}
previousWeek(): void {
const day = this.dates[0].getDay() || 7;
const lastWeek = this.dates[0];
const days = 7;
lastWeek.setTime(lastWeek.getTime() - (days * 24 * 60 * 60 * 1000));
this.setDates(lastWeek);
}
}

try this , i commented the line in the middle and it's working, can you check:
const monday = this.setMonday(date);
//dates[0] = monday;
const mondayDate = monday.getTime();

Related

Prime ng calendar UTC

I am receiving from the server a date in UTC format (as a string) = "2020-04-01T00:00:00Z".
When my users are visiting the calendar here in the UK (gmt) they can see it fine. However my users in the USA of course see the calendar pre-selecting 31st March.
How can I make my users in the USA also see the calendar pre-selecting 1st April?
I'm aware that PrimeNG removed the UTC="true" attribute.
See if this works:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
dates: UTCDate[] = [];
days: UTCDate[] = [];
constructor() {
for (var i = 0; i < 24; i+= 3) {
this.dates.push(new UTCDate(new Date(Date.UTC(2018, 0, 1, i))));
}
for (var j = 1; j < 28; j+= 3) {
this.days.push(new UTCDate(new Date(Date.UTC(2018, 0, j))));
}
}
}
class UTCDate {
private boundDateBacker: Date;
constructor(private dateInstance: Date) {
this.boundDateBacker = this.utcToLocal(dateInstance);
}
public get boundDate(): Date {
return this.boundDateBacker;
}
public set boundDate(value: Date) {
if (value) {
this.dateInstance.setTime(this.localToUtc(value).getTime());
const newTime = value.getTime();
if (newTime !== this.boundDateBacker.getTime()) {
this.boundDateBacker.setTime(newTime);
}
}
}
private localToUtc(date: Date): Date {
return new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()));
}
private utcToLocal(date: Date): Date {
return new Date(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
}
}
I didn't write it, I found it while looking for a solution to the utc issue. I haven't tested it because I don't need to implement timezone support yet, but thought you could have a look at this solution and maybe find what you are looking for.
I'm thinking the logic there could be used inside a directive, instead of a separate class.
StackBlitz

Display current date calendar react?

I am building a calendar, it has 53 weeks from (12-30-2019 -> 03-01-2021). How when the app first loads it display current date.
// the function display dates
export default function RenderDates(props) {
const dates_ = [];
const startDate = moment('12-29-2019', 'MM-DD-YYYY');
// display date in week
for(let i = 1; i <= 53*7; i++) {
dates_.push(
<Date>
<ContentDate>
<ShortDate>{moment.weekdaysShort()[i%7]}</ShortDate>
<span>{startDate.add(1,'days').get('Date')}</span>
</ContentDate>
</Date>
)
}
return dates_;
}
demo: https://codesandbox.io/s/github/Kalipts/scroll_calendar?file=/src/components/RenderDates.js
You can assign unique id to every date box and then focus today's box
https://codesandbox.io/s/quirky-leavitt-w2x3w
export default function RenderDates(props) {
const dates_ = [];
const startDate = moment("12-29-2019", "MM-DD-YYYY");
useEffect(() => {
const today = moment().format("YYYY-MM-DD");
console.log('today', today);
const node = document.getElementById(today);
if (node) {
node.setAttribute("tabindex", "-1");
node.focus();
node.removeAttribute("tabindex");
}
}, []);
for (let i = 1; i <= 53 * 7; i++) {
const date = startDate.add(1, "days");
dates_.push(
<Date id={date.format("YYYY-MM-DD")}>
<ContentDate>
<ShortDate>{moment.weekdaysShort()[i % 7]}</ShortDate>
<span>{date.get("Date")}</span>
</ContentDate>
</Date>
);
}
return dates_;
}
I just changed a bit your codesandbox to make it work and here is the link: https://codesandbox.io/s/vibrant-worker-b2xhq?file=/src/App.js
Basically what I did was:
On your RenderDates component I check for the current date and added an id to the Date component if that date was the current one.
On App component (It could be on RenderDates component) I added a useEffect to run once the component is mounted that getElementById using the id on date and scrollIntoView.
It is very simple and works well! :)

Limit react-day-picker range to x days

I want to limit the range length in react-day-picker to e.g. 10 days. How should this be done, is something availlable in the package already?
This is an example range selector: https://react-day-picker.js.org/examples/selected-range/
Could be easily implemented, I've just added some lines to the handleDayClick function:
Instead of this:
handleDayClick(day) {
const range = DateUtils.addDayToRange(day, this.state);
this.setState(range);
}
Implement this:
handleDayClick(day) {
const oneDay = 24 * 60 * 60 * 1000; // hours*minutes*seconds*milliseconds
const diffDays = Math.round(Math.abs((day - this.state.from) / oneDay));
const range = DateUtils.addDayToRange(day, undefined);
if(diffDays <= 10){
const range = DateUtils.addDayToRange(day, this.state);
this.setState(range);
}
else {
this.setState(range);
}
}

Chart .dimension(...).group(...).columns is not a function (d3.js v4.2.8, dc.js, React)

After building a dc.js data table in d3 v3 looking to build the same data table in d3 v4.2.8 (did it for the line chart,please see DC.js to React conversion ) .Keep getting the error bitRateTableChart.dimension(...).group(...).columns is not a function(…). It seems that the columns are not being defined properly. The code of TableChart.js:
import React, { PropTypes } from 'react';
import ReactDOM from "react-dom";
import * as d3 from 'd3';
import dc from "dc";
import * as crossfilter from 'crossfilter';
import {Jumbotron } from 'react-bootstrap';
import functionDCHelper from './functionDCHelper';
import {scaleTime, scaleLinear} from 'd3-scale';
class TableChart extends React.Component {
componentDidMount() {
var bitRateTableChart = dc.compositeChart(this.refs.tableChart);
var dateDimension = functionDCHelper.generateValues(this.props.data);
bitRateTableChart /* dc.dataTable('.dc-data-table', 'chartGroup') */
.dimension(dateDimension) // .dimension(dateDimension)
// Data table does not use crossfilter group but rather a closure as a grouping function
.group(function (d) {
var format = d3.format('02d');
return d.bitdate.getFullYear() + '/' + (d.bitdate.getMonth() ); //+ 1
})
// (_optional_) max number of records to be shown, `default = 25`
.columns([
'CHANNEL_ID',
'BITRATE'
])
.ordering(function (d ) { return d.bitdate; })
// (_optional_) custom renderlet to post-process chart using [D3](http://d3js.org)
.on('renderlet', function (table) {
// d3.select(.tableChart).selectAll('.info');
})
// .size(15)
bitRateTableChart.render();
}
render() {
return( <div ref="tableChart">
</div>)
}
}
export default TableChart;
The code of functionDcHelper.js:
import crossfilter from 'crossfilter';
import * as d3 from 'd3';
import dc from 'dc';
var minDate,min15,bitrateWeekMinIntervalGroupMove,maxDate,minIntervalWeekBitrateGroup,dateDimension,dateFormat,numberFormat,maxbit;
function nonzero_min(chart) {
dc.override(chart, 'yAxisMin', function () {
var min = d3.min(chart.data(), function (layer) {
return d3.min(layer.values, function (p) {
return p.y + p.y0;
});
});
return dc.utils.subtract(min, chart.yAxisPadding());
});
return chart;
}
// 15 Min Interval - copied from https://github.com/mbostock/d3/blob/master/src/time/interval.js
var d3_date = Date;
function d3_time_interval(local, step, number) {
function round(date) {
var d0 = local(date), d1 = offset(d0, 1);
return date - d0 < d1 - date ? d0 : d1;
}
function ceil(date) {
step(date = local(new d3_date(date - 1)), 1);
return date;
}
function offset(date, k) {
step(date = new d3_date(+date), k);
return date;
}
function range(t0, t1, dt) {
var time = ceil(t0), times = [];
if (dt > 1) {
while (time < t1) {
if (!(number(time) % dt)) times.push(new Date(+time));
step(time, 1);
}
} else {
while (time < t1) times.push(new Date(+time)), step(time, 1);
}
return times;
}
function range_utc(t0, t1, dt) {
try {
d3_date = d3_date_utc;
var utc = new d3_date_utc();
utc._ = t0;
return range(utc, t1, dt);
} finally {
d3_date = Date;
}
}
local.floor = local;
local.round = round;
local.ceil = ceil;
local.offset = offset;
local.range = range;
var utc = local.utc = d3_time_interval_utc(local);
utc.floor = utc;
utc.round = d3_time_interval_utc(round);
utc.ceil = d3_time_interval_utc(ceil);
utc.offset = d3_time_interval_utc(offset);
utc.range = range_utc;
return local;
}
function d3_time_interval_utc(method) {
return function (date, k) {
try {
d3_date = d3_date_utc;
var utc = new d3_date_utc();
utc._ = date;
return method(utc, k)._;
} finally {
d3_date = Date;
}
};
}
// generalization of d3.time.minute copied from- https://github.com/mbostock/d3/blob/master/src/time/minute.js
function n_minutes_interval(nmins) {
var denom = 6e4 * nmins;
return d3_time_interval(function (date) {
return new d3_date(Math.floor(date / denom) * denom);
}, function (date, offset) {
date.setTime(date.getTime() + Math.floor(offset) * denom); // DST breaks setMinutes
}, function (date) {
return date.getMinutes();
});
}
min15 = n_minutes_interval(15);
dateFormat = d3.timeFormat('%Y/%m/%d/%H:%M');
//dateFormat = d3.timeParse ('%Y/%m/%d/%H:%M');
// parse the date / time
//var dateFormat = d3.timeParse("%d-%b-%y");
numberFormat = d3.format('d');
//### Crossfilter Dimensions
function generateValues(data) {
data.forEach(function (d) {
d.bitdate = new Date(d.DATETIME); //d.DATETIME = dateFormat.parse(d.DATETIME);
// d.month = d3.time.month(d.bitdate);
// d.week = d3.time.week(d.bitdate);
d.BITRATE = String(d.BITRATE).match(/\d+/); //d.BITRATE = +d.BITRATE;
});
var crossFilteredData = crossfilter(data);
var all = crossFilteredData.groupAll();
// Dimension by full date
dateDimension = crossFilteredData.dimension(function (d) {
return d.bitdate;
});
maxbit = d3.max(data, function (d) { return +d["BITRATE"]; }); //alert(maxbit);
//Group bitrate per week, 15 minInterval - maintain running tallies
bitrateWeekMinIntervalGroupMove = dateDimension.group(min15).reduce(
/* callback for when data is added to the current filter results */
function (p, v) {
++p.count;
p.BITRATE = +v.BITRATE;
p.total += +v.BITRATE;
p.avg = p.count ? Math.round(p.total / p.count) : 0;
return p;
},
/* callback for when data is removed from the current filter results */
function (p, v) {
--p.count;
p.BITRATE = +v.BITRATE;
p.total -= +v.BITRATE;
p.avg = p.count ? Math.round(p.total / p.count) : 0;
return p;
},
/* initialize p */
function () {
return {
count: 0,
bitrate: 0,
total: 0,
avg: 0
};
}
);
try {
minDate = dateDimension.bottom(1)[0].DATETIME;
} catch(err) {
minDate = new Date("2016-06-14 0:00");
}
try {
maxDate = dateDimension.top(1)[0].DATETIME;
} catch(err) {
maxDate = new Date("2016-06-18 23:55");
}
return {
min15, minDate, maxDate, bitrateWeekMinIntervalGroupMove,minIntervalWeekBitrateGroup, dateDimension, maxbit
};
}
export default {
generateValues,
nonzero_min,
dateFormat,
numberFormat
};
Any help would be appreciated.
Following Gordon's answer here is the current code for the dataTable (dc.js,crossfilter, d3 v4.2.8 ,React,):
import React, { PropTypes } from 'react';
import ReactDOM from "react-dom";
import * as d3 from 'd3';
import dc from "dc";
import * as crossfilter from 'crossfilter';
import {Jumbotron } from 'react-bootstrap';
import functionDCHelper from './functionDCHelper';
import {scaleTime, scaleLinear} from 'd3-scale';
class TableChart extends React.Component {
componentDidMount() {
var bitRateTableChart = dc.dataTable(this.refs.tableChart);
var { dateDimension } = functionDCHelper.generateValues(this.props.data);
bitRateTableChart
.dimension(dateDimension)
// Data table does not use crossfilter group but rather a closure as a grouping function
.group(function (d) {
var format = d3.format('02d');
return d.bitdate.getFullYear() + '/' + format((d.bitdate.getMonth() + 1));
})
.columns(
[
'DATETIME',
'CHANNEL_ID',
'BITRATE'
])
.ordering(function (d ) { return d.bitdate; }) /// sortBy(function (d) { return d.bitdate; })
// (_optional_) custom renderlet to post-process chart using [D3](http://d3js.org)
.on('renderlet', function (table) {
table.selectAll('.dc-table-group').classed('info', true);
})
.size(15)
bitRateTableChart.render();// dc.renderAll();
}
render() {
return(
<div className="row">
<div className="table table-hover dc-data-table dc-table-row" ref="tableChart">
</div>
</div>
)
}
}
export default TableChart;

How to change view date dynamically (which is filter event by date time)

I Want to filter event by date but date is pass by normal input type="text" not kendo default datepicker.And display passing date in kendo schduler header But cant not change view date.This is my code.........
$scope.searchEventByDate = function (item) {
var scheduler = $("#scheduler").data("kendoScheduler");
scheduler.view().startDate(item.StartDate);
scheduler.view().endDate(item.EndDate);
scheduler.view(("day"));
$scope.scheduler.dataSource.read();
};
This is my filter param
parameterMap: function (options, operation) {
var popupheight = $(window).height() - 180 + 'px';
$scope.popupWraperForTryout = popupheight;
var scheduler = $("#scheduler").data("kendoScheduler");
if (searchCount != 0) {
if (operation === "read") {
return {
filterByPersonalEvent: $scope._filterParamObj.filterBypersonal,
filterBySignUpRequired: $scope._filterParamObj.filterBySingupRequired,
filterByPaidOrFree: $scope._filterParamObj.filterByPaid,
filterByEventStatus: $scope._filterParamObj.eventStatusId,
filterByEventType: $scope._filterParamObj.eventTypeId,
selectedTeam: $scope._filterParamObj.seasonTeamId,
filterByStartDate: scheduler.view().startDate(),
filterByEndDate: scheduler.view().endDate(),
OrgId: _orgId,
UserTimezone: global.userTimezoneOffset
}
}
}
},
I am so tired.This code is not change in view date.Please help me
Several issues here - the day view shows just one day; you can't set startDate and endDate - just date.
$scope.searchEventByDate = function (item) {
var scheduler = $("#scheduler").data("kendoScheduler");
//scheduler.view().startDate(item.StartDate);
//scheduler.view().endDate(item.EndDate);
scheduler.view("day");
// item.StartDate should be Date object - like scheduler.date(new Date("2013/6/6"));
scheduler.date(item.StartDate);
$scope.scheduler.dataSource.read();
};
If you need to set some explicit date range to filter - you can do it, but still you can't show more than just one day in day view.
$scope.searchEventByDate = function (item) {
var scheduler = $("#scheduler").data("kendoScheduler");
scheduler._myFilterStartDate = item.StartDate;
scheduler._myFilterEndDate = item.EndDate;
scheduler.view("day");
scheduler.date(item.StartDate);
$scope.scheduler.dataSource.read();
};
And in parameter map:
...
return {
filterByStartDate: scheduler.view().startDate(),
filterByEndDate: scheduler.view().endDate(),
myFilterStartDate: scheduler._myFilterStartDate,
myFilterEndDate: scheduler._myFilterEndDate,
OrgId: _orgId,
UserTimezone: global.userTimezoneOffset
};
...

Resources