I have the following code
import React, {Component, useMemo } from "react";
class TimeslotPicker extends Component {
constructor(props) {
super(props);
this.state = {
error: '',
loading: false
};
}
createCalendar(year, month) {
let mon = month - 1; // months in JS are 0..11, not 1..12
let d = new Date(year, mon);
let table = '<div className="row">' +
'<div className="col">MON</div>' +
'<div classNAme="col">TUE</div>' +
'<div className="col">WED</div>' +
'<div className="col">THU</div>' +
'<div className="col">FRI</div>' +
'<div className="col">SAT</div>' +
'<div className="col">SUB</div>' +
'</div><div className="row">';
// spaces for the first row
// from Monday till the first day of the month
// * * * 1 2 3 4
for (let i = 0; i < this.getDay(d); i++) {
table += '<div className="col"></div>';
}
// <td> with actual dates
while (d.getMonth() == mon) {
table += '<div className="col">' + d.getDate() + '</div>';
if (this.getDay(d) % 7 == 6) { // sunday, last day of week - newline
table += '</div><div className="row">';
}
d.setDate(d.getDate() + 1);
}
// add spaces after last days of month for the last row
// 29 30 31 * * * *
if (this.getDay(d) != 0) {
for (let i = this.getDay(d); i < 7; i++) {
table += '<div className="col"></div>';
}
}
// close the table
table += '</div></div>';
return table;
}
getDay(date) { // get day number from 0 (monday) to 6 (sunday)
let day = date.getDay();
if (day == 0) day = 7; // make Sunday (0) the last day
return day - 1;
}
render () {
const calendar = this.createCalendar(2022, 9);
return (
{calendar}
)
}
}
export default TimeslotPicker;
I get the following error when running the code "Objects are not valid as a React child (found: object with keys {calendar}). If you meant to render a collection of children, use an array instead."
What am I doing wrong?
If you return single quotes or say backticks with string interpolation, react treats it as a string and not JSX.
What you can do instead is
let table = (
<div className="row">
<div className="col">MON</div>
<div className="col">TUE</div>
<div className="col">WED</div>
<div className="col">THU</div>
<div className="col">FRI</div>
<div className="col">SAT</div>
<div className="col">SUB</div>
</div>
);
Or, you can use dangerouslySetInnerHTML to render HTML from a string with React
For the first approach here's link to codesandbox
Related
I created a custom element(web component) and using webpack will render without any issues but as I include on the working page(which is a wordpress) on render will show up and at the end of the request to hole rendered element is getting destroyed. I do not get any error in console.
the component looks as it follows
import moment from "moment";
import 'moment/min/moment-with-locales'
moment.locale('de');
export class ToursEvents extends HTMLElement {
constructor() {
super();
//this.attachShadow({mode: 'closed'});
}
connectedCallback() {
this.html = this.innerHTML;
}
get data() {
return this._data;
}
set data(tours) {
let times = tours[0]
this._data = tours[0];
this.vendors = tours[1];
let div = document.createElement("div");
div.innerHTML = `
${times.reduce((acc, item) => `${acc}
<div class="bk_day tours-list__slot">
<div class="bk_date tours-list__date">${moment(item.day).format("dddd")}, ${moment(item.day).format("DD.MM.YYYY")}</div>
<ul class="tours-list__vendors">${ this.makeList(item.times) }</ul>
</div>`
, ``)}`;
this.innerHTML = div.innerHTML
//this.shadowRoot.appendChild(div);
}
makeList(times) {
let list = '';
times.map( (time) => {
const eventId = time.event_id;
const vendor = this.vendors[eventId];
let percentageFree = 0, mark = "", availability ="", workload = typeof(WORKLOAD) !== 'undefined' ? WORKLOAD : 0.8;
let tips = '';
list += '<li data-date="' + time.date + '" data-event-id="' + eventId + '" class="' + mark + '">';
list += '<div class="tours-list__time">' + moment(time.date).format('HH.mm') + ' - ' + moment(time.date).format('HH.mm') +'</div>';
if(vendor.title.includes("Discount")) {
tips += '<div><span class="discount">Spar-tipp!</span></div>';
}
list += '<div class="tours-list__title">' + tips + vendor.title + '</div>';
if(time.available_slots != 0) {
list += '<div class=""><button class=""><span class="bk_info_text">Infos/Tickets</span> <span class="icon-down"></span></button></div>'
} else {
list += '<div class="bk_info"><span>Booked</span></div>'
}
list += '</li>';
});
return list
}
showDetails() {
}
}
customElements.define('tours-events', ToursEvents);
How should I debug this issue?
If you run customElements.define('tours-events', class{}); in the console
and you get undefined you know (WordPress?) redirected you to another page.
If you get a DOM exception the Element IS defined
If your Element is not in the DOM (if that is what you mean with 'destroyed')
you have to step through the console-debugger to find the reason when/why it was removed.
Put a debugger; statement in your element's Constructor and take it from there.
Here are date and time.
Date 2018-05-25T10:35:04.000Z
Expected Output = 3 days 12 hours
I want to display date and time same like as a give above. Currently, I am using moment.js. Is there any way to display like above?
Alternatively to Zvi's suggestion, you could use the AngularJS date filter
Say in your controller you have 2 dates:
app.controller('AppCtrl', function($scope) {
ctrl = this;
ctrl.date1 = new Date("2018-05-22T22:35:04.000Z");
ctrl.date2 = new Date("2018-05-25T10:35:04.000Z");
});
And in HTML, you'd display the difference with the date filter:
{{ctrl.date2 - ctrl.date1 | date:"dd 'days' HH 'hours'"}}
Here's a working JSFiddle example
You can use this moment-precise-range.
Here's full example:
calcDiff = (date : string) => {
let diff_in_string = '';
let original_date = moment(date);
let date_time_now = moment();
let diff_in_object: any = moment-presice.preciseDiffBetweenDates(original_date, date_time_now, true);
if (diff_in_object.days > 0) {
diff_in_string = diff_in_string + diff_in_object.days + ' ';
if (diff_in_object.days === 1) {
diff_in_string += 'Day '
} else {
diff_in_string += 'Days '
}
}
if (diff_in_object.hours > 0) {
if (diff_in_object.days > 0) {
diff_in_string += 'and ' + diff_in_object.hours + ' '
} else {
diff_in_string += diff_in_object.hours + ' '
}
if (diff_in_object.hours === 1) {
diff_in_string += 'Hour '
} else {
diff_in_string += 'Hours '
}
}
diff_in_string += 'ago'
return diff_in_string;
}
You should consider using The HumanizeDuration library (you can check this answer).
It allows you to translate in any language you want the difference between two dates the way you want.
For example :
var yourdate= moment().set({'year': 2018, 'month': 5, 'day': 22});
var today = moment();
var duration = moment.duration(today.diff(yourdate));
var humanized = humanizeDuration(duration, { units: ['d', 'h'], language: language, round: true });
You can also format it with spacers, etc.
What do you have to change so that week start from Monday not Sunday?
I can not post the code here, always get an error message and I do not understand because my English is not so good.
`function calendar() {
// show info on init
showInfo();
// vars
var day_of_week = new Array(
'So','Mo', 'Di',
'Mi', 'Do', 'Fr', 'Sa'),
month_of_year = new Array(
'Januar', 'Februar', 'März',
'April', 'May', 'Juni', 'July',
'August', 'September', 'Oktober',
'November', 'Dezember'),
Calendar = new Date(),
year = Calendar.getYear(),
month = Calendar.getMonth(),
today = Calendar.getDate(),
weekday = Calendar.getDay(),
html = '';
// start in 1 and this month
Calendar.setDate(1);
Calendar.setMonth(month);
// template calendar
html = '<table>';
// head
html += '<thead>';
html += '<tr class="head_cal"><th colspan="7">' + month_of_year[month] +
'</th></tr>';
html += '<tr class="subhead_cal"><th colspan="7">' + Calendar.getFullYear()
+
'</th></tr>';
html += '<tr class="week_cal">';
for (index = 0; index < 7; index++) {
if (weekday == index ) {
html += '<th class="week_event">' + day_of_week[index] + '</th>';
} else {
html += '<th>' + day_of_week[index] + '</th>';
}
}
html += '</tr>';
html += '</thead>';
// body
html += '<tbody class="days_cal">';
html += '</tr>';
// white zone
for (index = 0; index < Calendar.getDay(); index++) {
html += '<td class="white_cal"> </td>';
}
for (index = 0; index < 31; index++) {
if (Calendar.getDate() > index) {
week_day = Calendar.getDay();
if (week_day === 0) {
html += '</tr>';
}
if (week_day !== 7) {
// this day
var day = Calendar.getDate();
var info = (Calendar.getMonth() + 1) + '/' + day + '/' +
Calendar.getFullYear();
if (today === Calendar.getDate()) {
html += '<td><a class="today_cal" href="#" data-id="' +
info + '" onclick="return showInfo(\'' +
info + '\')">' +
day + '</a></td>';
showInfo(info);
} else {
html += '<td><a href="#" data-id="' +
info + '" onclick="return showInfo(\'' +
info + '\')">' +
day + '</a></td>';
}
}
if (week_day == 7) {
html += '</tr>';
}
}
Calendar.setDate(Calendar.getDate() + 1);
} // end for loop
return html;
}`
Codepen
In your day_of_week array change the order of days so that Sunday comes last.
Instead of this:
var day_of_week = new Array('So', 'Mo', 'Di','Mi', 'Do', 'Fr', 'Sa')
Do this:
var day_of_week = new Array('Mo', 'Di','Mi', 'Do', 'Fr', 'Sa', 'So')
Also, you should have a quick read of the help to see how to create links to external sites like Codepen etc (use the question mark '?' in the question editor if you need it). That will help you with things like posting code, links, formatting etc.
Also, when you are linking to an external code site (like Codepen or JSFiddle) you have to include some code in your question or answer as well as the link to the full code.
Update
OK - I see what you mean. Your day of week date does not correctly correspond to the day (as in Jun 3 2017 is a Saturday but showing as a Sunday) after my suggestion.
Because the order of the days changed (ie Monday became the first day of the week), you need to offset your weekday by -1 day.
In your white zone you need to change the first Calendar.getDay() loop from:
for (index = 0; index < Calendar.getDay(); index++)
to:
for (index = 0; index < Calendar.getDay() -1; index++)
That takes care of the first week in the month where there is white-space before the month. Then you need to fix all the other calendar dates. So change the next loop's Calendar.getDay() to offset that too. From this:
week_day = Calendar.getDay();
to this:
week_day = Calendar.getDay() -1;
You should go through the rest of your code and check other months to make sure you are not going to get an invalid date (NaN) because you are decreasing the date by one day.
Update 2
Try this piece of code. This provides a Monday - Sunday calendar and will create the table accordingly. You can easily modify the relevant table cells to include your hook into events and the actual date with styling etc.
If you wanted to you could create the table header with a loop for the days and with a little modification could make the first day of any given week whatever you wanted. I have tested it with each month of this year from Jan through June and the dates work fine.
_('#calendar').innerHTML = calendar();
// short querySelector
function _(s) {
return document.querySelector(s);
}
function calendar() {
var html = '<table><thead><tr>';
html += '<td>Mon</td>';
html += '<td>Tue</td>';
html += '<td>Wed</td>';
html += '<td>Thu</td>';
html += '<td>Fri</td>';
html += '<td>Sat</td>';
html += '<td>Sun</td>';
html += '</tr></thead>';
return html + '<tbody>' + calendarRows(new Date("2017/07/02")) + '</tbody></table>';
}
function calendarRows(dt) {
var html = '';
// Get the number of days in the month
var d = new Date(dt.getFullYear(), dt.getMonth()+1, 0);
var totalDays = d.getDate();
// Get the first day of the month
var f = new Date(dt);
f.setDate(1);
// The first day of the month for the date passed
var firstDayOfMonth = f.getDay();
// The actual date of the month in the calendar
var calendarDate = 1;
// The actual day in any given week. 1 === first day, 7 === last
var dayOfWeek = 1;
while (dayOfWeek < 9 && calendarDate <= totalDays) {
if (dayOfWeek === 8) {
dayOfWeek = 1;
}
// If we are at the start of a new week, create a new row
if (dayOfWeek === 1) {
html += '<tr>';
}
// Process the calendar day
html += '<td>';
// Is this the first day of the month?
if (calendarDate === 1 && firstDayOfMonth === dayOfWeek) {
html += calendarDate;
calendarDate ++;
}
else {
if (calendarDate === 1 || calendarDate > totalDays) {
html += ' ';
}
else {
html += calendarDate;
calendarDate ++;
}
}
html +='</td>';
// Are we at the end of a week?
if (dayOfWeek === 7) {
html += '</tr>';
}
dayOfWeek ++;
}
return html;
}
Hopefully that will work for you. You could always tighten up the code, but I leave that up to you. I've tried to make it easy to modify, but admit I put it together rather quickly to try and help you out.
And if you end up modifying the while loop variables just make sure you don't get yourself into an infinite loop.
Update 3
OK - I have created a Codepen for you that has it working with your formatting. You will still need to make the popup events work and add the relevant code to show events in the calendar. You can also tighten the code up if you need. I left it verbose so you can see what is going on.
_('#calendar').innerHTML = calendar();
// short querySelector
function _(s) {
return document.querySelector(s);
}
// show info
function showInfo(event) {
// Your code in here
}
// toggle event show or hide
function hideEvent(){
_('#calendar_data').classList.toggle('show_data');
}
function calendar() {
//showInfo();
var calDate = new Date("2017/06/02");
var weekdays = new Array( 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So');
var months = new Array(
'Januar', 'Februar', 'März',
'April', 'May', 'Juni', 'July',
'August', 'September', 'Oktober',
'November', 'Dezember');
// Working vars
var d = calDate.getDate(),
m = calDate.getMonth(),
y = calDate.getFullYear(),
day = calDate.getDay(),
today = calDate.getDate();
var html = '<table><thead>';
// Month
html += '<tr class="head_cal"><th colspan="7">' + months[m] + '</th></tr>';
// Year
html += '<tr class="subhead_cal"><th colspan="7">' + y + '</th></tr>';
// Days of week
html += '<tr class="week_cal">';
for (i = 0; i < 7; i++) {
if (today == i) {
html += '<th class="week_event">' + weekdays[i] + '</th>';
} else {
html += '<th>' + weekdays[i] + '</th>';
}
}
html += '</tr>';
html += '</thead>';
// Individual calendar days
html += '<tbody class="days_cal">' + calendarRows(calDate, d, m, y, day, today) + '</tbody></table>';
return html;
}
function calendarRows(calDate, d, m, y, day, today) {
var html = '';
// Get the number of days in the month
var tempDt = new Date(calDate.getFullYear(), calDate.getMonth()+1, 0);
var totalDays = tempDt.getDate();
// Get the first day of the month
tempDt.setDate(1);
var firstDayOfMonth = tempDt.getDay();
// Reset the day to 1 (first day of any month)
d = 1;
// Counter for tracking day of week. 1 === first day, 7 === last
var dayOfWeek = 1;
while (dayOfWeek < 9 && d <= totalDays) {
if (dayOfWeek === 8) {
dayOfWeek = 1;
}
// If we are at the start of a new week, create a new row
if (dayOfWeek === 1) {
html += '<tr>';
}
// Is this the first day of the month?
if (d === 1 && firstDayOfMonth === dayOfWeek) {
html += makeCell(d, m, y, today);
d ++;
}
else {
if (d === 1 || d > totalDays) {
html += '<td> </td>';
}
else {
html += makeCell(d, m, y, today);
d ++;
}
}
// Are we at the end of a week?
if (dayOfWeek === 7) {
html += '</tr>';
}
dayOfWeek ++;
}
return html;
}
function makeCell(d, m, y, today) {
var info = (m + 1) + "/" + d + "/" + y;
var cell = "<td><a href='#' ";
cell += d === today ? "class='today_cal' " : "";
cell += "data-id='" + info + "' onclick=\"return showInfo('" + info + "')\">";
cell += d + "</a></td>";
return cell;
}
If you modularize your code into smaller chunks (like the makeCell()), you will find it is easier to figure out what is going on and it is easier to get your brain around the more complex code problems.
Hope this helps.
Update 4
Updated the same Codepen - I think this fixed your issue, plus you can set the first day of the week to whatever day you want and the calendar should adjust accordingly. Code change was in the CalendarRows function:
function calendarRows(calDate, d, m, y, day, today) {
var html = '';
// Get the number of days in the month
var tempDt = new Date(calDate.getFullYear(), calDate.getMonth()+1, 0);
var totalDays = tempDt.getDate();
// Get the first day of the month
tempDt.setDate(1);
var firstDayOfMonth = tempDt.getDay();
// Reset the day to 1 (first day of any month)
d = 1;
// Weekdays are 0 === Sunday, 6 === Saturday
var firstDayOfWeek = 1, // <-- this means weeks start on Monday
lastDayOfWeek = 0, // <-- this measn Sunday
dayOfWeek = firstDayOfWeek,
safety = 0,
endLoop = false;
while (endLoop === false) {
safety ++;
if ((dayOfWeek === firstDayOfWeek && d > totalDays) || safety === 50) {
if (safety === 50) console.error("Infinite loop safety break");
break;
}
// If we are at the start of a new week, create a new row
if (dayOfWeek === firstDayOfWeek) {
html += '<tr>';
}
// Is this the first day of the month?
if (d === 1 && firstDayOfMonth === dayOfWeek) {
html += makeCell(d, m, y, today);
d ++;
}
else {
if (d === 1 || d > totalDays) {
html += '<td> </td>';
}
else {
html += makeCell(d, m, y, today);
d ++;
}
}
// Are we at the end of a week?
if (dayOfWeek === lastDayOfWeek) {
html += '</tr>';
}
// Add a day to the current day counter
dayOfWeek ++;
// If we get to Saturday, reset the next day to Sunday
if (dayOfWeek === 7)
dayOfWeek = 0;
}
return html;
}
In my app I have a drop-down for booking an appointment with psychiatrist. Here the user gives the input as minutes, to talk to the doctor,so in drop-down it should look like a normal timings like 9-10 am, 10-11pm so on till 5pm, so the customer can see the available timing to book the appointment. I'm struggling to get this time split. I have done only the conversion from mins to hours and after that Im struck with the time split.Hoping for some help here, or any valid guidance for proceeding to get the time split.
Controller:
myApp.controller('ctrl', function ($scope) {
$scope.calc = function () {
var time = $scope.timeSelect;
if (time < 60) {
var a = (time) + 'm';
} else if (time % 60 == 0) {
var a = (time - time % 60) / 60 + 'h';
} else {
var a = ((time - time % 60) / 60 + 'h' + ' ' + time % 60 + 'm');
}
$scope.result =a;
}
$scope.result='';
});
Whenever you are dealing with dates and times I highly recommend using Momentj.js. Here is an extremely contrived example to demonstrate how you might use Moment.js to set your time periods.
angular.module("app", ["angularMoment"])
.controller("ctrl", function($scope, moment) {
var startingTime = moment().hours(9).minutes(0);
var endingTime = moment().hours(17).minutes(0);
$scope.selectedTimeslot = "";
$scope.intervals = [15, 30, 45, 60, 90, 120];
$scope.interval = 60;
$scope.timeslots = [];
$scope.setTimeSlots = function() {
$scope.timeslots = [];
var currentStartTime = angular.copy(startingTime); // use copy to avoid reference issues since we're dealing with objects and not primitives
while (currentStartTime < endingTime) {
$scope.timeslots.push(currentStartTime.format("h:mm") + " - " + currentStartTime.add($scope.interval, "minute").format("h:mm"));
}
}
$scope.setTimeSlots();
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.16.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-moment/1.0.0/angular-moment.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
Interval in minutes: <select ng-model="interval" ng-change="setTimeSlots()" ng-options="i for i in intervals"></select>
<br/>Timeslots:
<select ng-model="selectedTimeslot" ng-options="slot for slot in timeslots">
<option value="">Please select</option>
</select><br/><br/>
Selected timeslot: {{selectedTimeslot}}
</div>
This might work for you:
function createTimeSlots(startHour, endHour, interval) {
if (!startHour) {
endHour = 8;
}
if (!endHour) {
endHour = 20;
}
var timeSlots = [],
dateTime = new Date(),
timeStr = '';
dateTime.setHours(startHour, 0, 0, 0);
while (new Date(dateTime.getTime() + interval * 60000).getHours() < endHour) {
timeStr = dateTime.getHours() + ':' + dateTime.getMinutes();
timeStr += '-';
dateTime = new Date(dateTime.getTime() + interval * 60000);
timeStr += dateTime.getHours() + ':' + dateTime.getMinutes();
timeSlots.push(timeStr);
}
return timeSlots;
}
console.log(createTimeSlots(9, 18, 45));
"9:0-9:45",
"9:45-10:30",
"10:30-11:15",
"11:15-12:0",
"12:0-12:45",
"12:45-13:30",
"13:30-14:15",
"14:15-15:0",
"15:0-15:45",
"15:45-16:30",
"16:30-17:15"
You might wanna add some 0 padding on the getHours() and getMinutes() so that 1:0 will be printed as 01:00.
From the question I get a rough idea of what you need, so I hope this helps you on your way. First, I would make a separate function to convert a time (in number of minutes from midnight, as an easy example) to a string, like this:
function timeToString(time) {
if (time < 12 * 60)
return (time - time % 60) / 60 + ":" + time % 60 + "am";
else return (time - time % 60 - 12*60) / 60 + ":" + time % 60 + "pm";
}
Then the array to fill the drop-down can be created like this:
var times = [];
for (t = startHour * 60; t < endHour * 60; t += duration) {
times[times.length] = timeToString(t) + ' - ' + timeToString(t + duration);
}
I have a situation where I have a variable number of objects in an array, and I need to create groups of three. I know that to iterate over an array I can do something like this (Fiddle - https://jsfiddle.net/o5pbttjq/):
render: function() {
var random = Array.apply(null, Array((Math.floor(Math.random() * (15 - 1) + 1) + 1))).map(Number.prototype.valueOf,0).map(function(d,i) {return i});
return (
<div>
{random.map(function(d) {
return <p>{d}</p>
})}
</div>
);
}
I can also group them like so, but it's quite ugly (Fiddle - https://jsfiddle.net/Lxqm3tzo/):
render: function() {
var random = Array.apply(null, Array((Math.floor(Math.random() * (15 - 1) + 1) + 1))).map(Number.prototype.valueOf,0).map(function(d,i) {return i});
var content = "<div>";
random.forEach(function(d, i) {
if (i % 3 === 0 && i !== 0) {
content += "</div><div>"
}
content += "<p>" + d + "</p>"
})
content += "</div>"
return (
<div dangerouslySetInnerHTML={{__html: content}}></div>
);
}
How can I create groups of a variable number of objects with JSX?
The following will work without having to set the innerHTML. See the fiddle here: https://jsfiddle.net/kuvvd513/8/
var Hello = React.createClass({
render: function() {
var random = Array.apply(null, Array((Math.floor(Math.random() * (15 - 1) + 1) + 1))).map(Number.prototype.valueOf,0).map(function(d,i) {return i});
var allGroups = [];
var group = [];
random.forEach(function(d, i) {
if (i % 3 === 0 && i !== 0) {
allGroups.push(<div> {group} </div>);
group = [];
}
group.push(<p> {d} </p>);
}.bind(this));
allGroups.push(<div> {group} </div>);
return (
<div>
{allGroups}
</div>
);
}
});
React.render(<Hello name="World" />, document.getElementById('container'));