Unable to copy an array to an array using vue.js - vue.js

I have a multiple selectbox using vuetify select component. I'm getting array of selected items and I want to merge status as true of selected items like [ { "ward": 1, "status": true }, { "ward": 2, "status": true} ]
I'm trying to copy selected items of array to another array but couldn't succeed. In console, I got selectedFruits as below.
methods: {
save() {
console.log(this.selectedFruits);
debugger;
this.selectedIndex.push({ ward: this.selectedFruits, status: true });
console.log(this.list);
},

You can try this
save(){
this.list = []
this.selectedFruits.forEach(e => {
this.list.push({ ward: e, status: true });
});
console.log(this.list)
}

If you want to copy an array or object without passing it by reference, do it like this
const newArray = JSON.parse(JSON.stringify(oldArray));

You can use the Spread-Operator for this.
Here an example:
const existingArr = [{ hi: 'foobar' }];
const arr = [{ a: 'foo', b: 'bar'}, { a: 'hello', b: 'world'}]
const newArr = [...existingArr, ...arr]
console.log(newArr)

Related

How to store array of object in react nativr async storage

I'm trying to set an array of objects in React Native AsyncStorage.
However, just the 1st item will store in it.
await AsyncStorage.setItem(
`${props.index}`,
JSON.stringify({
data: totalSet,
name: props.index,
date: today.toISOString().substring(0, 10),
})
the first item (data) is an array
Update
In my workout tracker app,
I try to create nested object. in the child component, I have following data:
weight: number
reps: number
result: also number (combination of weight and reps)
setIndex :number, which indicate the index of each sets
I have sent above data to parent component like this:
Child component
onPress={() =>
childToParent({
setDetails: [
{
setIndex: setIndex,
result: result,
weight: weight,
reps: reps,
},
],
}) + buttonStatus()
in the parent, I have given data, and trying to add into exsiting array and also adding 2 more item, date and index of each workout
parent component
const [totalSet, settotalSet] = useState([{ today }, { index }]);
useEffect(() => {
if (data != 0) {
settotalSet((current) => [...current, data]);
}
}, [data]);
then I store it into asyncstorage
const storeData = async () => {
try {
await AsyncStorage.setItem(
`${props.index}`,
JSON.stringify(totalSet)
).then((res) => console.log(res));
} catch (e) {
// saving error
}
};
and get it into another component like this
getMyObject = async () => {
try {
await AsyncStorage.getItem('1512').then((res) => {
setData(JSON.parse(res));
});
} catch (e) {
// read error
}
};
Finally as a result, I have below array:
Array [
Object {
"today": "2022-09-04",
},
Object {
"index": "1512",
},
Object {
"setDetails": Array [
Object {
"reps": "3",
"result": 13.200000000000001,
"setIndex": 0,
"weight": "12",
},
],
},
Object {
"setDetails": Array [
Object {
"reps": "3",
"result": 26.400000000000002,
"setIndex": 1,
"weight": "24",
},
],
},
]
everything is fine, except I need a nested object and this is an array.
How to create such an nested object at the first place?

Filtering 2 or more categories in vue.js

I have a code where i filtered an array with a specific category.
response.data.items.filter(item => item.category_id === categ_id_1)
Now i want to add more categories in the filter (categ_id_2, categ_id_3). How do i do that?
Assuming the category_id is a primitive (ie string, number, etc), the easiest way I can think of is to maintain a Set of wanted categories and use Set.prototype.has() for filtering.
const categories = new Set(['categ_id_1', 'categ_id_2', ...])
response.data.items.filter(({ category_id }) => categories.has(category_id))
If you're wanting the list to be reactive in Vue, something like this...
data: () => ({
categoryFilters: ['categ_id_1', 'categ_id_2']
}),
computed: {
categoryFilterSet () {
return new Set(this.categoryFilters)
}
},
methods: {
async loadAndFilterData () {
const response = await axios({...}) // just guessing
const filtered = response.data.items.filter(({ category_id }) =>
this.categoryFilterSet.has(category_id))
}
}
The reason for using the computed property is that Vue does not work reactively with Set so you must back it up with an array.
Another way using Array.prototype.includes() which is used to pass/fail the test of filter for each element.
const items = [{
"a": 1,
"category_id": "categ_id_1"
}, {
"a": 2,
"category_id": "categ_id_2"
}, {
"a": 3,
"category_id": "categ_id_3"
}, {
"a": 4,
"category_id": "categ_id_4"
}, {
"a": 5,
"category_id": "categ_id_5"
}];
const search = ["categ_id_2", "categ_id_3"];
const result = items.filter(e => search.includes(e.category_id));
console.info("result::", result);
Try it as
response.data.items.filter(item => item.category_id === categ_id_1 ||item.category_id === categ_id_2 ||item.category_id === categ_id_3)

Vuejs: Cannot set property 'profile_picture' of undefined

I'm really confused whats wrong with my code. Can someone tell me what I did wrong here.
data() {
return {
users: [],
}
},
methods:{
moveData(response){
for(var x=0;x<response.data.data.length; x++){
this.users[x].profile_picture = response.data.data[x].profile_picture;
this.users[x].age = response.data.data[x].age;
this.users[x].intro = response.data.data[x].introMessage;
this.users[x].name = response.data.data[x].userName;
}
// eslint-disable-next-line
console.log('Users',this.users);
}
}
as the error suggests that this.users[x] is undefined. the simple solution would be to initialize this.users[x] with some empty object just like
for(var x=0;x<response.data.data.length; x++){
this.users[x] = {};
this.users[x].profile_picture = response.data.data[x].profile_picture;
this.users[x].age = response.data.data[x].age;
this.users[x].intro = response.data.data[x].introMessage;
this.users[x].name = response.data.data[x].userName;
}
As you using this.users[x], it always undefined because your array length is 0. So here one way more you can use .map() array to modify the field name and directly assign response to your users in moveData.
By use of Map array with spread operator
const response = [{
profile_picture: 'https://image.flaticon.com/icons/svg/149/149452.svg',
age: 25,
introMessage: 'Hello',
userName: 'test105'
}, {
profile_picture: 'https://image.flaticon.com/icons/svg/149/149452.svg',
age: 18,
introMessage: 'HI',
userName: 'demo105'
}]
console.log(response.map(({age,profile_picture,...r}) => Object.create({
age,
profile_picture,
name: r.userName,
intro: r.introMessage
})));
Modification in your code, use push method of array
const response = {
data: {
data: [{
profile_picture: 'https://image.flaticon.com/icons/svg/149/149452.svg',
age: 25,
introMessage: 'Hello',
userName: 'test105'
}, {
profile_picture: 'https://image.flaticon.com/icons/svg/149/149452.svg',
age: 18,
introMessage: 'HI',
userName: 'demo105'
}]
}
}
let users = [];
for (var x = 0; x < response.data.data.length; x++) {
users.push({
profile_picture: response.data.data[x].profile_picture,
age: response.data.data[x].age,
intro: response.data.data[x].introMessage,
name: response.data.data[x].userName
});
}
console.log(users)

Vue.js with iView Table - accessing Elasticsearch search response object

I am using the iView UI kit table in my Vue.js application that consumes an Elasticsearch API with axios. My problem is that I just can't seem to get to access the nested search response object, which is an array list object. I only get to access the 1st level fields, but not the nested ones. I don't know how to set the table row key in the iView table.
This is how my axios call and mapper methods look like:
listObjects(pageNumber){
const self = this
self.$Loading.start()
self.axios.get("/api/elasticsearch/")
.then(response => {
self.ajaxTableData = self.mapObjectToArray(response.data);
self.dataCount = self.ajaxTableData.length;
if(self.ajaxTableData.length < self.pageSize){
self.tableData = self.ajaxTableData;
} else {
self.tableData = self.ajaxTableData.slice(0,self.pageSize);
}
self.$Loading.finish()
})
.catch(e => {
self.tableData = []
self.$Loading.error()
self.errors.push(e)
})
},
mapObjectToArray(data){
var mappedData = Object.keys(data).map(key => {
return data[key];
})
return mappedData
},
The iView table columns look like this:
tableColumns: [
{
title: 'Study Date',
key: 'patientStudy.studyDate',
width: 140,
sortable: true,
sortType: 'desc'
},
{
title: 'Modality',
key: "generalSeries.modality",
width: 140,
sortable: true
},
...
]
The (raw) Elasticsearch documents look like this:
[
{ "score":1, "id":"3a710fa2c1b3f6125fc168c9308531b59e21d6b3",
"type":"dicom", "nestedIdentity":null, "version":-1, "fields":{
"highlightFields":{
},
"sortValues":[
],
"matchedQueries":[
],
"explanation":null,
"shard":null,
"index":"dicomdata",
"clusterAlias":null,
"sourceAsMap":{
"generalSeries":[
{
"seriesInstanceUid":"999.999.2.19960619.163000.1",
"modality":"MR",
"studyInstanceUid":"999.999.2.19960619.163000",
"seriesNumber":"1"
}
],
"patientStudy":[
{
"studyDate":"19990608"
}
]
}
}
]
And this is how the consumed object looks like:
As you can see, the fields I need to access are within the "sourceAsMap" object, and then nested in arrays.
How can I provide the iView table cell key to access them?
UPDATE:
I now "remapped" my Elasticsearch object before displaying it in the Vue.js table, and it works now. However, I don't think that the way I did it is very elegant or clean....maybe you can help me to do it in a better way. This is my method to remap the object:
getData(data){
let jsonMapped = []
for(let i = 0; i < data.length; i++){
let id = {}
id['id'] = data[i].id
let generalData = data[i]['sourceAsMap']['generalData'][0]
let generalSeries = data[i]['sourceAsMap']['generalSeries'][0]
let generalImage = data[i]['sourceAsMap']['generalImage'][0]
let generalEquipment = data[i]['sourceAsMap']['generalEquipment'][0]
let patient = data[i]['sourceAsMap']['patient'][0]
let patientStudy = data[i]['sourceAsMap']['patientStudy'][0]
let contrastBolus = data[i]['sourceAsMap']['contrastBolus'][0]
let specimen = data[i]['sourceAsMap']['specimen'][0]
jsonMapped[i] = Object.assign({}, id, generalData, generalSeries, generalImage, generalEquipment, patient,
patientStudy, contrastBolus, specimen)
}
return jsonMapped
},
The result is this:
Even though it now works, but how can I optimize this code?
A few functions can help you with your situation
let data = [{
key1: ['k1'],
key2: ['k2'],
key3: [{
subKey1: 'sk1',
subKey2: ['sk2'],
subObject: [{ name: 'John', surname: 'Doe' }],
items: [1, 2, 3, 5, 7]
}]
}];
function mapIt(data) {
if (isSingletonArray(data)) {
data = data[0];
}
for(const key in data) {
if (isSingletonArray(data[key])) {
data[key] = mapIt(data[key][0]);
} else {
data[key] = data[key];
}
}
return data;
}
function isSingletonArray(obj) {
return typeof obj === 'object' && Array.isArray(obj) && obj.length === 1;
}
console.log(mapIt(data));
Outputs:
{
key1: 'k1',
key2: 'k2',
key3: {
subKey1: 'sk1',
subKey2: 'sk2',
subObject: { name: 'John', surname: 'Doe' },
items: [ 1, 2, 3, 5, 7 ]
}
}
You can check it in your browser. mapIt unwraps the singleton arrays into objects or primitives.
But I recommend you to watch out special elastic client libraries for javascript. It could save you from writing extra code.

How to chain get and map the result with lodash?

I've got a list I'm trying to pull an object from using _.get but following that selection I need to loop over the object to create a new property. So far I've been successful using a combination of _.get and _.map as shown below but I'm hoping I can use _.chain in some way.
var selected = _.get(results, selectedId);
return _.map([selected], result => {
var reviews = result.reviews.map(review => {
var reviewed = review.userId === authenticatedUserId;
return _.extend({}, review, {reviewed: reviewed});
});
return _.extend({}, result, {reviews: reviews});
})[0];
Is it possible to do a transform like this using something other than map (as map required me to break this up/ creating an array with a solo item inside it). Thank you in advance!
I can see that you're creating unnecessary map() calls, you can simply reduce all those work into something like this:
var output = {
reviews: _.map(results[selectedId], function(review) {
return _.defaults({
reviewed: review.userId === authenticatedUserId
}, review);
})
};
The defaults() method is similar to extend() except once a property is set, additional values of the same property are ignored.
var selectedId = 1;
var authenticatedUserId = 1;
var results = {
1: [
{ userId: 1, text: 'hello' },
{ userId: 2, text: 'hey' },
{ userId: 1, text: 'world?' },
{ userId: 2, text: 'nah' },
]
};
var output = {
reviews: _.map(results[selectedId], function(review) {
return _.defaults({
reviewed: review.userId === authenticatedUserId
}, review);
})
};
document.body.innerHTML = '<pre>' + JSON.stringify(output, 0, 4) + '</pre>';
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>