MomentJS possible bug with the add() function - javascript

I'd like to add several months in an array but I cannot get the add() function of MomentJS to work properly. Here's how it goes :
function getMonths(begin, end){
var cursor = moment(begin);
var momentEnd = moment(end);
var arrayMonths = [];
while(cursor.month() != momentEnd.month() || cursor.year() != momentEnd.year()){
cursor.add(1, 'month'); // Actually adds one month to the cursor
console.log(cursor.toDate()); // Because this display the cursor with an added month
arrayMonths.push(cursor.toDate()); // However the cursor being pushed doesn't have this added month
console.log(arrayMonths); // verified here
}
return arrayMonths;
}
The console log shows that the cursor has actually been incremented (as add() is a mutator) however its proper value isn't added to the array.
I cannot figure out if this is an issue in my code or if it is inherent to MomentJS. Does anybody have any clue ?
Thank you !

The documentation for toDate says:
To get the native Date object that Moment.js wraps, use moment#toDate.
This will return the Date that the moment uses, so any changes to that Date will cause the moment to change. If you want a Date that is a copy, use moment#clone before you use moment#toDate.
IE you're getting the same underlying Date object every time you call toDate - ie each call to add is also modifying it, and every member of the array is actually the same object.
If you do as the documentation says, and use clone, your code works:
arrayMonths.push(cursor.clone().toDate());
Here's a demo:
function getMonths(begin, end){
var cursor = moment(begin);
var momentEnd = moment(end);
var arrayMonths = [];
while(cursor.month() != momentEnd.month() || cursor.year() != momentEnd.year()){
cursor.add(1, 'month'); // Actually adds one month to the cursor
console.log(cursor.toDate()); // Because this display the cursor with an added month
//clone the object before pushing, to ensure it's not further modified
arrayMonths.push(cursor.clone().toDate());
console.log(arrayMonths); // verified here
}
return arrayMonths;
}
getMonths(moment('2016/01/01', 'YYYY/MM/DD'), moment('2017/01/01', 'YYYY/MM/DD'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.js"></script>

Not entirely sure what's happening here as your code looks OK.
I would however try using and temporary variable to double check what's happening.
function getMonths(begin, end){
var cursor = moment(begin);
var momentEnd = moment(end);
var arrayMonths = [];
while(cursor.month() != momentEnd.month() || cursor.year() != momentEnd.year()){
cursor.add(1, 'month');
var cursorDate = cursor.toDate();
console.log(cursorDate); // temporary variable - no chance it gets mutated etc...
arrayMonths.push(cursorDate);
console.log(arrayMonths);
}
return arrayMonths;
}

Related

printing array shows different values when printing only the last element - javascript

im getting logs with a date property in the ISO YYYYMMDDhhmmss format, and im transfering them to Date object using the map function as seen below.
when I print the whole object I get the wrong dates but when I print just one element of the array its correct, this is bizarre to me,what am I missing ?
let dates = ascendingLogs.map(log => new Date(log['date'].replace(
/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/,
'$4:$5:$6 $2/$3/$1'
)));
console.log(dates[dates.length - 1])
console.log(dates)
let numberOfElements = 8
let timeGap = (dates[dates.length -1].getTime() - dates[0].getTime()) / numberOfElements;
let labels = []
for (let i = 1; i < numberOfElements; i ++){
dates[i] = new Date(dates[i - 1].getTime() + (timeGap));
};
below are the console.log of 1. last element in dates, whole dates array, ascendingLogs object
EDIT :
I have been able to narrow down the problem to the for loop, what im thinking is that it somehow asynchronously changes the console.log value but I dont know how to solve it.
heres a reproducible example you could examine :

unable to get value of i in for loop

I have a simple for loop and it is matching condition according to my log files
but still the value of i is showing undefined
here is my javascript code
var indexs,i;
for(i = 0; i < data[0].length; i++){
if (new Date(data[0][i]) == new Date(inRecord.rdate))
{indexs = i;
}
Logger.log(new Date(data[0][i])+ " : " +new Date(inRecord.rdate) +": indexes:"+indexs)
}
and Image below if my log output which shows the condition should matched.
what am I doing wrong here?
new Date returns an object. And two objects can not be compared even where they contain the same data. The result will always be false.
new Date creates an object which cannot be compared. Even if two of these objects are identical, they will not produce a true comparison. To get around this, define them before the IF statement and compare the millsecond values with getTime(). This will be comparing two numbers (not objects) and work great :)
let dataDate = new Date(data[0][i])
let recordDate = new Date(inRecord.rdate)
if (getTime(dataDate) == getTime(recordDate)) {
indexs = i;
}
Happy to clarify if this doesn't work.

How can I store composed changes using Quill?

I started to work with Quill, and I need to save the changes made by the user in the document, and if possible, composing them, so I don't need to store operation by operation.
To accomplish this, I am monitoring the 'text-change' event, and every operation is stored in the database of my application. From time to time (every minute), I compose the changes made in the document with a previous document state and execute a diff between the result of this composition and the previous document state, storing the result of the diff, and deleting the previous operations, because they are in the diff result.
To get the previous document state, initially I use the original document delta. Then, when a diff is stored, I just compose the original document delta with the diff's that exist in the database. For example:
Original document delta: {"ops":[{"insert":"Evaluation Only. Created with Aspose.Words. Copyright 2003-2018 Aspose Pty Ltd.","attributes":{"size":"16px","font":"Calibri","bold":true,"color":"#FF0000"}},{"insert":"\n","attributes":{"paragraph":true,"spacing_before":"0px","spacing_after":"10.67px","indent":0,"text_indent":"0px","line_spacing":"17.27px"}},{"insert":"Test","attributes":{"size":"14.67px","font":"Calibri","color":"#000000"}},{"insert":"s","attributes":{"size":"14.67px","font":"Calibri","color":"#000000"}},{"insert":"\n","attributes":{"paragraph":true,"spacing_before":"0px","spacing_after":"10.67px","indent":0,"text_indent":"0px","line_spacing":"17.27px"}}],"page_setup":{"left_margin":"113.4px","top_margin":"94.47px","right_margin":"113.4px","bottom_margin":"94.47px"}}
First change: {"ops":[{"delete":80}]}
Second change: {"ops":[{"retain":5},{"insert":"\n","attributes":{"spacing_before":"0px","spacing_after":"10.67px","text_indent":"0px","line_spacing":"17.27px"}}]}
Third change: {"ops":[{"retain":6},{"insert":"A","attributes":{"color":"#000000"}}]}
The code I am using is shown below:
var diffs = result.diffs;
var deltas = result.deltas;
var lastComposedDelta = null;
for (var i = 0; i < diffs.length; i++) {
var currentDelta = newDelta(diffs[i].Value);
if (lastComposedDelta == null) {
lastComposedDelta = currentDelta;
} else {
lastComposedDelta = lastComposedDelta.compose(currentDelta);
}
}
var composedDeltas = lastComposedDelta;
for (var i = 0; i < deltas.length; i++) {
var currentDelta = newDelta(deltas[i].Value);
if (composedDeltas == null) {
composedDeltas = currentDelta;
} else {
composedDeltas = composedDeltas.compose(currentDelta);
}
}
var diffDelta = composedDeltas;
if (lastComposedDelta != null) {
diffDelta = lastComposedDelta.diff(composedDeltas);
}
The result of this diff is: {"ops":[{"delete":80},{"retain":5},{"retain":1,"attributes":{"paragraph":null,"indent":null}},{"attributes":{"color":"#000000"},"insert":"A"},{"attributes":{"paragraph":true,"spacing_before":"0px","spacing_after":"10.67px","indent":0,"text_indent":"0px","line_spacing":"17.27px"},"insert":"\n"}]}
The problem I encountered is when the user inserts a new line and indent it, for example. The delta of such operations are:
New line: {"ops":[{"retain":8},{"insert":"\n"}]}
Indent: {"ops":[{"retain":9},{"retain":1,"attributes":{"indent":1}}]}
Then, when I try to diff the document, with the code above, it gives me the error:
Uncaught Error: diff() called with non-document
Value of "lastComposedDelta": {"ops":[{"insert":"Tests","attributes":{"size":"14.67px","font":"Calibri","color":"#000000"}},{"insert":"\n","attributes":{"spacing_before":"0px","spacing_after":"10.67px","text_indent":"0px","line_spacing":"17.27px"}},{"attributes":{"color":"#000000"},"insert":"A"},{"attributes":{"paragraph":true,"spacing_before":"0px","spacing_after":"10.67px","indent":0,"text_indent":"0px","line_spacing":"17.27px"},"insert":"\n"},{"delete":80},{"retain":5},{"retain":1,"attributes":{"paragraph":null,"indent":null}},{"insert":"A","attributes":{"color":"#000000"}},{"insert":"\n","attributes":{"paragraph":true,"spacing_before":"0px","spacing_after":"10.67px","indent":0,"text_indent":"0px","line_spacing":"17.27px"}}]}
Value of "composedDeltas":
{"ops":[{"insert":"Tests","attributes":{"size":"14.67px","font":"Calibri","color":"#000000"}},{"insert":"\n","attributes":{"spacing_before":"0px","spacing_after":"10.67px","text_indent":"0px","line_spacing":"17.27px"}},{"insert":"A","attributes":{"color":"#000000"}},{"insert":"\n","attributes":{"paragraph":true,"spacing_before":"0px","spacing_after":"10.67px","indent":0,"text_indent":"0px","line_spacing":"17.27px"}},{"insert":"\n"},{"delete":80},{"retain":1,"attributes":{"indent":1}},{"retain":4},{"retain":1,"attributes":{"paragraph":null,"indent":null}},{"insert":"A","attributes":{"color":"#000000"}},{"insert":"\n","attributes":{"paragraph":true,"spacing_before":"0px","spacing_after":"10.67px","indent":0,"text_indent":"0px","line_spacing":"17.27px"}}]}
I dig a little, and found out that the error is caused because there is a "retain" operation on the deltas used to diff, and it is not processed. So, I want to know if there is a solution for this, because I am unsure if the code I've made is the right way to do this (storing diffs of a document).
If you don't need each individual operation, you can just update the document on the text-change event like so:
quill.on('text-change', () => {
// By the time we hit the 'text-change' event,
// quill.getContents() will return the updated
// content of the document
const currentOps = quill.getContents();
updateDatabase(currentOps);
});
function updateDatabase(currentOps) {
// Do whatever you need to do with the current ops
// to store them. No need at all to store the diffs.
}
So, I discovered the problem with the diff function. It was because, when I initialized the editor, I was using the function updateContents to set the delta I had in the database to the editor. Quill always initialize the editor with a blank line. By calling the updateContents, it was composing the blank line with the text coming from my database. Then, when the user was changing the text, the delta from the editor was different from the delta in the database.
To fix this, I changed the function that was loading the content from the database to setContents. This way, the deltas from the editor and database matched.

API response is returning undefined

I am making a API call that returns a JSON response of an Array with a bunch of objects. Each object has a key "dt" that is the timestamp of a specific time of day and another key of "height" which is the Ocean's predicted or past tide height at that moment in time.
I only want the current tide's height at whatever moment in time the AJAX call happens. This is the function I created in order to achieve that:
let tideApi = 'https://www.worldtides.info/api?heights&lat=45.202&lon=-123.963&key=24e4ff14-6edf-4f79-9591-e47f9e0e21e1';
$.getJSON(tideApi, function(response) {
// Create Global variable
let tideHeight = 0;
// get current time
let nowMil = new Date().getTime();
// round that time to the nearest halfhour and convert back to timestamp (JSON timestamps are set in intervals of 30 minutes)
let timeNow = Math.round(nowMil/1000/60/30) * 30 * 60 * 1000;
// set entire array to variable
let heightArray = response.heights;
// get length
len = heightArray.length
// loop through each object in height array
for (var i=0; i < len; i++) {
// if one of the objects timestamp equals current time
if (i.dt = timeNow) {
// set tide height to variable
tideHeight = i.height;
// return tide height (curretly returning undefined)
console.log("Tide Height: " + tideHeight);
return tideHeight;
} else {
console.log("Error, no time found");
}
}
// put tide height into div
$("#tideStat").append("<p>" + tideHeight + "</p>");
});
It's currently returning undefined for a reason I am struggling to figure out. Any help would be great!
API Call (Don't worry going to change after this)
Codepen
There are a few problems in your code
let timeNow = Math.round(nowMil/1000/60/30) * 30 * 60 * 1000;. Your API doesn't seem to be returning milliseconds. Remove the * 1000.
You're not accessing items from your heightArray. Rather, just checking dt and height property on i, which is an integer. So change i.dt and i.height to heightArray[i].dt and heightArray[i].height respectively.
When you use if (lhs = rhs), you're attempting to assign, not compare. So, change = to === in the if condition.
Remove return tideHeight;. I think you want break? Not sure though. Because of this line, your last jQuery related code doesn't execute.
Forked pen. Some logs commented out for better output.
Use bracket notation to reference i object of heightArray array, === operator, instead of =, which is assignment operator
if (heightArray[i].dt === timeNow) {
// do stuff
tideHeight = heightArray[i].height;
}

Cannot read property "0" from undefined. Error Google Apps Script

I´m geting Cannot read property "0" from undefined. Error on line 16. ( while (colunaDias[emptyCell][0] <= dias) )
It should be a very simple function for google SpreadSheets. I can´t see what I´m doing wrong...
The bizarre thing is that if I don´t use the variable "dias" and use a integer instead. The while function works....
function myFunction() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var leadsSheet = ss.getSheetByName("Leads Todas as Categorias, menos outros - Days (5days)");
var targetSheet = ss.getSheetByName("feticaria");
var cellLeads = leadsSheet.getRange(1,1).getValue();
//var cellTarget = targetSheet.getRange(1,1).setValue(valor);
var colunaDias = leadsSheet.getRange('B:B').getValues();
var sourceMedium = leadsSheet.getRange('A:A').getValues();
var emptyCell = 16;
var dias = 1;
while (colunaDias[emptyCell][0] != ""){
while (colunaDias[emptyCell][0] <= dias){
dias++;
emptyCell++;
}
emptyCell++;
}
Logger.log(emptyCell);
}
I think the only thing that could cause that error is if emptyCell is bigger than the colunaDias array, i.e. if your sheet is smaller than 16 rows (if the value you show here is correct).
Add this line right before the first while :
Logger.log('emptyCell = '+emptyCell+' and colunaDias.length = '+colunaDias.length);
I tested a copy of your script and it runs without error except if I define emptyCell > 1000 on a 1000 rows Sheet.
I'm guessing that colunaDias[emptyCell] is undefined. It passes the first while condition, because "undefined" is not equal to "". If colunaDias[emptyCell] is undefined, then either there is something wrong with this line:
var colunaDias = leadsSheet.getRange('B:B').getValues();
or
colunaDias[emptyCell][0]
Where "emptyCell" is 16 is the problem. getValues() returns an object of rectangular grid of values. I would test to see if there is anything in the rectangular grid, by checking [0][0].
Logger.log('is there any data? ' + colunaDias[0][0])
If there is no data, then the something failed on line:
var colunaDias = leadsSheet.getRange('B:B').getValues();
If that line is working, then something higher up is wrong.
You should be checking the return type of getSheetByName for null.
// The code below will log the index of a sheet named "YourSheetName"
var leadsSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("YourSheetName");
if (leadsSheet != null) {
Logger.log(leadsSheet.getIndex());
}
I know this post in from a few years ago, but this was the closest to a problem I am having. I just want to post my answer in case someone else ends up here one day.
For some reason the check variable "dias" is being passed as a string.
That's why replacing it with a number allows the script to run.
dias = parseInt(dias); //use this before the variable needs to be read
I cant say why it is passing a string after being ++ but this will fix it

Categories

Resources