multiple items local storage javascript - javascript

I have two different lists on my page, which data I want to store in Local Storage. With this code below I store my data from one list.
How can I use this code to store this data from two lists, but to be in separate objects?
maybe this question is silly, but i'm a beginner. Thanks for your help.
class Storage {
saveStorage(task) {
const tasks= this.getFromStorage();
tasks.push(task);
localStorage.setItem('tasks', JSON.stringify(tasks));
}
removeStorage(task){
const tasks= this.getFromStorage();
recipes.forEach((task, index) => {
if(task === task.id) {
tasks.splice(index,1);
}
});
localStorage.setItem('tasks', JSON.stringify(tasks));
}
getStorage() {
let tasks;
if(localStorage.getItem('tasks') === null) {
tasks= [];
} else {
tasks= JSON.parse(localStorage.getItem('tasks'));
}
return tasks;
}
}

Pass a name into the constructor, e.g.:
constructor(name) { this.name = name; }
Then replace tasks with this.name everywhere, e.g.:
localStorage.getItem(this.name)
Then you can just do:
const tasks = new Storage("tasks");
const users = new Storage("users");

If I understand your question correct, you need to adjust your structure of your functions to take in a parameter that defines the list you want to edit.
You storage should then contain an Array of Objects, and each object needs to have an identifier, such as a name or ID that can then be used to identify the different lists.
You would then need to pass them to your functions to modify and retrieve. Pass in that exact ID or name and your functions code should then be made to look for the right object in the array. Can easily be done with array.find, such as someArray.find(x = >x.name === "List1").
Hope it helps.

Try something like this that is a little more generic and reusable.
class Storage {
static saveStorage(obj, key) {
const store = Storage.getFromStorage(key);
store.push(obj);
localStorage.setItem(key, JSON.stringify(store));
}
static removeStorage(obj, key, fnCompare) {
const store = Storage.getFromStorage(key);
store.forEach((item, index) => {
if (fnCompare && fnCompare(obj, item)) {
store.splice(index, 1);
} else if (item == obj) {
store.splice(index, 1);
}
});
Storage.saveStorate(store, key);
}
static getFromStorage(key) {
if (localStorage.getItem(key) === null) {
return [];
} else {
return JSON.parse(localStorage.getItem(key));
}
}
}
Then you can call it like this:
Storage.saveStorage({ test: 'true'}, 'test');
Storage.removeStorage({ test: 'true'}, 'test', function(curr, prev) { return curr.test == prev.test});
Storage.getFromStorage('test')

I would use something more generic. With "tasks" hard-coded in there, it makes things difficult to reuse. Also, this is built so all stored data MUST be an array or items in an array - I would change it to handle all types. If you want to inject something into an array, I would think you can and should do that outside of the Storage class and just save again. Also, complex objects will need to be "revived" when pulled back out.
One other thing to note is that you may run into the "JSON Graph Problem" because JSON doesn't store object reference data. Use this with care. Here's a little more information on that: http://netflix.github.io/falcor/documentation/jsongraph.html.
See the example code below and here's a working jsfiddle to demonstrate: https://jsfiddle.net/wd4acLfv/45/
class Storage {
static get(key, reviveFuncOrDefault = null) {
const itemJSON = localStorage.getItem(key)
if (reviveFuncOrDefault !== null) {
if (itemJSON === null)
return reviveFuncOrDefault
else if (typeof reviveFuncOrDefault === 'function')
return reviveFuncOrDefault(JSON.parse(itemJSON))
}
return JSON.parse(itemJSON)
}
static set(key, item) {
localStorage.setItem(key, JSON.stringify(item))
}
static unset(key) {
localStorage.removeItem(key)
}
}
// Plain Object
Storage.set('obj', { foo: 'bar '}) // Set object
console.log(Storage.get('obj', {})) // Object exists
console.log(Storage.get('obj2', {})) // Object fallback value
// Primitive Type
Storage.set('bool', true) // Set array
console.log(Storage.get('bool', false)) // Array exists
console.log(Storage.get('bool2', false)) // Array fallback value
// Array
Storage.set('arr', [ 1, 2, 3 ]) // Set array
console.log(Storage.get('arr', [])) // Array exists
console.log(Storage.get('arr2', [])) // Array fallback value
// Mutate array
const arr = Storage.get('arr', [])
arr.push(4)
Storage.set('arr', arr)
console.log(Storage.get('arr', []))
// Non-plain JS Object
class Person {
constructor(firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
getFullName() {
return this.firstName + ' ' + this.lastName
}
}
Storage.set('person', new Person('Bob', 'Ross')) // Set object
const person = Storage.get('person',
({ firstName, lastName }) => new Person(firstName, lastName)
)
console.log(person.getFullName())

Related

How to make a method that finds every object by id in angular

Please help,
I want to make a method findChildByIdInData(data:any, childId:string) where the data is any JSON main node that has children with Ids.
Simply, how to make a method that receives JsonNode and its child Id as parameters to find that object using angular.
In my case, I have a data as a node where I want to find its children's objects (may be nested) by id.
Thanks for your time :)
To implement lodash
https://stackoverflow.com/a/41992126/18762612
import { get } from "lodash";
variable in component
deepObj = {a:{b:{n:{e:100, c: 120}}}
example of get
constructor(){
get(deepObj, 'a.b.n.e');
}
Got the result by using the Recursively Traverse an Object method:
this link helps me: https://cheatcode.co/tutorials/how-to-recursively-traverse-an-object-with-javascript.
the backendService:
// Verify the object
isObject(value): any {
return !!(value && typeof value === "object");
};
// Find object in node
findNestedObject(object: {}, keyToMatch: String, valueToMatch: String): any {
if (this.isObject(object)) {
let entries = Object.entries(object);
for (let i = 0; i < entries.length; i += 1) {
const [objectKey, objectValue] = entries[i];
if (objectKey === keyToMatch && objectValue === valueToMatch) {
return object;
}
if (this.isObject(objectValue)) {
let child = this.findNestedObject(objectValue, keyToMatch, valueToMatch);
if (child !== null) {
return child;
}
}
}
}
return null;
};
and call that method in component as:
// Find the nested object by passing node, key, & value
// the this.shop is your backend data or json
let result = this.backendService.findNestedObject(this.data, "id", "dataId");
console.log("Result: ", result);

Insert element inside array

I have a function
checkName(output) {
output.filter((NewData) => {
return this.props.elements.filter((OldData) => {
if (NewData.key == OldData.key) {
NewData.name = OldData.name,
//there i need to add another element
// Need to add newData.number = OldData.number
}
return NewData
})
})
return output
}
and I call this function like:
const named = this.checkName(product.rows)
Now I need to add to my product's array that I passed to checkName the value "OldData.Number" to "newData.Number" that is not defined in product (so I need to create this field)
For example:
Product before the checkName function
product.rows = [NewData.name]
Product after the checkName function
product.rows = [NewData.name="value of OldData.name", NewData.number="value of OldData.number"]
How can I obtain this result?
There are 2 confusing things in your code:
You are using filter to execute an action in each member of the output array. However, filter should be used to... well, filter that array, meaning that is should not modify it, just return a sub-set of it. Instead, you might want to use forEach. However, taking into accound the next bullet, probably you want to use map.
You are modifying the array passed to the checkName function. This is confusing and can lead to hard-to-find bugs. Instead, make your function "pure", meaning that it should not mutate its inputs, instead just return the data you need from it.
I would suggest some implementation like this one:
checkName(output){
return output.map((NewData) => {
// find the old data item corresponding to the current NewData
const OldData = this.props.elements.find(x => x.key === NewData.key);
if (OldData) {
// If found, return a clone of the new data with the old data name
// This uses the spread syntax: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax
return {
...NewData, // Clone the NewData object
name: OldData.name, // set the value found in OldData.name in the "name" field of the cloned object
number: OldData.number, // You can do the same for each field for which you want to replace the value cloned from NewValue
};
} else {
// Otherwise, just return a clone of the NewData
return { ...NewData };
}
}
}
The usage would be like this:
const named = this.checkName(product.rows)
Be aware that the product.rows array won't be modified!
You can get keys and values of the old object.
const keys = Object.keys(oldObject);
const values = Object.values(oldObject);
// or
const [keys, values] = Object.entries(oldObject);
After, you will create a loop with all keys of oldObject, and insert in newObject like a array.
keys.forEach( (key, index) => newObject[key] = values[index]);
// or
for (const [key, value] of Object.entries(object1)) {
newObject[key] = value
}
Use map like this.
checkName(output){
return output.map(( NewData) =>{
this.props.elements.forEach((OldData) => {
if (NewData.key == OldData.key) {
NewData.name = OldData.name;
NewData.number = OldData.number;
}
})
return NewData;
})
// return output;
}

Check if array of objects has changed

I have an array that could contain objects. Objects can either be added to it or have a property modified. I want to check if the array has changed at all (could be element(s) added or simply just have one object have a key changed), and then update the DB based on the potential change.
Just wanna know if what I have will cover all cases and/or if there is a better way to do it.
const origArrayCopy = JSON.stringify(origArray);
someFnThatPotentiallyChanges(origArray);
if (origArrayCopy !== JSON.stringify(origArray)) {
updateDB(arr);
} else {
console.log('NO DIFF');
}
And here's a jsFiddle I created to test around with https://jsfiddle.net/j4eqwmp6/
Converting the object to a string using stringify should account for deep-nested changes, right? Any insights on this implementation and is there now a more appropriate way to do it?
Using JSON.stringify is certainly a possibility.
An alternative, is to wrap the object (array) in a proxy, and do that for every nested object as well. Then trap all actions that mutate those objects.
Here is how that could look:
function monitor(obj, cb) {
if (Object(obj) !== obj) return obj;
for (let key of Object.keys(obj)) {
obj[key] = monitor(obj[key], cb);
}
return new Proxy(obj, {
defineProperty(...args) {
cb();
return Reflect.defineProperty(...args);
},
deleteProperty(...args) {
cb();
return Reflect.deleteProperty(...args);
},
set(...args) {
cb();
return Reflect.set(...args);
}
});
};
// Example array
let origArray = [{x: 1}, { child: { y: 1} }];
// Activate the proxy:
let dirty = false;
origArray = monitor(origArray, () => dirty = true);
// Perform a mutation
origArray[1].child.y++;
console.log(dirty); // true
console.log(origArray);

How to pass an instance of an array to a function

I have a checkbox group that I want to get all checked items. I am trying to pass an Array to a function so I can get all checked items but it's not working.
checkedCategory: Array<number>;
contains(checkedArr: Array<number>, id: number): boolean {
if (checkedArr instanceof Array) {
return checkedArr.indexOf(id) > -1;
} else if (!!checkedArr) {
return checkedArr === id;
}
return false;
}
private add(checkedArr: Array<number>, id: number) {
if (!this.contains(checkedArr, id)) {
console.log('add: ' + checkedArr);
if (checkedArr instanceof Array) {
checkedArr.push(id);
} else {
checkedArr = [id];
}
}
}
private remove(checkedArr: Array<number>, id: number) {
const index = checkedArr.indexOf(id);
if (!checkedArr || index < 0) {
return;
}
checkedArr.splice(index, 1);
}
toggleCategory(id: number) {
if (this.contains(this.checkedCategory, id)) {
this.remove(this.checkedCategory, id);
} else {
this.add(this.checkedCategory, id);
}
}
I have a (click) event in my checkbox that will call togglecategory
(click)="toggleCategory(category.id)"
Then, when I try to console.log the 'checkedCategory' it's undefined.
I have 3 checkboxes group and I want to reuse the 'contains/add/remove' function that's why I want to pass an array.
Thank you
When you call toggleCategory(20) see what happens, in your case you will see that your function will print add: undefined. so the first thing you must debug is your add function. I think the issue is that your array is not defined. Try to initalize your empty array like this let checkedCategory: Array<number> = Array();
But either way, You need to debug your add function. Good Luck :)
If you have any questions about why this is the solution, let me know, I dont mind sharing the Theory aspect to why this occurs if you are interested.

Replacing object property name with different identifier

Here's the thing.. I want to overwite an object with if-else condition inside angular.forEach with this controller, basically "k1" has an original keyword and I want to replace it with a new keyword. what do you think is the best way to display the new input object?
$scope.SubmitKeyword = function (key, new_keyword) {
console.log(key, new_keyword)
$scope.new_keyword = new_keyword;
if ($scope.new_keyword == null || $scope.new_keyword == undefined || $scope.new_keyword == "") {
alert('Invalid input!')
return
}
angular.forEach($scope.new_campaign_keywords, function (v, k) {
console.log(v,k)
if (k == key) {
if (v['orig_keyword'] == new_keyword) {
alert('No Changes Found!')
return
} else {
console.log('changes detected')
var a = 0;
angular.forEach($scope.campaigns, function (v1,k1) {
a++
console.log(k1)
if (k1 == a) {
//display the new keyword
else {
//remain the original keyword
}
}
})
}
}
})
};
enter image description here
enter image description here
Use the hasOwnProperty method to detect the existence of a property:
$scope.SubmitKeyword = function (key, new_keyword) {
var obj = $scope.new_campaign_keywords;
console.log(key, new_keyword)
$scope.new_keyword = new_keyword;
if (!new_keyword) {
alert('Invalid input!');
return;
};
if (obj.hasOwnProperty(new_keyword)) {
alert('New keyword in use');
return;
};
//ELSE
console.log('changes detected');
obj[new_keyword] = obj[key];
delete obj[key];
};
Use the delete operator to remove the old keyword.
You have different options to do this, if you are using ES6 or Typescript you can use the spread operator to copy only certain properties from an Object
let obj= { bar: true, foo1: true, foo2:true};
if(someValidation){
let { bar, ...rest} = obj;
obj = {
...rest,
newKey: bar, //or whatever value/key you want
}
}
Now since I see ES5 code only on your code example, I would argue that you are complicating things a little bit, first of all is not a good idea to use a forEach to modify the same array you are iterating over.
Use a map function and do the changes there. You can use the delete operator to eliminate the property you don't want, but is well know that has some performance issues, so let's go with this approach:
$scope.campaigns = $scope.campaigns.map(function (v) {
a++
if (condition) {
return {
newBar: v.bar,
foo1: v.foo1,
foo2: v.foo2,
};
}
return v;
});
The other benefit is that now you are making a new array and replacing the current $scope variable value once, rather than modifying every single element, since the map return value will be done once the new list is created.
If you need to iterate over the keys dynamically you can use Object.keys to iterate over them and do the same approach, create a new object, and return it to the map, or return the same initial object.

Categories

Resources