mutability with nested objects with es6 and redux - react-native

Wrong mutation of nested object, the uom_id gets [ null, null ] and it should always have a value.
case ADD_TO_CART:
console.log('ADD TO CART', {...(JSON.parse(JSON.stringify(payload.product)))})
const ex = state.shoppingCart[`c_${payload.product.default_code}`] ? {
...(JSON.parse(JSON.stringify(state.shoppingCart[`c_${payload.product.default_code}`]))),
quantity: state.shoppingCart[`c_${payload.product.default_code}`].quantity + 1,
uom_id: [ payload.product.uom_id[0], payload.product.uom_id[1]],
section: payload.section
} : {
...(JSON.parse(JSON.stringify(payload.product))),
section: payload.section,
uom_id: [ payload.product.uom_id[0], payload.product.uom_id[1]] ,
quantity: 1
};
console.log('THIS IS THE EX, ', ex);
return {
...state,
shoppingCart: {
...state.shoppingCart,
[`c_${payload.product.default_code}`]: state.shoppingCart[`c_${payload.product.default_code}`] ? {
...(JSON.parse(JSON.stringify(state.shoppingCart[`c_${payload.product.default_code}`]))),
quantity: state.shoppingCart[`c_${payload.product.default_code}`].quantity + 1,
uom_id: [ payload.product.uom_id[0], payload.product.uom_id[1]],
section: payload.section
} : {
...(JSON.parse(JSON.stringify(payload.product))),
section: payload.section,
uom_id: [ payload.product.uom_id[0], payload.product.uom_id[1]],
quantity: 1
},
}
}
I expect the object be copied with nested levels.
ct in the image you can see the first object as the payload and after the result of ex

I think your payload object has a product object within a product object.
As such:
{
payload : {
product : {
product : {
},
section: undefined
}
}
}
Therefore you would have to use payload.product.product.uom_id[0] to get your values.
Also, I recommend using deconstructing assignments for objects and arrays to help clean up the code structure. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
Eg.
const { product: { product } } = payload
where this product variable would be the same as payload.product.product

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?

How can I automatically update a property of an object in an array when another property of the same object is updated?

My model looks like this:
export default {
data() {
return {
...
salesOrder: {
...
line_items: [{
status: 'saved',
item_number: 1,
description: 'The first line item'
cost: 458.00,
quantity: 2
}, {
status: 'saved',
item_number: 2,
description: 'The second line item'
cost: 0.589,
quantity: 3
}]
}
}
}
}
And it's used to generate a UI that looks like this:
I would like to update the status field whenever the description, quantity, or cost fields change on the same line item so that my UI would look like this:
The problem is, it doesn't look like there's any way to watch properties of an object inside an array.
I can create a computed property for the array, and watch that, but then I get the entire array as the val and newVal params:
{
computed: {
lineItems() {
return this.salesOrder.line_items;
}
},
watch: {
lineItems() {
handler(val, newVal) {
// val and newVal are the whole array
},
deep: true
}
}
}
Any suggestions? Thanks in advance for any help.

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 set nested state in vuex store?

I have a very complicated state in my application like:
state: {
formFieldList: [
{
name: 'RadioGroup',
schema: {
edit:true,
label:"Radios",
name:"Radios",
type:"radios",
values: [
{
labelName: 'default',
value: 'default',
}
{
labelName: 'default2',
value: 'default',
}
]
},
{
name: 'RadioGroup1',
schema: {
edit:true,
label:"Radios1",
name:"Radios1",
type:"radios1",
values: [
{
labelName: 'default',
value: 'default',
}
{
labelName: 'default2',
value: 'default',
}
]
},
},
],
}
As Vuejs Array Changing Caveats, I use Vue.set in my mutation.When I set values array in one fieldList item,It will update all RadioGroup values.
updateOptionValue(state, { index, optionIndex, value }) {
let values = state.formFieldList[index].schema.values;
let labelName = values[optionIndex].labelName;
Vue.set(values, optionIndex, {
labelName,
value,
});
}
How can I handle nested array update?
Here's my simple demo on codesandbox https://codesandbox.io/s/w6nq81l808
As I add two radiogrouops to the red area(click radiogroup twice), and edit the two radiosgroups simultaneously, the value will change in the same time.
You can assign state attribute to new object to make it reactive:
updateOptionValue(state, { index, optionIndex, value }) {
let values = state.formFieldList[index].schema.values;
let labelName = values[optionIndex].labelName;
values[optionIndex] = {
value,
labelName
}
state.formFieldList = JSON.parse(JSON.stringify(state.formFieldList)) // assign new object
}

Vue.js | Filters is not return

I have a problem.
I am posting a category id with http post. status is returning a data that is true. I want to return with the value count variable from the back. But count does not go back. Return in function does not work. the value in the function does not return from the outside.
category-index -> View
<td>{{category.id | count}}</td>
Controller File
/**
* #Access(admin=true)
* #Route(methods="POST")
* #Request({"id": "integer"}, csrf=true)
*/
public function countAction($id){
return ['status' => 'yes'];
}
Vue File
filters: {
count: function(data){
var count = '';
this.$http.post('/admin/api/dpnblog/category/count' , {id:data} , function(success){
count = success.status;
}).catch(function(error){
console.log('error')
})
return count;
}
}
But not working :(
Thank you guys.
Note: Since you're using <td> it implies that you have a whole table of these; you might want to consider getting them all at once to reduce the amount of back-end calls.
Filters are meant for simple in-place string modifications like formatting etc.
Consider using a method to fetch this instead.
template
<td>{{ categoryCount }}</td>
script
data() {
return {
categoryCount: ''
}
},
created() {
this.categoryCount = this.fetchCategoryCount()
},
methods: {
async fetchCategoryCount() {
try {
const response = await this.$http.post('/admin/api/dpnblog/category/count', {id: this.category.id})
return response.status;
} catch(error) {
console.error('error')
}
}
}
view
<td>{{count}}</td>
vue
data() {
return {
count: '',
}
},
mounted() {
// or in any other Controller, and set your id this function
this.countFunc()
},
methods: {
countFunc: function(data) {
this.$http
.post('/admin/api/dpnblog/category/count', { id: data }, function(
success,
) {
// update view
this.count = success.status
})
.catch(function(error) {
console.log('error')
})
},
},