Object Oriented JavaScript: How would you go about this? - javascript

As I've gotten to know JS better, I've moved from a procedural style to semi-OO (don't ask me what I mean by that: a mess basically!) but now I want to start using it properly. OO appeals to my coding-brain.
However, I'm trying to develop a library of school weeks, and I'm not sure how I'd best go about it.
If I was to simply use an array of weeks, they would look something like this:
WeeksArray[36].StartDate = "2011-09-05";
WeeksArray[36].EndDateSchool = "2011-09-09";
WeeksArray[36].EndDateProper = "2011-09-11";
WeeksArray[36].JSDate = new Date ( 2011, 8, 05 );
WeeksArray[36].Type = "1";
WeeksArray[36].Label = "Week 36: 5th Sept 2011";
Key: Week number according to School Calendar
StartDate / EndDate: MySQL-compatible date ranges
JSDate: JS date object of start of week
Type: school timetable, week 1 or 2
Label: human-readable label indicating start of week
I would like this library to be accessible by other scripts, so that they can load an Array or Object containing all of the weeks in the school calendar. I'd imagine, for instance, one of my scripts producing a drop-down menu from this information, which displays "Week 36: 5th Sept 2011" and when clicked upon sends a request to my PHP script & SQL database then filters the information on screen accordingly. NOTE: I don't need help with the implementation of the latter, it's just an example for context.
I started coding as follows:
var LEAP = {}
LEAP.Schedule = {
init: function() {
this.setWeeks();
}
setWeeks: function() {
var WeeksArray = [];
But the more I look at it, the less correct it feels!
Should I be creating "Week" objects, then a container for them which has a method to return all of the Week objects? I've been reading the OOP chapter in "Pro JavaScript Techniques" by John Resig, but truth be told I don't fully understand it. This feels like the right approach, but an Object within an Object is hurting my head.
The final outcome should be that I include this script on one of my pages, then can use something like var WeeksArray = LEAP.Schedule.getWeeks();, but even then I'm not sure that's realistic?
I'm rather confused...! :D Any help on the subject would be hugely appreciated.

setWeeks: function(){
var WeeksArray = []; //This variable is private, which is probably not your desired result.
}
^ That doesn't work, see comment.
I'd recommend something like this:
External file:
var LEAP = {};
LEAP.Schedule = function(){//init
//all events which should only occur once should be called here
//Create the initial objects, e.g.
this.weeks = [];
this.calculateWeeks();
}
LEAP.Schedule.protoype.calculateWeeks = function(){
for (var i=0; i<52; i++){
this.weeks.push(Math.random()); //For the sake of the example ;)
}
}
LEAP.Schedule.prototype.getWeeks = function(){
return this.weeks;
}
Main file:
var Scheduleobject = new LEAP.Schedule();
var weeks = Scheduleobject.getWeeks();
This feels like a very natural OOP approach, to me.
You can even change the LEAP.Schedule function such that it returns the Weeks array immediately, dependent on the situation.
EDIT
An example of a week class:
LEAP.Schedule.week = function(n_year, n_month, n_day, n_week){
//add code to validate the input
//...
//finished validating, processing:
this.year = n_year;
this.month = n_month;
this.day = n_day;
this.week = n_week;
}
LEAP.Schedule.week.protoype.getStartDate = function(){
return year + "-" + pad(month) + "-" + pad(day);
}
//LEAP.Schedule.week.prototype.*Date are defined in a similar way
//The "EndDateSchool" and "EndDateProper" variables always follow the same pattern. Reduce the number of unnecessary variables by calculating these variables in the prototype function.
LEAP.Schedule.week.prototype.getLabel = function(){
return "week" + this.week + ": " + this.day + (day==1||day==21||day==31?"st":day==2||day==22?"nd":day==3||day==23?"rd":"th") + " " + ["jan", "feb", "mar", "etc"][this.month-1] + " " + this.year;
}
function pad(n){return n>9?n:"0"+n}//a simple function to add a zero for your specific cases.
The week class can be called in this way:
var week = new Schedule.Week(2011, 8, 5, 36); //or this.Week(2011, 8, 5, 36) from the contex of the class.
var startDate = week.getStartDate(); //example`

Following up on my comment.
You might not ever need formal week objects. It might be enough to simply store which weeks are which type, and a formula for converting the number to a date. So your Calendar or Schedule object might have a property indicating the absolute day that week number 1 starts, and an array of week types in order. Then when getWeeks() is called, it can start at week 1 and build an array of the necessary weeks, which could be formal objects, or could simply be associative arrays:
weeks = [];
for (var i = 0; i < this.week_types.length; i++){
weeks[i] = {
"StartDate": this.get_start_date(i),
"JSDate": this.get_js_date(i),
..., //The rest of the properties
"type": this.week_types[i],
"Label": this.get_label(i)
}
Hopefully that starts you on the right track, I'm happy to help if I can provide further clarification.

Related

How to fetch data by weeks and have it display by switching between weeks?

I want to code something like this where you can see the weeks and switch between them. At the moment I wrote these days in HTML, so it is not dynamic. I am new to this, so I don't know what JS library can do something like this. I managed to find something that gives you the current week. However, I don't think this is the right approach.
var week = {
period: null,
load: function () {
var d = new Date(); // today, now
week.period = d.setDate(d.getDate() + ((7 - d.getDay()) % 7 + 1) % 7);
document.getElementById("date").innerHTML = dayjs( week.period).format("DD/MMM/YYYY");
},
};
week.load();
<h1 id="date"></h1>
This way I get the next Monday. How would you go from here? I want to first get the weeks done. I have the fetch under control, as I have JSON data.

Google Apps Script: Reading Duration values is off by X minutes

I'm working with duration fields on Google Spreadsheet on my timezone
Here is an example of the data I'm working with and my Spreadsheet configuration
Sample data:
actividadID
destinoID
atractivoID
actividadDescripc
actividadDuracion
actividadTipo
da839da6
ae4f25ff
'46432440
Visita
1:00:00 a. m.
EspecĂ­fica
Script Objective
The idea is to loop through a subset of these fields so for that I'm grabbing all the values of the spreadsheet and filtering them:
function TourDuration(tourID, mySS) {
const touractivData = mySS.getSheetByName("TourActividad").getDataRange().getValues();
const activData = mySS.getSheetByName("Actividad").getDataRange().getValues();
var current_activList = touractivData.filter(function(item){
return item[1] == tourID; //Match Bot Numbers && Unprocessed trades
});
Logger.log("current_activList:");
Logger.log(current_activList);
When I check the result of the data I'm grabbing I see data that is off, going into negative not only by hours but also by minutes:
[da839da6, ae4f25ff, 46432440, Visita a la Plaza Mayor de Lima, Sat
Dec 30 01:08:36 GMT-05:00 1899, EspecĂ­fica]
(This one should be the equivalent to 1 hour, but instead I got a negative time)
My goal is to add all the durations that match my filter into a consolidated one without success.
Here is the full code at the moment:
function TourDuration(tourID, mySS) {
const touractivData = mySS.getSheetByName("TourActividad").getDataRange().getValues();
const activData = mySS.getSheetByName("Actividad").getDataRange().getValues();
var current_activList = touractivData.filter(function(item){
return item[1] == tourID; //Match Bot Numbers && Unprocessed trades
});
var current_activList_length = current_activList.length;
var total_duration = 0;
for(var i = 0; i < current_activList_length; i++){
var activDuration = activData.filter(function(item){
return item[0] == current_activList[i][2]; //Match Bot Numbers && Unprocessed trades
});
var duration = Utilities.formatDate(new Date(activDuration[0][4]), "GTM-5", "dd/MM/yyyy HH:mm");
var dur2 = new Date(activDuration[0][4]).toString().substr(25,6)+":00";
dateString = Utilities.formatDate(activDuration[0][4], dur2, "MM/dd/yyyy HH:mm:ss");
Logger.log(duration)
Logger.log(dur2)
Logger.log(dateString)
total_duration = total_duration;
}
}
And this is the result of the log for a register with a 45min duration:
Could it be that the App Script interface has a different timezone?
Although the minutes difference is hard to explain since usually the differences are in full hours.
Also, I don't plan on using getDisplayValue() since I need to consult the whole sheet and getDataRange() would be more efficient.
Explanation:
Also, I don't plan on using getDisplayValue() since I need to
consult the whole sheet and getDataRange() would be more efficient.
getDisplayValues is used instead of getValues() and its purpose is to get the displayed value as it is shown in the sheet.
Please refer to this post for more details:
Difference between getValue() and getDisplayValue() on google app script
On the other hand, getDataRange() is not a sophisticated function.
This expression:
const activSheet = mySS.getSheetByName("Actividad");
const activData = activSheet.getDataRange().getValues();
is identical to this:
const activSheet = mySS.getSheetByName("Actividad");
const activData = activSheet.getRange(1,1,activSheet.getLastRow(),
activSheet.getLastColumn()).getValues();
Towards the solution:
By using getDisplayValues you will be able to get the value as it is displayed in your sheet:
function TourDuration() {
const mySS = SpreadsheetApp.getActive();
const activSheet = mySS.getSheetByName("Actividad");
const activData = activSheet.getDataRange().getDisplayValues();
console.log(activData[1][4]); // 1:00:00
}
However, you can't take the full date from this expression because the date is not specified in the cell. If you expand the change the format of your cells in column E to date:
you will see that you are getting exactly the info that is stored in the cell. So the code works as expected. The issue has to do with the missing information in the sheet itself.
You need to store the correct date in your sheet:
and then if you change the format back to time, the date will still be correct and your current script will be able to get it properly.

Google forms to calendar event issues with date format

So I have a very simple form that takes 3 inputs, a title, start and end date. I have tried to use a simple script to produce a calendar event. this can be seen below.
function onFormSubmit(e) {
var title = e.values[1];
var start_time = new Date(e.values[2]);
var end_time = new Date(e.values[3]);
CalendarApp.createEvent(title, start_time, end_time);
}
The issue I have is that as the date string is UK format (e.g. 05/12/2016 12:00:00) it is logging the events as 12th May as opposed to 5th December.
I am new to all of this so am looking for an elegant and simple solution I understand, not just to copy code I don't.
Thanks.
function convertUKDateToUSDate(date) {
const arr = date.split('/');
const temp = arr[0];
arr[0] = arr[1];
arr[1] = temp;
return arr.join('/');
}
will convert a date string with the prefix "DD/MM/" into "MM/DD/YYYY" format. Split turns the string into an array like ["DD", "MM", "YYYY HH:MM:SS"] and then the temporary variable is used to swap the "MM" and "DD" before the array entries are joined back together with the same character that was used to split them. You'll end up with a final onFormSubmit(e) like this:
function onFormSubmit(e) {
var title = e.values[1];
var start_time = new Date(convertUKDateToUSDate(e.values[2]));
var end_time = new Date(convertUKDateToUSDate(e.values[3]));
CalendarApp.createEvent(title, start_time, end_time);
}
Obviously I'm assuming e.values[2] and e.values[3] are strings. If they're Date objects already (or if you just want a shorter solution), then consider using the Moment.js (the premier Date object library) format function to convert between the formats. Normally I'd recommend using Moment anyways but you said you wanted something you could understand instead of copy.

TypeError: Cannot find function getHours in object 17

I have a Google App Script that stopped working and throws the Error "TypeError: Cannot find function getHours in object 17.". Since we haven't made any changes in the code and I'm not too familiar with Google App Script/Javascript, I hope someone can point me to the right direction.
The code is much longer than this but I'm giving an example of an appearance of the getHours function (I can provide the full code if needed):
if (action.indexOf("[") == -1 && action != "") { // Check if there is some operation to take action
var roomtype = row[1]; // Reading data from the table
var desc = row[8];
var date = row[2];
var tstart = row[3];
var tstop = row[4];
var name = row[5];
var company = row[9];
var short_title = RoomShortcuts[0][roomtype] + " " + name + " (" + company + ")"; // Creating title of the Calendar entry
if (action == "Tentative") { short_title = "PROV: " + short_title; } // This is for Tentative events
var year = date.getYear(); // Getting the date and time and transforming it for the calendar
var month = date.getMonth();
var day = date.getDate();
var startHour = tstart.getHours();
var startMinute = tstart.getMinutes();
var stopHour = tstop.getHours();
var stopMinute = tstop.getMinutes();
var startdate = new Date(year, month, day, startHour, startMinute);
var stopdate = new Date(year, month, day, stopHour, stopMinute);
if (roomtype == "Gallery") {
var repeat = 2;
cal_EventCalendar[0]['Gallery'] = CalendarApp.openByName("Hub SMR");
} else {
var repeat = 1;
}
Thanks a lot!
I had a similar problem. I was able to use getHours in one script but got the same error when trying to access the sheet from another script. Anyhow, after reading:
http://www.w3schools.com/jsref/jsref_gethours.asp
I put together the following solution:
function weeklyUpdater() {
var sheet = SpreadsheetApp.getActiveSheet();
var schedule = sheet.getRange(2, 2, sheet.getLastRow() + 1, 3).getValues();
var hours = new Date(schedule[0][2]); // parse string into date
var hoursX = hours.getHours();
Logger.log(hoursX + ":");
}
The key is using new Date whereas in my other script schedule[0][2].getHours() works!
Anyhow, hope this helps.
I don't know what row is, or where it's defined. But the 4th element is a number object, with a value of 17, not whatever object you expected it to be.
var tstart = row[3];
var startHour = tstart.getHours(); // Number object has no function getHours()
the issue is in your spreadsheet, not in your script.
You can easily test that by double clicking on the cell that correspond to row[3] (most probably in column D) and see what happens : if it's a date object that shows only hours:minutes then it will give you a calendar popup like this:
If it is a 'ordinary' number or string then nothing special will happen and your script will never get any hour or minute from it since these statements need a date object as argument.
This is one of the dangers of spreadsheets that makes things look like what they are not, in this case showing time value in hours and minutes while the object behind is is a full date value with years, seconds and milliseconds... one often forget that ;-)
So, check the most recent cell values and I'm pretty sure you'll find that someone typed a value the wrong way and that the spreadsheed failed to translate it into a date value.

Formatting a JSON Date with javascript

I am returning a JSON object from my web service method. The object has some dates in it and so the generated JSON is like the following:
{"d": [
{"PeriodID":8,"Period":"072011","BeginDate":"\/Date(1294268400000)\/"},
{"PeriodID":2,"Period":"052011","BeginDate":"\/Date(1293836400000)\/"}
]}
I am trying to convert this data in a string to be added as <option> elements in an HTML select. This is my code:
var rtypes = data.d;
$.each(rtypes, function (key, value) {
var text = value.Period + " - " + "from " + eval(value.BeginDate.slice(1, -1));
var option = $("<option></option>").attr("value", value.PeriodID).text(text);
$('#rpCombo').append(option);
});
Now the questions:
Can I format the date contained in the Period field (e.g. 072011) as a "July 2011"?
How can I convert the result of eval(value.BeginDate.slice(1, -1)) that is for instance something like "Wed July 14......" into something like "14/07/2011"?
Thanks for helping
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date/parse
For example
// create 1 of June 2011 from Jun 2011
var period = new Date(Date.parse("1 "+period));
Here is what I think you want
<script>
var months = ["Jan","Feb","Mar","Apr","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]
var result = {"d": [
{"PeriodID":8,"Period":"072011","BeginDate":1294268400000},
{"PeriodID":2,"Period":"052011","BeginDate":1293836400000}
]}
var aPeriod, period, periodMM, periodYYYY, periodText, beginDate, beginMM, beginDD;
for (var i=0,n=result.d.length;i<n;i++) {
aPeriod = result.d[i];
// period = new Date(aPeriod.Period.slice(2),aPeriod.Period.slice(0,2)-1,1,0,0,0);
// periodText = months[period.getMonth()]+" "+period.getFullYear();
periodMM = parseInt(aPeriod.Period.slice(0,2),10);
periodYYYY = aPeriod.Period.slice(2);
periodText = months[periodMM]+" "+periodYYYY;
beginDate = new Date(aPeriod.BeginDate);
beginDD = beginDate.getDate();
if (beginDD<10) beginDD="0"+beginDD;
beginMM = beginDate.getMonth()+1;
if (beginMM<10) beginMM="0"+beginMM;
periodText += " "+beginDD+"/"+beginMM+"/"+beginDate.getFullYear();
alert(periodText)
}
</script>
Not sure on the scale of your project, but I was doing a lot with dates recently and benefitted by implementing javascript extensions on the javascript Date object. This will make your life soooo much easier as it has for me and will take care of the above scenario and then some.
There is a very good article here: Javascript/Json Date Parsing
I did need to tweak it a little, but no looking back since implementing this approach.

Categories

Resources