I need to find out the difference in the old and new value of the localStorage when the change event if triggered.
I can toggle the same localStorage key within different tabs, so if I add one the values would be:
'1234,4321'
But then when I remove one it would be:
'1234'
My code below will convert the string to an array, separating the comma. However this only seems to work on way around, so if I remove one the code below will display an empty array, instead of the removed number.
window.addEventListener('storage', function (e) {
if (e.key === 'favourites') {
let newv = e.newValue.split(',').filter(id => !!id);
let oldv = e.oldValue.split(',').filter(id => !!id);
let difference = newv.filter(function (i) {
return oldv.indexOf(i) === -1;
});
console.log(difference);
}
});
What is the best way to do this!?
So you need to check for added by looking to see if the original does not have it from the new values. And to check for a removed item, you need to check that the id does not exist in the orginal values.
const oldValue = '1234,4321'
const newValue = '1234,5555'
const oldValueIds = oldValue.split(",")
const newValueIds = newValue.split(",")
const removed = oldValueIds.filter(id => !newValueIds.includes(id))
const added = newValueIds.filter(id => !oldValueIds.includes(id))
console.log('removed: ', removed)
console.log('added: ', added)
Related
I got this these values.
And I want to have this result.
So I made the following test code and tried it to the first cell.
function test2() {
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName("richText3");
const range1 = sheet.getRange("A1");
const text1 = range1.getValue();
Logger.log(text1);
const re = new RegExp(/\([ a-zA-Z\/']*\)\?/dg);
const redBold = SpreadsheetApp.newTextStyle().setBold(true).setForegroundColor('red').build();
let array;
while ((array = re.exec(text1)) !== null) {
const [start, end] = array.indices[0];
const richTxtValBlder = SpreadsheetApp.newRichTextValue()
.setText(text1)
.setTextStyle(start, end, redBold)
.build();
range1.setRichTextValue(richTxtValBlder);
}
}
After first try, I got this result.
I checked the Reference Document again and I found this comment.
setText(text) : Sets the text for this value and clears any existing text style.
When creating a new Rich Text value, this should be called before setTextStyle()
I found that I should call .setText() once and call .setTextStyle() multiple times.
But the problem is .setTextStyle() should be called programmatically according to the number of patterns in each cell and I cannot find how to do it programmatically.
Each cell may have 0 to 10 patterns and I don't want to make 10 different richTExtValueBuilder which only differ in the number of .setTextStyle() calls.
Do you have any different ideas ?
Modification points:
In your script, only cell "A1" is used, and also the 1st match is used. I thought that this might be the reason for your issue.
In order to achieve your goal, I retrieve the values from column "A". And also, I use matchAll instead of exec.
When these points are reflected in your script, how about the following modification?
Modified script:
function test2() {
const ss = SpreadsheetApp.getActive();
const sheet = ss.getSheetByName("richText3");
const range1 = sheet.getRange("A1:A" + sheet.getLastRow());
const re = new RegExp(/\([ a-zA-Z\/']*\)\?/g);
const redBold = SpreadsheetApp.newTextStyle().setBold(true).setForegroundColor('red').build();
const richTextValues = range1.getRichTextValues();
const res = richTextValues.map(([a]) => {
const array = [...a.getText().matchAll(re)];
if (array) {
const temp = a.copy();
array.forEach(a => temp.setTextStyle(a.index, a.index + a[0].length, redBold));
return [temp.build()];
}
return [a];
});
range1.setRichTextValues(res);
}
Testing:
When this script is run, the following result is obtained.
From:
To:
References:
map()
setRichTextValues(values)
It looks like you need to call .setText() once, .setTextStyle() multiple times, and .build() once, e.g. change your while loop. Untested code:
let richTxtValBlder = SpreadsheetApp.newRichTextValue().setText(text1);
while ((array = re.exec(text1)) !== null) {
const [start, end] = array.indices[0];
richTxtValBlder = richTxtValBlder.setTextStyle(start, end, redBold);
}
richTxtValBlder = richTxtValBlder.build();
range1.setRichTextValue(richTxtValBlder);
Question: I am trying to validate email endings in an array
let input = 'test#gmail.com' // This is grabbed dynamically but for sake of explanation this works the same
let validEndings = ['#gmail.com', '#mail.com', '#aol.com'] //and so on
if(input.endsWith(validEndings)){
console.log('valid')
}else{
console.log('invalid')
}
I can get this to work when validEndings is just a singular string e.g let validEndings = '#gmail.com'
but not when its in an array comparing multiple things
You can solve the problem with regex. Example:
const input = 'test#gmail.com';
const validEndingsRegex = /#gmail.com$|#mail.com$|#aol.com$/g;
const found = input.match(validEndingsRegex);
if (found !== null) {
console.log('valid')
} else {
console.log('invalid')
}
You can achieve this by using Array.some() method which tests whether at least one element in the array passes the test implemented by the provided function. It returns true if, in the array, it finds an element for which the provided function returns true; otherwise it returns false.
Live Demo :
let input = 'test#gmail.com';
let validEndings = ['#gmail.com', '#mail.com', '#aol.com'];
const res = validEndings.some(endingStr => input.endsWith(endingStr));
console.log(res);
I am trying to filter through a large set of data that has an array nested inside whos values I need to compare against a string. To compare them I need to clean the strings because its coming through user input and spacing/capitalization may vary. So I had my functions working through a filter that looked like this
data initially looked like
formularyOptions = [{Condition: "headache"...}{Condition: "hair loss"..}...]
chiefComplaint = "Headache"
const cleanText = (value) => {
let str = value;
if (!str) {
return value;
}
str = str.toLowerCase();
str = str.replace(/\s/g, "");
return str;
};
let formularyList = formularyOptions.filter(
(item) => !!chiefComplaint && cleanText(item.Condition) === cleanText(chiefComplaint),
);
And this worked just fine but now
My data looks like this:
[{Condition: ["headache", "migraine"]...}{Condition: ["hair loss"]..}...]
Ive tried changing my filter to loop through the Conditions array but that doesnt return anything for some reason I dont understand. And the includes method wont work since it is case sensitive. Any advice on how to approach this or even why a forEach wouldnt work inside a .filter would be super helpful this is my attempt with a for loop:
let formularyList = formularyOptions.filter(
(item) => !!chiefComplaint && item.Condition.forEach((condition) => cleanText(condition) === cleanText(chiefComplaint)),
);
which just returns an empty array..
You are including a .forEach(...) inside a boolean conditional, but it is void, it only loops, nothing is returnted.
I think you actually need to use the .some(...) instead, which will try to find some item that corresponds to the condition:
let formularyList = formularyOptions.filter(
(item) => !!chiefComplaint && item.Condition.some((condition) => cleanText(condition) === cleanText(chiefComplaint)),
);
I'd like to create a const variable that is equal to the number of checked checkboxes with a certain class. This is my code to do that(which is not working):
const blocksUserAddLineCBs = $(".useradd"+blockIdEnding);
const blocksUserAddLinesActiveCBCounter = blocksUserAddLineCBs.reduce((currentTotal, item) => {
return $(item).prop('checked') === true + currentTotal;
}, 0);
Is the reduce method not working with a Field created with a jQuery Selector? How could i that without having to create a let Variable and a $().each Loop which increases the variable every time it recognizes one of the elements is checked ($(this).prop('checked'))
.reduce doesn't work on jQuery objects, and in any event it's overkill:
const count = $('.useradd' + blockIdEnding + ':checked').length;
or alternatively:
const $els = $('.useradd' + blockIdEnding);
const count = $els.filter(':checked').length;
(variables renamed to prevent window overflow)
reduce is a method found on arrays.
A jQuery object is not an array.
You can get an array from a jQuery object using its toArray method.
Currently trying to build a javascript form that converts the inputs into JSON. I've managed to create objects that allow multiple keys/values to be entered however I'm struggling to get my head around the logic and code for nesting a child object within an object.
let objects = [];
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('btn2').addEventListener('click', function(e) {
e.preventDefault();
let infoBoxOne = document.getElementById('key').value // store the key into a variable
let infoBoxTwo = document.getElementById('value').value // store the value into a variable
const lastObject = objects[objects.length-1] // finds the last object in the objects array
const objectValues = Object.entries(lastObject) // gets all the keys and values
const lastKeyValuePair = values[values.length-1]; // stores the last key and value entered into a variable
})
})
So my initial idea was to find the last key/value within the last object that was added and use something like Object.create() or push() to insert the data. Is there an easier way of achieving this?
edit: here's a jsfiddle showing what I have exactly so far https://jsfiddle.net/9jrzLxnm/
Secone edit: idea of what I'm trying to achieve
{
{
"firstObject":'FirstObject'
},
{
"lastObject": {
"infoBoxOne": "JlastObject",
},
}
}
Ok firstly you have to set the desired location to place a child object as an object itself.. then the rest is intuitive
My example is on jsfiddle
document.addEventListener('DOMContentLoaded', () => {
document.getElementById('btn2').addEventListener('click', function(e) {
e.preventDefault();
let childKey = document.getElementById('key').value // store the key into a variable
let childValue = document.getElementById('value').value // store the value into a variable
const lastObject = objects[objects.length-1] // finds the last object in the objects array
const values = Object.entries(lastObject) // gets all the keys and values
const [key,value] = values[values.length-1]; // stores the last key and value entered into a variable
lastObject[key]={} //turning place to put child into an object
lastObject[key][childKey]=childValue //placing the nested child
document.forms[0].reset();
listToJson();
})
})