Reputation: 647
I'm trying to render an HTML object from a JSON string that I'm receiving from an API. I'm able to get the string to render to HTML successfully but it shows the entire JSON string. I'm only looking to get specific values (Phone, Name, Id.) What would be the best way for me to extract specific values from my JSON array and format it in HTML? I'm referring to records by state but I'm unable to get any sub-value of record in the render process.
class menuScreen extends React.Component {
constructor(props) {
super(props)
const data = store.getState();
this.state = {
username: '',
messages: data.messages
}
}
handleSearch(e) {
this.setState({username: e.target.value})
}
handleChange(evt) {
this.setState({
username: evt.target.value.substr(0, 100)
});
}
onLinkClicked() {
var conn = new jsforce.Connection({serverUrl: 'https://cs63.salesforce.com', accessToken: sessionStorage.getItem('token')})
var parent = this.state.username
//console.log(this.state.username)
conn.sobject("Contact").find({
LastName: {
$like: parent
}
}, 'Id, Name, Phone'
).sort('-CreatedDate Name').
limit(5).skip(10).execute(function(err, records) {
if (err) {
return console.error(err);
}
for (var i = 0; i < records.length; i++) {
var record = (records[i]);
console.log("Name: " + record.Name); //these are the records I'm trying to render
console.log("Phone: " + record.Phone);
} this.setState({records : records})
}.bind(this));
}
render() {
return (
<div className='menubox' id='menubox'>
<div className='searchbar-container'>
<form onSubmit={e => e.preventDefault()}>
<input type='text' size='25' placeholder='Contact Last Name' onChange={this.handleChange.bind(this)} value={this.state.username}/>
<button type='submit' onClick={this.onLinkClicked.bind(this)}>
Search
</button>
</form>
</div>
<div>
<div dangerouslySetInnerHTML={ { __html: JSON.stringify(this.state.records) } }></div> //how can I show specific values, isntead of the entire string?
</div>
</div>
)
}
}
export default menuScreen;
Upvotes: 10
Views: 22950
Reputation: 1019
Since WebComponents are supported by all modern browsers, I decided to publish an additional answer on how this can be done almost natively.
It will be much faster because you don't need to modify the HTML string (or go through the nodes) in any way. And it will require only additional 10-15 lines of code and 0 dependencies. And you even can pass any parameters to your components. And use nested components as well.
The idea is pretty simple - we need to define WebComponent inside react component class:
class MenuComponent extends HTMLElement {
constructor() {
super();
}
connectedCallback() {
let decoded = JSON.parse(decodeURIComponent(this.dataset.json));
ReactDOM.render(<MenuWrapperComponent data={decoded} />, this);
}
disconnectedCallback() {
ReactDOM.unmountComponentAtNode(this);
}
}
Then define it with:
customElements.define('menu-component', MenuComponent);
And then you can insert your trusted HTML code like this:
class App extends Component {
render() {
// we need to render existing react component from the string
const myTrustedHtmlString = '<p>Hello world!</p><menu-component data-json="%some_encoded_data%"></menu-component><p>Goodbye!</p>';
return <div dangerouslySetInnerHTML={{ __html: myTrustedHtmlString }}></div>;
}
}
You can find working example here (with passing parameters to a component, as well as using a nested component).
Upvotes: 0
Reputation: 639
You can run a map function and output the JSX for each item.
class menuScreen extends React.Component {
constructor(props) {
super(props)
const data = store.getState();
this.state = {
username: '',
messages: data.messages,
records: [],
};
}
render() {
return (
<div>
{this.state.records.map(record => (
<div>{record.attributes.name} {record.attributes.phone} {record.whatever}</div>
)}
</div>
);
}
}
Keep in mind, if you want a more complex HTML structure within map function, you'll have to wrap it in a single DOM node.
The full file would look like:
render() {
return (
<div className='menubox' id='menubox'>
<div className='searchbar-container'>
<form onSubmit={e => e.preventDefault()}>
<input type='text' size='25' placeholder='Contact Last Name' onChange={this.handleChange.bind(this)} value={this.state.username}/>
<button type='submit' onClick={this.onLinkClicked.bind(this)}>
Search
</button>
</form>
</div>
<div>
{this.state.records.map(record => (
<div>{record.attributes.name} {record.attributes.phone}</div>
)}
</div>
</div>
);
}
Upvotes: 1
Reputation: 8552
You could create a separate render method that will render your records like so:
renderRecords(records) {
return records.map(r => <div> r.Name, r.Phone</div>);
}
And then call the method inside your render method, instead of using dangerouslySetInnerHTML, like so
render() {
return (
<div className='menubox' id='menubox'>
<div className='searchbar-container'>
<form onSubmit={e => e.preventDefault()}>
<input type='text' size='25' placeholder='Contact Last Name' onChange={this.handleChange.bind(this)} value={this.state.username}/>
<button type='submit' onClick={this.onLinkClicked.bind(this)}>
Search
</button>
</form>
</div>
<div>
<div>{ this.renderRecords() }</div>
</div>
</div>
)
}
Upvotes: 1
Reputation: 10532
JSON.parse
your string into a JavaScript object. You can then do whatever processing you want on that object, such as removing fields you don't want, and then you can JSON.stringify
it back into a JSON string which you can render.
Something like:
class BlahBlah extends React.Component {
constructor() {
//...some code...
this.processJson = this.processJson.bind(this)
}
//...a lot of code...
processJson(json) {
var object = JSON.parse(json)
var output = {}
//for every property you want
output[property] = object[property]
return JSON.stringify(output)
}
//...a lot more code...
render() {
return(
//...even more code...
<div dangerouslySetInnerHTML={ { __html: this.processJson(this.state.records) } }></div>
//...and yet more code.
)
}
}
Upvotes: 4