I wrote simple script that make an object from some formatted text. It works, but for me, it seems a little complicated. May be you can advise more a simpler way?
let myText = document.getElementById('element').innerText; //get text from div
let myObj = {};
let arrText = myText.replaceAll('\n', '').split(';') //split text
let monthesCodes = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
arrText.forEach(element => {
for (let i = 0; i < 12; i++) {
if (element.includes(monthesCodes[i])) {
let arrString = element.split(' – ') //split line one by one by '-'
if (!myObj.hasOwnProperty(i + 1)) { //if there are no key with month nomber in object - create it
myObj[i + 1] = {}
}
let keyDay = arrString[0].replace(' ' + monthesCodes[i], '').replaceAll('and', ',') //left only numbers and delimeters in left part of string
if (keyDay.includes(',')) { //if the left part have delimeters write in sub-object a key (number) with the value as name of the holiday
for (let keyDays of keyDay.split(',')) {
myObj[i + 1][+keyDays] = arrString[1];
}
} else { //else if we have only one number in left string
myObj[i + 1][keyDay] = arrString[1];
}
}
}
});
console.log(myObj)
<body>
<div id="element">
<br>1, 2, 3, 4, 5, 6 and 8 January – NY hollidays;
<br>7 January – Orthodox Christmas;
<br>23 February – Man's day;
<br>8 March – Woman's Day;
<br>1 May – Labor Day;
<br>9 May – Memorial Day;
<br>12 June – Country Day;
<br>4 November – People uniting day
</div>
</body>
Output
{
"1": {
"1": "NY hollidays",
"2": "NY hollidays",
"3": "NY hollidays",
"4": "NY hollidays",
"5": "NY hollidays",
"6": "NY hollidays",
"7": "Orthodox Christmas",
"8": "NY hollidays"
},
"2": {
"23": "Man's day"
},
"3": {
"8": "Woman's Day"
},
"5": {
"1": "Labor Day",
"9": "Memorial Day"
},
"6": {
"12": "Country Day"
},
"11": {
"4": "People uniting day"
}
}
I think that separating the part of the code where you get the info from the strings from the part where this gets organised into the object should help in understanding as you can focus more on the details of what each part is doing:
const event_listings = document.getElementById('element').innerText
.replaceAll('\n', '').split(';');
const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
const parse_event_listing = (string) => {
const [date_info, title] = string.split(' – ');
let date_parts = date_info.replace(/,/g, '').replace(' and', '').split(' ');
const month = date_parts.pop();
return [months.indexOf(month) + 1 + '', date_parts, title];
};
const myObj = event_listings
.map(parse_event_listing)
.reduce(
(acc, [month, days, title]) => Object.assign(acc, {
[month]: Object.assign(
acc[month] || {},
Object.fromEntries(days.map((d) => [d, title]))
)
}), {}
);
console.log(myObj);
<body>
<div id="element">
<br>1, 2, 3, 4, 5, 6 and 8 January – NY hollidays;
<br>7 January – Orthodox Christmas;
<br>23 February – Man's day;
<br>8 March – Woman's Day;
<br>1 May – Labor Day;
<br>9 May – Memorial Day;
<br>12 June – Country Day;
<br>4 November – People uniting day
</div>
</body>
Here's another way that uses reduce(), filter(), some simple regex and array manipulation. The benefit (I think) is one: it spits out the data in 2 different usable formats and two: it is easier to read
It first compiles a tidy array of objects, each having
{
month: month name,
event: event name,
dates: list of dates associated
}
That might be useful to have the data in that format. But it then takes that and runs it through a map() to format it the way you have in your example.
let myText = document.getElementById('element').innerText; //get text from div
let arrText = myText.replaceAll('\n', '').split(';') //split text
let months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
let event_list = arrText.reduce((acc, a) => {
let nums = a.replace("and", ",").replace(/[^,\d.-]/g, "").split(",");
let month = months.filter(m => a.includes(m));
let event = a.split("–")[1].trim();
acc.push({
event: event,
month: month[0],
dates: nums.join(",")
});
return acc;
}, []);
console.log(event_list)
// now the same format you have
let event_list2 = {};
event_list.map(obj => {
let monthnum = months.indexOf(obj.month) + 1;
if (!event_list2.hasOwnProperty(monthnum)) event_list2[monthnum] = {};
obj.dates.split(",").forEach(dt => event_list2[monthnum][dt] = obj.event);
})
console.log(event_list2)
<div id="element">
<br>1, 2, 3, 4, 5, 6 and 8 January – NY hollidays;
<br>7 January – Orthodox Christmas;
<br>23 February – Man's day;
<br>8 March – Woman's Day;
<br>1 May – Labor Day;
<br>9 May – Memorial Day;
<br>12 June – Country Day;
<br>4 November – People uniting day
</div>
Related
I have a string like "August 24th, 2020" that I need to convert into the "Date" type in Angular. Is there any simple way to do this please?
I've tried this:
const deadline = new Date ("August 24th, 2020")
But that results in "Invalid Date".
Maybe moment.js is capable to parse that outside of the box, however, if you're not willing to attach external library and maintain its compatibility to the rest of your environment for this purpose only, you may parse that yourself:
const dateStr = "August 24th, 2020",
parseDate = s => {
const [, month, dd, yyyy] = s.match(/([a-z]+)\s(\d+)[a-z]+,\s(\d+)/i)||[],
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
return new Date(Date.UTC(yyyy, months.indexOf(month), dd))
}
console.log(parseDate(dateStr))
I am trying to control "Month" and "Year" in drop down list. I am having two fields, "Start Date" and "End Date". In that "Start Date" I am listing the "Current Month" and "Year" like "March 2020". I want to control my "End Date" based of "Start Date". For example if there is no "Month" selected in "Start Date" I should not allow user to select the "End Date". If user select's "MAY 2020" in "Start Date" and in "End Date" I want to display from "May 2020 to next May 2021". Like wise if user select's "June 2020" in "Start Date" and in "End Date" I want to display from "June 2020 to next June 2021". As of now I am displaying the current month and year in both Start and End date. Any one can guide me to achieve this. Thanks in Advance. Below is the code where I am getting current year month to next year.
const fareMon = () => {
const monthList = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
const currDate = new Date();
const year = currDate.getFullYear();
const months = [];
let currentMonthIndex = currDate.getMonth();
let yearsToAdd = 0;
for (let i = 0; i < 13; i += 1) {
if (currentMonthIndex === 12) {
currentMonthIndex = 0;
yearsToAdd += 1;
}
const futYear = year + yearsToAdd;
months.push(<option value={`${monthList[currentMonthIndex]} ${futYear}`}>{`${monthList[currentMonthIndex]} ${futYear}`}</option>);
currentMonthIndex += 1;
}
return <>{months}</>;
};
So, what I have done is, created a getFullYear function, where you can pass year and you will get all the months
Does this help:
const monthList = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
const getFullYear = (year) => {
const currentDate = new Date(`01 01 ${year}`);
const monthYear = [];
for(;currentDate.getFullYear() === year;){
const currentMonth = currentDate.getMonth();
monthYear.push(`${monthList[currentMonth]} ${year}`)
const nextMonth = currentMonth+1;
currentDate.setMonth(nextMonth);
}
return monthYear;
}
More cleaner and less compute intensive approach would be:
const monthList = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
const getYear = (year) => {
return monthList.map((month) => `${month} ${year}`);
}
I am wanting true or false return when using includes to see if the current month using moment().format('MMMM') is also in an array.
const splitMonths = ['April', 'May', 'June', 'July', 'August', 'September'];
const currentDate = moment().format('MMMM');
const seasonData = currentDate.includes(splitMonths);
console.log(seasonData);
The above returns false and I cannot understand why.
If I change splitMonths to splitMonths = ['May']; it will return true.
If I run console.log(currentDate) it returns May.
Why isn't this returning true?
You are checking array existence within the string currentDate.includes(splitMonths);. Instead it should be splitMonths.includes(currentDate);
const splitMonths = ['April', 'May', 'June', 'July', 'August', 'September'];
const month = "May";
const seasonData = splitMonths.includes(month);
console.log(seasonData);
hello my question is how to get last four months records from database.i got the output but not getting my expected pattern so how to do this can any one help me to solve this.
db.Air_pollution.aggregate([
{$match:
{CREATE_DATE:{$lte:new Date(),
$gte:new Date(new Date().setDate(new
Date().getDate()-120))}}},
{
$group:
{
_id:{month:{$month:"$CREATE_DATE"},
year:{$year:"$CREATE_DATE"}
},
avgofozone:{$avg:"$OZONE"}
}
},
{
$sort:{"year":-1}
},
{
$project:{
year:'$_id.year',
avgofozone:'$avgofozone',
month:'$_id.month',_id:0
}
}
])
Output is:
{ "avgofozone" : 21.07777777777778, "year" : 2018, "month" : 2 }
{ "avgofozone" : 17.8, "year" : 2018, "month" : 3 }
{ "avgofozone" : 17.8, "year" : 2018, "month" : 1 }
Expected output:
zone_type year january febravary march
avgofozone 2018 17.8 21.07777 17.8
You already have the data you need, rather than trying to get it exactly how you need it from MongoDB, why not just format it in the application layer?
Some simple JavaScript to do that:
const months = [
'January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September',
'October', 'November', 'December'
];
function monthNumToName(monthnum) {
return months[monthnum - 1];
}
const results = [{
"avgofozone": 21.07777777777778,
"year": 2018,
"month": 2
}, {
"avgofozone": 17.8,
"year": 2018,
"month": 3
}, {
"avgofozone": 17.8,
"year": 2018,
"month": 1
}];
const statsByYear = results.reduce((a, c) => {
const {
year,
month,
avgofozone
} = c;
if (!a[year])
a[year] = {
zone_type: 'avgofozone',
year,
[monthNumToName(month)]: avgofozone
}
else a[year][monthNumToName(month)] = avgofozone
return a;
}, {});
const formatted = Object.keys(statsByYear).map(k => {
return statsByYear[k];
});
console.log(formatted);
Is it possible to parse in ng-repeat a array value into a string? I'll explain what I mean.
<tr ng-repeat="(key,property) in obj.properties">
<td>{{key}}</td>
<td>{{property}}</td>
</tr>
This {{property}} is an array e.g [ 7 , 8 ], but I would like to show "Jully - August". Is it possible through a filter? Or I need to parse it in the controller.
Use filter convert number to name of month:-
<td>{{property|monthName}}</td>
app.filter('monthName', [function() {
return function (monthNumber) {
//1 = January
var monthNames = [ 'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December' ];
var nameList="";
for(var i=0;i<monthNumber.length;i++){
if(i==monthNumber.length-1){
nameList+=monthNames[monthNumber[i] - 1];
}else{
nameList+=monthNames[monthNumber[i] - 1]+"-";
}
}
return nameList;
}
}]);
Plunker
You can do it as well
<td>{{property|showMonthName}}</td>
app.filter('showMonthName', function() {
return function (months) {
var monthNames = [ 'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December' ];
months = months.map(function(i){
return monthNames[i-1];
});
return months.join(' - ');
}
});
So I tried this in my own system. I created one filter and applied inside ng-repeat. It works perfectly. You can modify your own filter based on this one.
<test-directive keyword = "view.ctrlKeywordinput" ng-repeat="movie in [1,2]" ><div> {{movie | monthfilter}}</div></test-directive>
and here is my filter:
app.filter("monthfilter", function(){
return function(input){
switch(input){
case 1:
return "january";
break;
case 2:
return "february";
break;
}
};
});