Why does ReactJS render [object Object] instead of array.name? - javascript

I want to filter an array of objects based on a boolean value, so it returns new array of objects that only contains objects with "true" value.
here is my base array:
const extrasList = [
{key: 0, name: "extraNew1", price: 20, active: true },
{key: 1, name: "extraNew2", price: 100, active: false },
{key: 2, name: "extraNew3", price: 400, active: false },
]
here is how I used .filter method to get only "active: true" objects:
const activeExtras = extrasList.filter((extra) => {
return extra.active;
});
and now, to display just names in objects, I used .map method:
const aExtrasList = activeExtras.map((extra) => {
return (
<div key={extra.key}>
<p>{extra.name} </p>
</div>
);
})
I expected React to render "extraNew1", but instead I got "[object Object]"... what am I missing?
Edit: The code above renders fine, the problem occurs when I try to put it inside of this variable:
const toSend = [`name: ${name} - model: ${activeModel} - extra: - ${aExtrasList}`];
Note: name and activeModel are declared in no relation to aExtrasList.

const extrasList = [
{key: 0, name: "extraNew1", price: 20, active: true },
{key: 1, name: "extraNew2", price: 100, active: false },
{key: 2, name: "extraNew3", price: 400, active: false },
]
const activeExtras = extrasList.filter((extra) => {
return extra.active;
});
return(
<>
{
activeExtras.map(extra => {
return(
<div key={extra.key}>
<p>{extra.name} </p>
</div>
)
})
}
</>
);

Related

How to transform only 2 properties but keep remaining same as is in a nested object structure?

Apologies if title is not clear.
I am using json2csv npm package to prepare csv from json object and this package allows us to add a hook to transform object before actual csv line is prepared.
I only need to manipulate two properties out of all. How can I do this effectively? My code feels too bloated.
const {
Parser: Json2csvParser,
transforms: { unwind },
} = require('json2csv');
const json2csvFields = [
{ value: 'root.filename', label: 'File Name' },
{ value: 'issue.root.priority', label: 'Priority' },
{ value: 'issue.root.url', label: 'URL' },
{ value: 'issue.root.startline', label: 'Start Line' },
{ value: 'issue.root.stopline', label: 'Stop Line' },
{ value: 'issue.root.startcolumn', label: 'Start Column' },
{ value: 'issue.root.stopcolumn', label: 'Stop Column' },
{ value: 'issue.root.issuename', label: 'Issue Name' },
{ value: 'issue.root.issuecategory', label: 'Issue Category' },
{ value: 'issue._', label: 'Issue Description' },
];
const sampleData = [
{
root: {
filename:
'/home/users/john-doe/workspace/foo-project/src/main/classes/foo.cls',
},
issue: {
root: {
priority: 1,
url: 'www.example.com',
startline: 100,
stopline: 105,
startcolumn: 20,
stopcolumn: 25,
issuename: 'blah',
issuecategory: 'Category A',
},
_: ' Fox ',
},
},
];
const json2csvOptions = {
fields: json2csvFields,
quote: '',
header: true,
transforms: [
(item) => ({
'root.filename': item.root.filename.replace(
'/home/users/john-doe/workspace/foo-project/src/main/classes/',
''
),
'issue._': `"${item.issue._.trim()}"`,
// Except for the above two, everything else doens't need any transformation.
'issue.root.priority': item.issue.root.priority,
'issue.root.url': item.issue.root.url,
'issue.root.startline': item.issue.root.startline,
'issue.root.stopline': item.issue.root.stopline,
'issue.root.startcolumn': item.issue.root.startcolumn,
'issue.root.stopcolumn': item.issue.root.stopcolumn,
'issue.root.issuename': item.issue.root.issuename,
'issue.root.issuecategory': item.issue.root.issuecategory,
}),
],
};
const json2csvParser = new Json2csvParser(json2csvOptions);
const csv = json2csvParser.parse(sampleData);
console.log(csv);
This prints below output:
File Name,Priority,URL,Start Line,Stop Line,Start Column,Stop Column,Issue Name,Issue Category,Issue Description
foo.cls,1,www.example.com,100,105,20,25,blah,Category A,"Fox"
EDIT: Updated code to a working example.
After listing the two properties with special treatment, use Object.fromEntries and Object.entries to transform all the issue.root properties to their flat structure with .s in the property names. Then that object can be spread into the returned object.
const transformsFn = ({ root, issue }) => ({
'root.filename': root.filename.replace(
'/home/users/john-doe/workspace/foo-project/src/main/classes/',
''
),
'issue._': `"${issue._.trim()}"`,
...Object.fromEntries(
Object.entries(issue.root).map(
([key, val]) => [`issue.root.${key}`, val]
)
),
});
const json2csvOptions = {
fields: json2csvFields,
quote: '',
header: true,
transforms: [transformsFn],
};

Recursive function and React in Crome debug VM - a mess

First, let me explain what I want to do.
I have tree-like data structure, with arbitrary depth from which i want to make a list of all non-leaf branches which I pass as props to Child component.
Data set and recursive function are bellow.
Problem:
I get double data in array! I noticed that function getBranches() is called also in chrome VM and it just appends same data again to already existing array. See pic bellow.
Is my approach fundamentally wrong? What to do?
const treeData = {
'first-level-node-1': { // key
label: 'Regija',
type: TYPES[1],
index: 0, // rendering order
url: 'http://opa.com',
nodes: {
'second-level-node-1': {
label: 'Bolnica BN',
index: 0,
type: 1,
nodes: {
'third-level-node-1': {
label: 'Konektor Sysmex',
index: 0,
nodes: {},
type: TYPES[0]
},
},
},
},
},
'first-level-node-2': {
label: 'Regija 2',
index: 1,
type: TYPES[1],
nodes: {
'2-1': {
label: 'Dz Trebinje',
index: 0,
type: 1,
nodes: {
'3-1': {
label: 'Konektor Biomerux',
index: 0,
hasNodes: false,
type: TYPES[0],
}
}
}
}
},
};
My getBranches() function:
const getBranches = (treeData) => {
console.log('i= ',i++)
Object.keys(treeData).forEach((key) => {
if (treeData[key].type!==TYPES[0]) {
branches.push({key: key, label: treeData[key].label});
console.log({key: key, label: treeData[key].label})
treeData[key].nodes && getBranches(treeData[key].nodes)
};
});
return [...branches];
};
My Component:
const Sites = () => {
const branches = getBranches(treeData);
console.log(branches);
//const [data, setData] = useState(treeData);
return (
<Container fluid="md">
<Row>
<Col>
<MyTreeView data={treeData}/>
</Col>
<Col>
<BranchView
sites={treeData}
parentList={branches}
/>
</Col>
</Row>
</Container>
);
};
Some additional info:
branch vs leaf is distinguished by property type
The Picture. Notice the i s
I'm guessing the problem is simply that you don't declare branches inside your function, making it a global variable. So the next time the function is run, you're appending to it. Adding a const declaration should probably do.
That said, I think you can simplify getBranches in a clean manner:
const getBranches = (o) => Object .entries (o) .flatMap (
([key, {label, type, nodes}]) => [
... (type == TYPES [0] ? [] : [{key, label}]),
... (nodes ? getBranches (nodes) : [])
]
)
const TYPES = [0, 1]
const treeData = {"first-level-node-1": {label: "Regija", type: TYPES[1], index: 0, url: "http: //opa.com", nodes: {"second-level-node-1": {label: "Bolnica BN", index: 0, type: 1, nodes: {"third-level-node-1": {label: "Konektor Sysmex", index: 0, nodes: {}, type: TYPES[0]}}}}}, "first-level-node-2": {label: "Regija 2", index: 1, type: TYPES[1], nodes: {"2-1": {label: "Dz Trebinje", index: 0, type: 1, nodes: {"3-1": {label: "Konektor Biomerux", index: 0, hasNodes: false, type: TYPES[0]}}}}}}
console .log (getBranches (treeData))
.as-console-wrapper {max-height: 100% !important; top: 0}

Vue JS lodash findKey nested object with dot notation returns undefined

I'm trying to pull out a value for a nested object key from some eligibility array that I've got, but I'm getting an undefined value for some reason and need to know what I'm missing.
Given the following array:
const eligibilityCriteria = [
{ field: 'loan.amount', operator: '>=', value: 1000 },
{ field: 'loan.term', operator: '>=', value: 1 },
{ field: 'applicant.birthday', operator: '>=', value: 40 },
{ field: 'applicant.isHomeowner', operator: '==', value: false }
]
I need to find loan.amount from a nested object and pull out it's value:
My big nested object is (coming from the store)
application: {
meta: {
brand: '',
version: '',
affiliate: '',
affiliate_full: '',
campaign: '',
client_hostname: '',
client_href: '',
client_origin: '',
client_useragent: '',
client_ip: '127.0.0.1',
icicle_hash: ''
},
loan: {
amount: 500,
term: null,
purpose: null
}
}
My function right now is:
checkEligibility () {
const eligibilityCriteria = [
{ field: 'loan.amount', operator: '>=', value: 1000 },
{ field: 'loan.term', operator: '>=', value: 1 },
{ field: 'applicant.birthday', operator: '>=', value: 40 },
{ field: 'applicant.isHomeowner', operator: '==', value: false }
]
for (const [index, offer] of this.datasets.offers.entries()) {
const eligibility = eligibilityCriteria
if (eligibility) {
for (const [ci, criteria] of eligibility.entries()) {
// TODO: this fails to pull the value, returns undefined
const field = _.findKey(this.$store.state.application.application, criteria.field)
}
}
}
}
What am I missing?
You must have to misunderstood what _.findKey() does
This method is like _.find except that it returns the key of the first element predicate returns truthy for instead of the element itself.
See Example 2 in the code below.
If you want to retrieve the value from the object at a given path, you must use _.property() (Example 2 below)
const eligibilityCriteria = [
{ field: 'loan.amount', operator: '>=', value: 1000 },
{ field: 'loan.term', operator: '>=', value: 1 },
]
const application = {
loan: {
amount: 500,
term: 2,
amount2: 0,
}
}
// example 1
// outputs "loan"
console.log(_.findKey(application, "amount"))
// outputs undefined - there is no key in application object that has property chain "loan.amount"
console.log(_.findKey(application, "loan.amount"))
// outputs undefined - "amount2" key is there but the value is falsy
console.log(_.findKey(application, "amount2"))
// example 2
for (const [ci, criteria] of eligibilityCriteria.entries()) {
console.log(criteria.field, _.property(criteria.field)(application))
}
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.21/lodash.min.js"></script>

render nested arrays with react by display key only once

I have a nested array and I would like to render this array with JSX code such that key like array1 should be display once and the text should be displayed as list and then continue the same loop with the next array. I have tried using map function and for loop but could not achieve success.
sampleArray : [{"array1": [ {"text": "abc"},{"text": "def"}, {"text": "ghi"}],
"array2":[{"text": "efg"}, {"text": "fgh"}]]
Please suggest me map function to iterate over this array to render into JSX code. Thanks
Hey I don't know if you made a mistake in your object, but here are two versions of this implementation with your object and with my update:
Ignore typings did it in TypeScript
export const Test = ({ className }: Test) => {
const sampleArray = [
{
array1: [{ text: 'abc' }, { text: 'def' }, { text: 'ghi' }],
array2: [{ text: 'efg' }, { text: 'fgh' }],
},
]
const sampleArray2 = [
{
array1: [{ text: 'abc' }, { text: 'def' }, { text: 'ghi' }],
},
{
array2: [{ text: 'efg' }, { text: 'fgh' }],
},
]
return (
<>
{/* YOUR VERSION */}
<div>
{Object.keys(sampleArray[0]).map((key) => {
return (
<div>
<div id="title">{key}</div>
{sampleArray[0].map((item) => {
return <div>{item.text}</div>
})}
</div>
)
})}
</div>
{/* UPDATED VERSION */}
<div>
{sampleArray2.map((key) => {
const title = Object.keys(key)[0]
return (
<div>
<div id="title">{title}</div>
{key[title].map((item) => {
return <div>{item.text}</div>
})}
</div>
)
})}
</div>
</>
)
}

How to change property of item in ImmutableList({}) inside Immutable.Map({})

How do I change property of item in ImmutableList({}) that is inside Immutable.Map({})?
I have:
const initialState = Immutable.Map({
width: window.board.width,
height: window.board.height,
lines: Immutable.List([
Immutable.Map({id: 1, active: false, name: 'Some name'}),
Immutable.Map({id: 2, active: false, name: 'Sad name'}),
Immutable.Map({id: 3, active: true, name: 'Cool name'})
])
});
Lets say I want to set item with id 1 in the List. Then change its property active to true. I also want to set property active to false for all the other items in the List.
How do I do that? Thanks a lot in advance.
Edit (final solution):
export function activateLine(lineId) {
return function (dispatch, getState) {
const updatedLines = getState().board.update('lines', Immutable.List(),
(oldList) => oldList.map((listItem) => {
return listItem.set("active", (listItem.get("id") === lineId));
})).get('lines');
return dispatch({
type: types.ACTIVATE_LINE,
payload: updatedLines
});
};
}
You can traverse immutable like so (quick note though i would highly recommend you make the entire object immutable). You can keep down the lines of code and keep it a bit more elegant by just using immutable itself -
const changeImmutableObject = initialState.update('lines', Immutable.List(),
(oldList) => oldList.map((listItem) => {
if(listItem.get("id") === 1) {
return listItem.set("active", true);
} else {
return listItem.set("active", false);
}
})
)
See working fiddle - https://jsfiddle.net/o04btr3j/214/
This updates the list key inside your object (if it is not there for whatever reason it defaults to an immutable list), then maps over the properties. If it has an id of 1, it will set active to true, otherwise it will set active to false.
You can also just initialState.toJS() your immutable object and do your logic in plain js, or do and immutableobject.get('property') and modify and then set that back in your object, however I would recommend you just use the built in methods in immutable as it is much less code.
Also, If I'm not mistaken you can just do something like this :
const initialState = Immutable.fromJS({
width: window.board.width,
height: window.board.height,
lines:[
{id: 1, active: false, name: 'Some name'},
{id: 2, active: false, name: 'Sad name'},
{id: 3, active: true, name: 'Cool name'}
]
});
You can immutable.fromJS() an object to put it into an immutable object. And all immutable objects should have a .toJS method on them to turn them back into regular javascript objects/lists/whatever.
I have created lithe example on link to solution on jsbin.com
const initialState = Immutable.Map({
lines: Immutable.List([
Immutable.Map({id: 1, active: false, name: 'Some name'}),
Immutable.Map({id: 2, active: false, name: 'Sad name'}),
Immutable.Map({id: 3, active: true, name: 'Cool name'})
])
});
console.log('initialState', initialState.toJS())
// update lines, map over items and set active to false
const stateLinesAllNotActive = initialState.updateIn(
['lines'],
items => items.map((item) => item.set('active', false))
)
console.log('stateLinesAllNotActive', stateLinesAllNotActive.toJS())
// lines and key for item with id === 1, then set active to this item
const stateFirstActive = stateLinesAllNotActive.updateIn(
[
'lines',
stateLinesAllNotActive.get('lines').findIndex((item) => (item.get("id") === 1))
],
item => item.set("active", true)
)
console.log('stateFirstActive', stateFirstActive.toJS())
What follows should work, but, as someone said... I think could be better a full update...
const initialState = Immutable.Map({
lines: Immutable.List([
Immutable.Map({id: 1, active: false, name: 'Some name'}),
Immutable.Map({id: 2, active: false, name: 'Sad name'}),
Immutable.Map({id: 3, active: true, name: 'Cool name'})
])
});
let lines = initialState.get('lines');
let id = 1; // what you want update...
let updater = item => {
let updated = item.set('name', "Giuseppe");
return updated;
};
let index = lines.findIndex((i) => i.get("id") === id);
let result = lines.update(index, updater);
initialState.set("lines", result);
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>

Categories