I have an array of object and want display in a single line in ReactJS. The object look like:
[
{
name:"jane",
age : "20"
},
{
name:"mary",
age : "21"
}
{
name:"john",
age : "19"
}
]
I want display the result to be :
jane 20, mary 21, john 19
e.g
<span className="name>data.name</span> <span className="age>data.age</span>
I have a function but that concat the value but not sure now to get my desire output
const getData = () => {
var val = ''
roles.map((data, inx) => {
val = val + data.name + data.age
})
return (
<span>{val}</span>
)
}
how can I do this
Concatenating like
val = val + data.name + data.age
won't work, because you want JSX elements (spans), not plain strings.
When mapping, check the index. If the index is 1 or more, add a comma before the first span when creating the JSX.
const arr = [
{
name:"jane",
age : "20"
},
{
name:"mary",
age : "21"
},
{
name:"john",
age : "19"
}
]
const App = () => {
return arr.map(({ name, age }, i) => (
<React.Fragment>
{i === 0 ? null : ','}
<span className="name">{name}</span> <span className="age">{age}</span>
</React.Fragment>
));
};
ReactDOM.render(<App />, document.querySelector('.react'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div class='react'></div>
Related
I am creating an app with react js and it has a function to add data into an array. Now I need to check if a value already exists in an array.
I have an array in state variable like this "Question: []".
My array data like below and "QuesID","OpId","option" has different values.
[
{"QType":"Rating","QuesID":20,"OpId":1,"option":1},
{"QType":"Rating","QuesID":21,"OpId":1,"option":1},
]
if I send data {"QType":"Rating","QuesID":20,"OpId":2,"option":1} like this need to remove the previous value from an array and add this new value to an array.
This is what I tried,
addData= (event, item) => {
var QType = "Rating";
var QuesID = "22";
var OpId = "1";
var option = "1";
var Qobj = { QType: QType, QuesID: QuesID, OpId: OpId, option: option };
if (this.state.Question.find((item) => item.OpId === OpId) !== undefined) {
console.log("item exist");
} else {
console.log("item not exist");
this.state.Question.push(Qobj);
}
console.log(this.state.Question);
}
when it come data like this {"QType":"Rating","QuesID":20,"OpId":2,"option":1}, need to remove if it has a value with "QuesID"=20 and add the new value coming with "QuesID"=20.
And also it will come data like below.
[{QType: "Rating", QuesID: "22", OpId: "4", option: "4"},
{QType: "Rating", QuesID: "23", OpId: "3", option: "3"},
{QType: "Rating", QuesID: "24", OpId: "2", option: "2"},
{QType: "Rating", QuesID: "25", OpId: "1", option: "1"}]
How can I fix this?
Full Code
import React, { Component } from "react";
import fullStarSrc from "../img/highlightedStar.png";
import emptyStarSrc from "../img/star.png";
export default class testPage extends Component {
state = {
qtemp2: [
{ idsurveyquestion: "22", question: "Taste of the food?" },
{ idsurveyquestion: "23", question: "Quality of the food?" },
{ idsurveyquestion: "24", question: "Speed Of delivery?" },
{ idsurveyquestion: "25", question: "The accuracy of the order?" },
{ idsurveyquestion: "26", question: "How is our service?" },
],
Question: [],
};
rate = (event, item) => {
const { id } = event.target;
var i;
console.log("You clicked: " + id);
var QType = "Rating";
var QuesID = id.substr(1, 2);
var OpId = id.charAt(0);
var option = id.charAt(0);
console.log(QuesID);
var Qobj = { QType: QType, QuesID: QuesID, OpId: OpId, option: option };
if (
this.state.Question.find((item) => item.QuesID === QuesID) !== undefined
) {
console.log("item exist");
} else {
console.log("Not exist item");
this.state.Question.push(Qobj);
}
// this.state.Question.push(Qobj);
console.log(this.state.Question);
for (i = 1; i <= 5; i++) {
if (parseInt(i + item.idsurveyquestion) <= parseInt(id)) {
document
.getElementById(parseInt(i + item.idsurveyquestion))
.setAttribute("src", fullStarSrc);
} else {
document
.getElementById(parseInt(i + item.idsurveyquestion))
.setAttribute("src", emptyStarSrc);
}
}
};
render() {
const { qtemp2 } = this.state;
return (
<div>
<div class="bg">
<div class="bg_img1"></div>
<div class="heading1">
<center>
<h2 class="head1">Please Rate Us</h2>
</center>
</div>
<center>
<div>
{qtemp2.map((item) => (
<>
<p key={item.idsurveyquestion}>{item.question}</p>
<div>
<img
onClick={(event) => this.rate(event, item)}
class="star"
id={"1" + item.idsurveyquestion}
src={emptyStarSrc}
/>
<img
onClick={(event) => this.rate(event, item)}
class="star"
id={"2" + item.idsurveyquestion}
src={emptyStarSrc}
/>
<img
onClick={(event) => this.rate(event, item)}
class="star"
id={"3" + item.idsurveyquestion}
src={emptyStarSrc}
/>
<img
onClick={(event) => this.rate(event, item)}
class="star"
id={"4" + item.idsurveyquestion}
src={emptyStarSrc}
/>
<img
onClick={(event) => this.rate(event, item)}
class="star"
id={"5" + item.idsurveyquestion}
src={emptyStarSrc}
/>
</div>
</>
))}
</div>
</center>
</div>
</div>
);
}
}
And also I need to unselect the all-stars when clicking on the same star. How can I do it with a simple variable like adding "let toRemove = false;" and Where Should I add "toRemove = true;" ?
This is what I tried-> https://codesandbox.io/s/romantic-torvalds-j0995?file=/src/Rating2.js
You need to do the following (replace your if else block with this):
const index = this.state.Question.findIndex((item) => item.OpId === OpId)
const newArray = [...this.state.Question]
if (index !== -1) {
console.log("item exist");
newArray.splice(index, 1, item)
} else {
console.log("item not exist");
newArray.push(Qobj);
}
this.setState({ Question: newArray })
first define some lists. one for checking Qtype and the other one for OpId, and etc:
let checkListQtype = [];
let checkListOpId = [];
then use this code:
let filteredData = YOURLIST.filter((item)=>{
if(checkListQtype.includes(item.QType) || checkListOpId.includes(item.OpId){
retrun false;
} else {
checkListQtype.push(item.QType);
checkListOpId.push(item.OpId);
return item;
}
});
This login can help you.
find index of the item
then remove it
update state.
->
let questions = this.state.Question;
const index = questions.findIndex(item=>item.OpId === OpId);
if(index > -1){
questions.splice(index, 1);
this.setState({Questions:arr})
}
It looks like the QuesID property of your objects is being used as a key which uniquely identifies the question. For this reason, it could make more sense to store your data not as an array, but as an object where the data is indexed by it's QuesID. This lets you very easily access, delete or modify the data for a known QuesID. For example:
// state structured like this
{
"22": {QType: "Rating", OpId: "4", option: "4"},
"23": {QType: "Rating", OpId: "3", option: "3"},
"24": {QType: "Rating", OpId: "2", option: "2"},
"25": {QType: "Rating", OpId: "1", option: "1"}
}
addData = (event, item) => {
var QType = "Rating";
var QuesID = "22";
var OpId = "1";
var option = "1";
var Qobj = { QType: QType, OpId: OpId, option: option };
this.setState({
Question: {
...this.state.Question,
[QuesID]: Qobj
}
});
}
You simply use:
console.log(array.length)
The code below works fine and display post record successfully.
No I want to get the comment count for each post based on post (pid).
I have implemented this function below
getCounterByPid(pid)
My issue: The function above display comment counting 3 for each post.
Normally, the post with pid 102 should show 2 comment count, then others 1 count each
here is the code
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script src="build/react.min.js"></script>
<script src="build/react-dom.min.js"></script>
<script src="build/browser.min.js"></script>
<script src="build/jquery.min.js"></script>
<div id="app"></div>
<script type="text/babel">
class Application extends React.Component {
//function Application() {
constructor(props) {
super(props);
this.state = {
post: {"results":
[
{"desc": "my first product", "pid": "101"},
{"desc": "my second product", "pid": "102"},
{"desc": "my 3rd product", "pid": "103"},
]},
comment: {"res":
[
{"comment": "hello 1", "pid": "101"},
{"comment": "hello 2", "pid": "102"},
{"comment": "hello 3", "pid": "103"},
{"comment": "hello 4", "pid": "102"},
]},
};
}
// get total comment count for each post
getCounterByPid(pid) {
const resIndex = this.state.comment.res.findIndex(el => pid === el.pid);
//const c1 = this.state.comment.res[resIndex].counting;
const comment_count = this.state.comment.res[resIndex].pid;
const comment_l = comment_count.length;
//alert(comment_count.length);
return comment_l;
};
render() {
return (
<div>
<div>
<ul>
{this.state.post.results.map((obj, i) => (
<li key={i}>
{obj.pid} - {obj.desc}<br />
<span> Comment count: ({this.getCounterByPid(obj.pid)})</span>
</li>
))}
</ul>
</div>
</div>
);
}
}
ReactDOM.render(<Application />, document.getElementById('app'));
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
</body>
</html>
With your current code:
const resIndex = this.state.comment.res.findIndex(el => pid === el.pid);
//const c1 = this.state.comment.res[resIndex].counting;
const comment_count = this.state.comment.res[resIndex].pid;
const comment_l = comment_count.length;
findIndex will find one of the comments in your array, it doesn't matter which it returns but it will return an index.
comment_count however will be the actual pid of that comment so 101, 102 or 103 depending on the value of findIndex
Finally, you are returning the length of that pid, which will always be 3.
Rather than do that, you can just filter the comments to find all the comments which are related to that specific pid. Then return the length of that filtered array.
getCounterByPid(pid) {
const comments = this.state.comment.res.filter(el => pid === el.pid);
return comments.length;
}
I have created a working example here: https://codesandbox.io/s/frosty-sunset-szn6t
I created a React app. It works as expected in IE, Opera, Chrome, FF. I have problems with rendering one component in Edge after state update. I can't help myself with React Devtools for Chrome, because it all works there as it should.
My component is a combination of two input fields. One is number input, which can be manipulated by user, the other displays the same number value, but formatted as currency string. When user clicks on the field, the field with formatted value hides and shows the non-formatted input field. When user moves away from editable input, the before hidden input shows again.
Because state gets changed every time onchange events is triggered, I expect, that the other input would also update on each and every onchange.
Is this because it is hidden?
Here is the code, I tried to simplify it as much as possible:
class MasterComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
Rows: [
{ Id: 1, Name: 'Row 1', Price: 11 },
{ Id: 2, Name: 'Row 2', Price: 21 },
{ Id: 3, Name: 'Row 3', Price: 13 }
]
}
this.changeObjectValue = this.changeObjectValue.bind(this);
}
render() {
return <MCVE changeObjectValue={this.changeObjectValue} rows={this.state.Rows}></MCVE>
}
changeObjectValue(rowId, propertyName, value) {
// define which list user wants to change
let list = this.state['Rows'];
let changedList = [];
// change value
list.forEach(element => {
if (element.Id == rowId) {
element[propertyName] = value;
}
changedList.push(element);
});
// dynamically set objct name frmo parameters
this.setState({ Rows: changedList });
}
}
class MCVE extends React.Component {
render() {
return <table>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{this.props.rows.map((r, index) =>
<tr key={r.Id}>
<td>
<input readOnly value={r.Id}></input>
</td>
<td><input name="Name" onChange={event => this.changeInput(event, r.Id)} value={r.Name}></input></td>
<td>
<input name="Price" className="edit" type="hidden" onBlur={event => toggleEditDisplay(event)} onChange={event => this.changeInput(event, r.Id)} value={r.Price}></input>
<input name="Price" className="display" readOnly onClick={event => toggleEditDisplay(event)} value={formatMoney(r.Price)}></input>
</td>
</tr>
)}
</tbody>
</table>
;
}
changeInput(event, rowId) {
let propertyName = event.target.name;
this.props.changeObjectValue(
rowId,
propertyName,
event.target.value);
}
}
function toggleEditDisplay(event) {
let el = event.target;
// if has class 'edit' else has class 'display'
if (el.className.split(/\s+/).filter(e => e == 'edit').length > 0) {
let elToToggle = el.parentElement.getElementsByClassName('display')[0];
el.type = "hidden";
elToToggle.type = "text";
}
else {
let elToToggle = el.parentElement.getElementsByClassName('edit')[0];
el.type = "hidden";
elToToggle.type = "number";
}
}
function formatMoney(amount, decimalCount = 2, decimal = ",", thousands = ".", currencySymbol = '€', ignoreCurrencySymbol = false) {
try {
decimalCount = Math.abs(decimalCount);
decimalCount = isNaN(decimalCount) ? 2 : decimalCount;
const negativeSign = amount < 0 ? "-" : "";
let i = parseInt(amount = Math.abs(Number(amount) || 0).toFixed(decimalCount)).toString();
let j = (i.length > 3) ? i.length % 3 : 0;
return negativeSign + (j ? i.substr(0, j) + thousands : '') + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + thousands) + (decimalCount ? decimal + Math.abs(amount - i).toFixed(decimalCount).slice(2) : "") + (ignoreCurrencySymbol ? "" : currencySymbol);
} catch (e) {
console.log(e)
}
};
ReactDOM.render(<MasterComponent />, document.getElementById('app'));
Minimum HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<div id="app"></div>
<script src="https://unpkg.com/react#16/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#16/umd/react-dom.development.js" crossorigin></script>
<script src="reactScript.js"></script>
</body>
</html>
After testing, it seems that the issue is related to the type="hidden", we could modify the code and use CSS display attribute to hide or display the input element. Please check the following steps:
Remove the 'type="hidden"' from the first input TexBox.
Add the following css style in the index.css file:
.edit{
display:none;
}
Modify the toggleEditDisplay function:
function toggleEditDisplay(event) {
let el = event.target;
// if has class 'edit' else has class 'display'
if (el.className.split(/\s+/).filter(e => e == 'edit').length > 0) {
let elToToggle = el.parentElement.getElementsByClassName('display')[0];
el.style.display ='none';
elToToggle.type = "text";
elToToggle.style.display ='block';
}
else {
let elToToggle = el.parentElement.children[0];
//el.type = "hidden";
el.style.display ='none';
elToToggle.type = "number";
elToToggle.style.display ='block';
}
el.focus();
}
The result in the Edge browser as below:
I have a requirement to determine a generic standard approach to read the JSON data ( should be able to read any JSON structure) and display in reactjs page.
I know that if we know JSON structure, we can traverse through it and display the data in the page accordingly. But here JSON structure
should be dynamically determined via code and we should not code specifically for each JSON structure.
For example, I have given Sample1.json and Sample2.json files below. My program should be able to parse Sample1.json if I use it and display
them on the page. If I use Sample2.json, still it should be able to parse them and display the data dynamically. We should not have
code specifically like archive_header.tracking_id or stock_ledger_sales_key.version_number...etc.
Can someone please let me know how to handle this scenario?
Sample1.json
{
"archive_header": {
"tracking_id": "914553536-FRM01-20163609140455-000000001",
"archived_timestamp": "2018-05-08T09:14:04.055-05:00"
},
"journal_record_key": {
"location_number": "389234",
"dept_number": "28822"
},
"journal_record_detail": {
"financial_from_item_number": "771",
"financial_to_item_number": "771"
}
}
Sample2.json
{
"stock_ledger_sales_key": {
"version_number": "12",
"account_month_number": "01",
"account_year_number": "2016"
},
"stock_ledger_sales_detail": {
"mature_increase_mtd_percentage": "1.2",
"mature_increase_stdt_percentage": "2.3",
"mature_increase_ytd_percentage": "2"
}
}
You can just iterate over the keys recursively:
function recursively_iterate(object, parent_name="") {
output = ""
for (key in Object.keys(object)) {
if (typeof object[key] == "object") {
output = output + recursively_iterate(object[key], key)
}
output = output + parent_name + "." + key + ": " + object[key] + "\n"
}
return output
}
To display the information as you said, we can do something like this:
const jsonDOM = json => {
return Object.keys(json).map(key => {
return Object.keys(json[key]).map(child => {
return (<div>
<p>{child}</p>
<p>{json[key][child]}</p>
</div>
);
});
});
};
return (<div>
<h2>JSON 1</h2>
{jsonDOM(json1)}
<h2>JSON 2</h2>
{jsonDOM(json2)}
</div>
);
Here is the live demo
Hope it helps :)
You can use JSON.stringify and <pre> tag to output any json you like.
const sample1 = {
archive_header: {
tracking_id: "914553536-FRM01-20163609140455-000000001",
archived_timestamp: "2018-05-08T09:14:04.055-05:00"
},
journal_record_key: {
location_number: "389234",
dept_number: "28822"
},
journal_record_detail: {
financial_from_item_number: "771",
financial_to_item_number: "771"
}
};
const sample2 = {
stock_ledger_sales_key: {
version_number: "12",
account_month_number: "01",
account_year_number: "2016"
},
stock_ledger_sales_detail: {
mature_increase_mtd_percentage: "1.2",
mature_increase_stdt_percentage: "2.3",
mature_increase_ytd_percentage: "2"
}
};
class App extends React.Component {
render() {
return (
<div>
<h3>sample1</h3>
<pre>
<code>{JSON.stringify(sample1, null, 2)}</code>
</pre>
<h3>sample2</h3>
<pre>
<code>{JSON.stringify(sample2, null, 2)}</code>
</pre>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I am facing a issue on extracting the Json data coming from an API.
Please help me to rectify my mistake.
JSON
[
{
"flagshipId":"18",
"BanquetValues":"<p>xzxzxczx<\/p>\n",
"FloorPlan":"[{\"id\":1,\"fileName\":\"megarugas-15243406450731525866511-1.jpg\",\"ifActive\":\"1\"},{\"id\":2,\"fileName\":\"megarugas-15243406467351525866513-2.jpg\",\"ifActive\":\"1\"},{\"id\":3,\"fileName\":\"megarugas-15244876214221526013635-3.jpg\",\"ifActive\":\"1\"}]",
"ChildDescription":"[{\"id\":1,\"childName\":\"Ceremony 1 # Megarugas\",\"description\":\"xczxcxvx\"}]",
"RestaurantId":"695"
}
]
I want to display filename from array of FloorPlan into my carousel.
JSX
render()
{
var banquetImg = this.props.IMG_BASE + this.props.RESTAURANT_BANNER_PATH
return (
<div className="photosSection">
{
this.props.banquetImageList.length != 0
?
<div className="body">
<div className="row">
<Carousel showArrows={true} >
{this.props.banquetImageList.map((row, i) =>
<div key={row.RestaurantAttachmentId} className={"row"}>
<img src={banquetImg + row.FileName} key={row.RestaurantAttachmentId}/>
<p className="get-final-price">Get Final Price</p>
</div>
)}
</Carousel>
</div>
</div>
:
""
}
</div>
);
}
I've tried an approach like #AI.G. and this is my code:
let json_data = [
{
"flagshipId":"18",
"BanquetValues":"<p>xzxzxczx<\/p>\n",
"FloorPlan":"[{\"id\":1,\"fileName\":\"megarugas-15243406450731525866511-1.jpg\",\"ifActive\":\"1\"},{\"id\":2,\"fileName\":\"megarugas-15243406467351525866513-2.jpg\",\"ifActive\":\"1\"},{\"id\":3,\"fileName\":\"megarugas-15244876214221526013635-3.jpg\",\"ifActive\":\"1\"}]",
"ChildDescription":"[{\"id\":1,\"childName\":\"Ceremony 1 # Megarugas\",\"description\":\"xczxcxvx\"}]",
"RestaurantId":"695"
}
];
floor_plan = JSON.parse(json_data[0]['FloorPlan']);
console.log(floor_plan);
And this is what I got from terminal (MacOS 10.13.4, NodeJS v8.11.1):
$ node test.js
[ { id: 1,
fileName: 'megarugas-15243406450731525866511-1.jpg',
ifActive: '1' },
{ id: 2,
fileName: 'megarugas-15243406467351525866513-2.jpg',
ifActive: '1' },
{ id: 3,
fileName: 'megarugas-15244876214221526013635-3.jpg',
ifActive: '1' } ]
You can get each element from floor_plan (which is currently an array).
Is this your target?