0

I'm very new to React and Javascript. I am creating a simple search feature using React and Nodejs where you are able to search for tutors. I am trying to print the output of the search using react. My express server sends a response in the form of a string. It looks like the following:

'[{"tutorID":1,"email":"johndoe@sfsu.edu","firstName":"John","lastName":"Doe","courseTeaching":"csc510","imageReference":" http://localhost:3001/john.png "}]'

I want to be able to display every key and its value in the form of a table. Can someone please help me achieve this?

The code for my search in react is given below:

import React, {useState} from 'react';
import "./SearchForm.css"; 
import SearchIcon from '@mui/icons-material/Search';
import DisplayResults from './DisplayResults.js'; 


class SearchForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            selectedCategory: '',
            textSearch: '',
            searchResponse: []
        };

        this.handleInputChange = this.handleInputChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    handleInputChange(event) {
        const target = event.target;
        const value = target.value;
        const name = target.name;

        this.setState( {
            ...this.state,
            [target.name]: value
        });
    }

    handleSubmit(event) {
        event.preventDefault(); 
        let cat = this.state.selectedCategory;
        let searchquery = this.state.textSearch; 

        fetch(`http://localhost:3000/onSubmit?param1=${cat}&param2=${searchquery}`, {
            method: "GET",
            headers: {
                'Content-type': 'application/json'
            }
        })
        .then((result, err) => result.json())
        .then(contents => {
            this.setState({ searchResponse: contents}, function() {
                console.log(this.state.searchResponse);
            })
        });
    }

    render() {
        return (
            <>
            <p className="greeting">Hi, what would you like to search?</p>
            <form onSubmit={this.handleSubmit}>
                
            <div className="wrapper">

               <select class="theme" 
                name="selectedCategory"
                type="category"
                value={this.state.selectedCategory} 
                onChange={this.handleInputChange}>
                    <option value="all">Search All</option>
                    <option value="tutors">Tutors</option>
                    <option value="Courses">Courses</option>
                </select>
    
                <input className="searchBar" 
                name="textSearch" 
                type="text" 
                placeholder="search"
                value={this.state.textSearch}
                onChange={this.handleInputChange}>
                </input> 
                    

                <div className="searchIcon">       
                    <SearchIcon onClick={this.handleSubmit}/>
                </div>
            </div>

            </form>

            <DisplayResults searchResults={this.state.searchResponse}/>
        </>
        )
    }
}

export default SearchForm;

The code for the DisplayResults is below:

import React from 'react'; 

class DisplayResults extends React.Component {

    render() {
        return ( 
                <div>{this.props.searchResults}</div>
        ); 
    }
}

export default DisplayResults; 

Any help would be much appreciated, thank you.

Leks
  • 49
  • 1
  • 1
  • 6
  • There is no such thing as a "JSON Object". JSON is a string representation of a javascript object. To convert JSON into an object, use `theObject = JSON.parse(theString)`. To convert an object into a JSON string, use `theString = JSON.stringify(theObject)`. – Daniel Beck Nov 01 '21 at 15:17
  • @DanielBeck Thank you for your response. I have changed the code so that the second .then accepts a `contents`. I console.logged the `contents` and it's returning an object. However, when I try to assign it to `searchResponse` in the `SearchForm` file, React is not letting me do that. It gives me an error saying "Objects are Not Valid As React Child". – Leks Nov 01 '21 at 15:44
  • ...yes, that's because raw javascript objects can't be dropped into the DOM. Your displayResults component would need to pluck out whichever primitives inside that object you want to display: `
    {searchResults[0].email}
    ` or etc
    – Daniel Beck Nov 01 '21 at 16:41

3 Answers3

1

What you could do if the response was JSON is to use the .map property.

In this example I omitted the ' ' (at the start and end) from your set of data, to make it valid json.

let object = [{
"tutorID": 1,
"email": "johndoe@sfsu.edu",
"firstName": "John",
"lastName": "Doe",
"courseTeaching": "csc510",
"imageReference": " http://localhost:3001/john.png "
}]

So you could probably do something like this to access the values.

const listItems = object.map((object) => console.log(object.tutorID))

So with .map you can return a component with the data, you just mapped over.

So after that it's up to you what you want to do with the data. So you can create a table, or use one from Bootstrap or something similar and just map the values out.

<Table>
<p>{object.tutorID}</p>
<p>{object.email}</p>
<p>{object.firstName}</p>
<p>{object.lastName}</p>
...
</Table>

If I said anything wrong, or if I didn't quite give you the answer you wanted then let me know.

msvan
  • 39
  • 3
  • How would I be able to convert the string to a valid JSON object? – Leks Nov 01 '21 at 07:19
  • @Leks Instead of `result.text()` you should do `result.json()` – ShamPooSham Nov 01 '21 at 07:20
  • @ShamPooSham When I changed it from `result.text()` to `result.json()` i get the following error: Error: Objects are not valid as a React child (found: object with keys {tutorID, email, firstName, lastName, courseTeaching, imageReference}). If you meant to render a collection of children, use an array instead. I'm not really sure why this is happening. – Leks Nov 01 '21 at 07:30
  • @Leks Make sure the objects are inside an array.There is no .map on the Object object. However, if it is an Array of Objects. You can use .map. However, if you want to map over an object you can use object.keys, like this: https://stackoverflow.com/questions/14810506/map-function-for-objects-instead-of-arrays – msvan Nov 01 '21 at 07:33
  • @Leks Sounds like you get an object, not an array. Can you create an edit to your question with the code you have now? – ShamPooSham Nov 01 '21 at 09:37
  • @ShamPooSham Yes, I have done that just now. When I run this code, I keep getting the error as mentioned in my last comment. – Leks Nov 01 '21 at 15:10
  • @Leks Well, now `this.props.searchResults` is an array/object, so you have to decide what you want to do with each property. What html you expect react to create from the code you have? – ShamPooSham Nov 01 '21 at 15:36
  • @ShamPooSham I have changed the code so that the second .then accepts a contents. I console.logged the contents and it's returning an object. However, when I try to assign it to searchResponse in the SearchForm file, React is not letting me do that. It gives me an error saying "Objects are Not Valid As React Child". I am not sure how to deal with this. – Leks Nov 01 '21 at 15:45
  • @Leks I think the issue is in the DisplayResults component. You have to be more specific there, for example create a html table there where you assign the values of searchResults to different cells. You can't just say you want to output the object there, react doesn't know what to do with that. – ShamPooSham Nov 01 '21 at 17:09
0
  1. [Inside SearchForm] After receiving the response, let's turn your string data into something usable. Parse your string to an array of objects using JSON.parse(YOUR_DATA). You can then set your searchResponse state to this array.
  2. [Inside DisplayResults] You have an array of objects, so iterate over them using YOUR_DATA.map(). Your map function should return some JSX. In this case you are making a table. This is a function which creates the table. We use Object.values(YOUR_OBJECT) to get all the values (e.g. John, Doe ...) and Object.keys(YOUR_OBJECT) to get the keys (e.g. firstName, lastName). You can use something like this in your render() function to create the table.
    const createTable = () => {
        const tableHeaders = (  // Get the table headers from the first person, OR enter them manually.
            <tr>
                {Object.keys(this.props.searchResults[0]).map(headerTitle => <th>{headerTitle}</th>)}
            </tr>
        );
        // All the content rows of the table.
        const tableRows = this.props.searchResults.map((tutor) => (
            <tr> {/* this is one row of the table. It is filled with td's which each have a piece of information about the tutor. */}
                {Object.values(tutor).map(value => ( // for each of the properties of the tutor, we create a table cell.
                    <td>{value}</td>    
                ))}
            </tr>
        ));
        // The actual table, with table headers and table rows.
        return (
            <table>
                {tableHeaders}
                {tableRows}
            </table>
        );
    }
Hayato
  • 64
  • 3
0

const listItems = object.map((object) => console.log(object.tutorID)) top of the line work for me.

brids
  • 25
  • 2
  • 11
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 02 '22 at 02:03