Saving array and objects within said array - javascript

I am trying to make a simple to do app using vue.js, I want to try and save my to-dos that are set in the array so that when I reset the site, they still remain. Looking through some of the documentation I arrived at this:
data() {
return {
array: [
{id: 1, label: 'learn vuejs'},
]
}
},
methods: {
persist() {
localStorage.array = this.array;
alert('items saved')
}
},
mounted() {
if (localStorage.array && localStorage.array.id) {
this.array = localStorage.array;
this.array[id] = localStorage.array.id;
}
},
while this does save my array to localStorage, IT DOES NOT THE OBJECTS WITHIN. When I check localStorage in the console it shows :
array: "[object Object]"
anyone knows how to save the items within the array? if you do please explain it to me.

You need to store them as string. So localStorage.array = JSON.stringify(this.array), and when fetching from localStorage this.array = JSON.parse(localStorage.array);

Related

Object spread inside of new array

I have a Node.js program that is using Mongo Atlas search indexes and is utilizing the Aggregate function inside of the MongoDB driver. In order to search, the user would pass the search queries inside of the query parameters of the URL. That being said, I am trying to build a search object based on if a query parameter exists or not. In order to build the search object I am currently using object spread syntax and parameter short-circuiting, like so:
const mustObj = {
...(query.term && {
text: {
query: query.term,
path: ['name', 'description', 'specs'],
fuzzy: {
maxEdits: 2.0,
},
},
})
}
This is a shortened version, as there are many more parameters, but you get the jest.
In a MongoDB search query, if you have multiple parameters that must meet a certain criteria, they have to be included inside of an array called must, like so:
{
$search: {
compound: {
must: [],
},
},
}
So, in order to include my search params I must first turn my mustObj into an array of objects using Object.keys and mapping them to an array, then assigning the searches 'must' array to the array I've created, like so:
const mustArr = Object.keys(mustObj).map((key) => {
return { [key === 'text2' ? 'text' : key]: mustObj[key] };
});
searchObj[0].$search.compound.must = mustArr;
What I would like to do is, instead of creating the mustObj and then looping over the entire thing to create an array, is to just create the array using the spread syntax and short-curcuiting method I used when creating the object.
I've tried the below code, but to no avail. I get the 'object is not iterable' error:
const mustArr = [
...(query.term && {
text: {
query: query.term,
path: ['name', 'description', 'specs'],
fuzzy: {
maxEdits: 2.0,
},
},
})
]
In all, my question is, is what I'm asking even possible? And if so, how?
Corrected based on #VLAZ comment:
while spread with array [...(item)], item has to be array (iterable).
When you use short-circuit, the item as below,
true && [] ==> will be `[]` ==> it will work
false && [] ==> will be `false` ==> wont work (because false is not array)
try some thing like (Similar to #Chau's suggestion)
const mustArr = [
...(query.term ? [{
text: {
query: query.term,
path: ['name', 'description', 'specs'],
fuzzy: {
maxEdits: 2.0,
},
},
}] : [])
]

Finding value in json array and replacing it using Typscript [duplicate]

This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 2 years ago.
I have a file with 1000s of json rows like below. Im having difficulties locating a specific key in the array.
example json:
{"connection":"98374"
,"db":"8",
,"timestamp":"159905411631"
,"event":"DataCatch"
,"data":[{"key":"ruleid","value":"111"}
,{"key":"responseid","value":"155-response-4"}
,{"key":"responsetype","value":"Capture"}
,{"key":"reason","value":"ClientVisit"}
,{"key":"subreason","value":""}
,{"key":"score","value":"0.00"}
,{"key":"comment","value":""}]
}
I need to be able to find the "reason" key in the "data" array and replace the "value" with "test". The "data" array doesn't always appear on every json row, only when the "event" "dataCatch" is present.
I can parse it into a variable but I can only call the "data" array as a whole. Any ideas how to target specific values in an array?
Having a little trouble with this in Typescript.
There are any number of ways to go about this, but here's one.
First, parse your JSON into an array of objects.
Each element of the array will then look something like this:
{
connection: '98374',
db: '8',
timestamp: '159905411631'
event: 'DataCatch',
data: [
{ key: 'ruleid', value: '111' },
{ key: 'responseid', value: '155-response-4' },
{ key: 'responsetype', value: 'Capture' },
{ key: 'reason', value: 'ClientVisit' },
{ key: 'subreason', value: '' },
{ key: 'score', value: '0.00' },
{ key: 'comment', value: '' },
],
}
Let's call our array of objects allData, so we can refer to it later.
Now we can begin our "surgery".
We'll work from the inside-out, first looking at what needs to be done to a specific entry in an element's data array.
Here's a function that will do just what we need:
function updateReason(entry) {
if (entry.key === 'reason') {
return { ...entry, value: 'test' };
} else {
return entry;
}
}
This function checks if the provided entry has a key with a value of 'reason', and -- if so -- returns a new entry that is identical to the provided one except its value is 'test'.
How can we use this to update an entire data array (in an entry that has data, that is)?
We simply delegate the work to our dear friend map:
function updateData(data) {
// or simply `data.map(updateEntry);`
return data.map(entry => updateEntry(entry));
}
We're slowly working our way "outwards".
What about updating an entire entry in our big allData array (which may or may not contain data)?
// I've called such an entry a "collection", because I already used the name
// "entry" above :(
// A "collection" is just an entry in the big `allData` array.
function updateCollection(collection) {
if (collection.event === 'DataCatch') {
return {
...collection, // Leave everything else the way it is
data: updateData(collection.data), // But update the `data` array
};
} else {
return collection;
}
}
So close.
The last thing we need to do is apply this transformation to every element of our parsed allData array:
// or `allData.map(updateCollection);`
const updatedData = allData.map(collection => updateCollection(collection));
Also:
Q: Wouldn't it be cheaper to mutate the entry?
A: It would be cheaper, but not that much cheaper, due to a large amount of "structural sharing" that occurs here. I would recommend this approach unless you either need to mutate your input for some reason, or performance requirements demand it.
You need to map over the data key in your data variable like this.
data.data = data.data.map((item) => {
if (item.key === "reason") {
item.value = "test";
}
return item;
});
the data key is an array of values, so you need to loop through it and compare the value of the key property to the value you are looking for, if it matches then you can update the value property
https://codesandbox.io/s/angry-shirley-1gh83?file=/src/index.ts:666-782

Matching value of data object in VueJs

How can I retrieve the data from a data object in Vue?
I have data in this format:
datasets: [{
text:"Cars",
value: "[1,2,3]"
},
{
text:"Trains",
value: "[1,4,10]
}
]
Now I from route props I get the following info:
this.selectedText= this.$route.name;
Where this.$route.name is "Cars" for example.
Now I want to take this use this.selectedValue to get corresponding Value from this array:
so if this.selectedText="Cars" then this.selectedValue=[1,2,3] or based on this I want to retrieve the value of given text.
Create a method and use this code to find out the matching one.
function setSelectedValue() {
let matchingDatSet = this.datasets.find(ele => ele.text == this.selectedText);
if(matchingDataSet !== undefined) {
this.selectedValue = matchingDataSet.value;
}
}

Vue computed property changes the data object

I have basically this structure for my data (this.terms):
{
name: 'First Category',
posts: [
{
name: 'Jim James',
tags: [
'nice', 'friendly'
]
},
{
name: 'Bob Ross',
tags: [
'nice', 'talkative'
]
}
]
},
{
name: 'Second Category',
posts: [
{
name: 'Snake Pliskin',
tags: [
'mean', 'hungry'
]
},
{
name: 'Hugo Weaving',
tags: [
'mean', 'angry'
]
}
]
}
I then output computed results so people can filter this.terms by tags.
computed: {
filteredTerms: function() {
let self = this;
let terms = this.terms; // copy original data to new var
if(this.search.tags) {
return terms.filter((term) => {
let updated_term = {}; // copy term to new empty object: This doesn't actually help or fix the problem, but I left it here to show what I've tried.
updated_term = term;
let updated_posts = term.posts.filter((post) => {
if (post.tags.includes(self.search.tags)) {
return post;
}
});
if (updated_posts.length) {
updated_term.posts = updated_posts; // now this.terms is changed even though I'm filtering a copy of it
return updated_term;
}
});
} else {
return this.terms; // should return the original, unmanipulated data
}
}
},
filteredTerms() returns categories with only the matching posts inside it. So a search for "angry" returns just "Second Category" with just "Hugo Weaving" listed.
The problem is, running the computed function changes Second Category in this.terms instead of just in the copy of it (terms) in that function. It no longer contains Snake Pliskin. I've narrowed it down to updated_term.posts = updated_posts. That line seems to also change this.terms. The only thing that I can do is reset the entire data object and start over. This is less than ideal, because it would be loading stuff all the time. I need this.terms to load initially, and remain untouched so I can revert to it after someone clears their search criterea.
I've tried using lodash versions of filter and includes (though I didn't really expect that to make a difference). I've tried using a more complicated way with for loops and .push() instead of filters.
What am I missing? Thanks for taking the time to look at this.
Try to clone the object not to reference it, you should do something like :
let terms = [];
Object.assign(terms,this.terms);
let terms = this.terms;
This does not copy an array, it just holds a reference to this.terms. The reason is because JS objects and arrays are reference types. This is a helpful video: https://www.youtube.com/watch?v=9ooYYRLdg_g
Anyways, copy the array using this.terms.slice(). If it's an object, you can use {...this.terms}.
I updated my compute function with this:
let terms = [];
for (let i = 0; i < this.terms.length; i++) {
const term = this.copyObj(this.terms[i]);
terms.push(term);
}
and made a method (this.copyObj()) so I can use it elsewhere. It looks like this:
copyObj: function (src) {
return Object.assign({}, src);
}

How to update only one specific property of nested object in associative array

I have associative array.
It's a key(number) and value(object).
I need to keep state of this array same as it is I just need to update one object property.
Example of array:
5678: {OrderId: 1, Title: "Example 1", Users: [{UserId: 1}, {UserId: 2}, {UserId: 3}]}
5679: {OrderId: 2, Title: "Example 2", Users: [{UserId: 1}, {UserId: 2}, {UserId: 3}]}
I need to update Users array property.
I tried this but it doesn't work:
ordersAssociativeArray: {
...state.ordersAssociativeArray,
[action.key]: {
...state.ordersAssociativeArray[action.key],
Users: action.updatedUsers
}
}
This is data inside reducer.
What I did wrong how to fix this?
Something that might help.
When I inspect values in chrome I check previous value and value after execution of my code above:
Before:
ordersAssociativeArray:Array(22) > 5678: Order {OrderId: ...}
After:
ordersAssociativeArray: > 5678: {OrderId: ...}
Solution (code in my reducer)
let temp = Object.assign([], state.ordersAssociativeArray);
temp[action.key].Users = action.updatedUsers;
return {
...state,
ordersAssociativeArray: temp
}
So this code is working fine.
But I still don't understand why? So I have solution but would like if someone can explain me why this way is working and first not?
If it could help here how I put objects in this associative array initialy:
ordersAssociativeArray[someID] = someObject // this object is created by 'new Order(par1, par2 etc.)'
What you are doing is correct, as demonstrated by this fiddle. There may be problem somewhere else in your code.
Something that I would recommend for you is to separate your reducer into two functions, ordersReducer and orderReducer. This way you will avoid the excessive use of dots, which may be what caused you to doubt the correctness of your code.
For example, something like:
const ordersReducer = (state, action) => {
const order = state[action.key]
return {
...state,
[action.key]: orderReducer(order, action)
}
}
const orderReducer = (state, action) => {
return {
...state,
Users: action.updatedUsers
}
}
I hope you find your bug!
Update
In your solution you use let temp = Object.assign([], state.ordersAssociativeArray);. This is fine, but I thought you should know that it is sometimes preferable to use a {} even when you are indexing by numbers.
Arrays in javascript aren't great for representing normalized data, because if an id is missing the js array will still have an undefined entry at that index. For example,
const orders = []
array[5000] = 1 // now my array has 4999 undefined entries
If you use an object with integer keys, on the other hand, you get nice tightly packed entries.
const orders = {}
orders[5000] = 1 // { 5000: 1 } no undefined entries
Here is an article about normalizing state shape in redux. Notice how they migrate from using an array in the original example, to an object with keys like users1.
The problem can be that you're using array in the state but in the reducer you're putting as object. Try doing:
ordersAssociativeArray: [ //an array and not an object
...state.ordersAssociativeArray,
[action.key]: {
...state.ordersAssociativeArray[action.key],
Users: action.updatedUsers
}
]
It will put ordersAssociative array in your state and not an object.

Categories