sortinousn
sortinousn

Reputation: 647

Render HTML from a json string in react

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.

Here is the JSON result rendered to HTML I'm getting when running the below code.

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

Answers (4)

sashok1337
sashok1337

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

Christian Hain
Christian Hain

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

Mμ.
Mμ.

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

Pedro Castilho
Pedro Castilho

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

Related Questions