user9347049
user9347049

Reputation: 2045

Building search filter using ReactJs, and Node.js

App is running on Node.js and React. In database (mongodb used) I have collection Rooms that contains details about particular room.

I am trying to search that collection based on for example number of guests and if number of guests in search input is 2 I would like to display all the rooms that can have two guests.

Also my question is is it possible to do search input for every field in collection rooms? For example number of guests, room type, price and so on...

Also is it better to do it with search input or dropdown search?

SERVER PART

UserModel.js

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

// Define our model
const roomSchema = new Schema({
    title: { type: String },
    description: { type: String },
    price: { type: Number },
    room_type: { type: String },
    nb_guests: { type: Number },
    imageData: {type: String}
});

// Create the model class
const ModelClass = mongoose.model('room', roomSchema);

// Export the model
module.exports = ModelClass;

CLIENT PART

LandingPage.js

const Room = props => (
    <div className = "col-md-4" >
        <div className="card mb-4 shadow-sm">
            <img src={room9} class="card-img-top" 
             alt="..." width="100%" height="225" />
            <div className="card-body">
                <h5 class="card-title">{props.room.title}</h5>
                <p className="card-text">{props.room.description}</p>
                <div className="d-flex justify-content-between align- 
                       items-center">
                    <div className="btn-group">
                    <Link  className="btn btn-sm 
                    btn-outline-secondary" to={"/view/"+props.room._id}>View</Link>
                    </div>
                </div>
            </div>
        </div>
    </div >
)

function searchingFor(term){
    return function(x){
        return x.props.room.nb_guests.toLowerCase().includes(term.toLowerCase()) || !term;
    }
}
    export default class LandingPage extends React.Component {
        constructor(props) {
            super(props);
            this.state = { 
                rooms: [],
                term:''
            }
            this.onSearchHandler = this.onSearchHandler.bind(this);
        }

        componentDidMount() {
            axios.get('http://localhost:3090/admin/')
                .then(response => {
                    this.setState({
                        rooms: response.data
                    })
                        .catch(function (error) {
                            console.log(error);
                        })
                })
        }

        roomList() {
            return this.state.rooms.filter(searchingFor(this.state.term)).map(function (currentRoom, i) {
                return <Room room={currentRoom} key={i} />
            });
        }

        onSearchHandler(e){
            this.setState({
                term:e.target.value
            })
        }
        render() {
            return (
                <div>
                    <LPheader />
                    <Carousel />
                    <div>
                        <div className="album py-5 bg-light">
                            <div className="container">
                                <div className="row">
                                    <form>
                                        <input 
                                        type="text"
                                        onChange={this.onSearchHandler}
                                        value={term}
                                        />
                                    </form>
                                    {this.roomList()}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            )
        }
    }

This is the code I started with and I am getting this error

Uncaught ReferenceError: term is not defined

To be completely honest I am not even sure if this is right way to do it, any advice would be highly appreciated.

Update

roomList = () => {
        const { rooms, term } = this.state;

        if (!term) {
          return rooms.map(function(currentRoom, i) {
            return <Room room={currentRoom} key={i} />;
          });
        } else if {
          return rooms
            .filter(room => {
              return room.nb_guests == term;
            })
            .map(matchingRoom => {
              return <Room room={matchingRoom} />;
            });
            else if{
                .filter(room => {
                    return room.price == term;
                  })
                  .map(matchingRoom => {
                    return <Room room={matchingRoom} />;
                  });
                  else if{
                    .filter(room => {
                        return room.room_type == term;
                      })
                      .map(matchingRoom => {
                        return <Room room={matchingRoom} />;
                      });
            }
        }
      };

      onSearchHandlerPrice = e => {
        this.setState({
          term: (e.target.value)
        });
      };

      onSearchHandlerGuests = e => {
        this.setState({
          term: (e.target.value)
        });
      };


<div className="container">
<div className="row">
  <form>
    <input type="text" onChange={this.onSearchHandlerGuests} value={this.state.term} />
  </form>

  <form>
    <input type="text" onChange={this.onSearchHandlerPrice} value={this.state.term} />
  </form>
  {this.roomList()}
</div>
</div>

Upvotes: 1

Views: 4124

Answers (1)

Cat_Enthusiast
Cat_Enthusiast

Reputation: 15688

You're very close to getting this done. I think the searchingFor() function is over-complicating your logic. See the following sandbox on how you can filter the rooms by number of guests: https://codesandbox.io/s/thirsty-dan-vjt7o

Notes:

  • I commented out the axios request and just plugged in some sample data. It should still work if you swap it back with your own code.

You could simplify your code by updating the term state-value as the user types, causing a re-render and inside the newly executed roomList(), filter and return the appropriate rooms that match term.

  roomList = () => {
    const { rooms, term } = this.state;

    if (!term) {
      return rooms.map(function(currentRoom, i) {
        return <Room room={currentRoom} key={i} />;
      });
    } else {
      return rooms
        .filter(room => {
          return room.nb_guests == term;
        })
        .map(matchingRoom => {
          return <Room room={matchingRoom} />;
        });
    }
  };

  onSearchHandler = e => {
    this.setState({
      term: e.target.value
    });
  };

Upvotes: 2

Related Questions