1

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>
5
  • In your render method, on your form tag change ` value={term}` to ` value={this.state.term}` Commented Jun 27, 2019 at 7:17
  • I changed it thanks! I don't know how I missed it. But now it can't recognize room I think it's issue with my function searchingFor() because it is outside of class component or what do you think? Commented Jun 27, 2019 at 7:26
  • Are you just using React and Node? Any redux? Commented Jun 27, 2019 at 7:53
  • Yes. Not in this component bu I am using it Commented Jun 27, 2019 at 7:54
  • Gotcha, was just wondering because it seems like you're front-loading all the data inside your Landing page component. :) Commented Jun 27, 2019 at 7:56

1 Answer 1

2

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
    });
  };
Sign up to request clarification or add additional context in comments.

9 Comments

Thank you for your code! It's working but when I enter in search bar number 2 it displays correctly rooms with two guests but when I try delete that number and put other in search input I can't and error that I am getting is ' Warning: Each child in a list should have a unique "key" prop.' and Received NaN for the value attribute. If this is expected, cast the value to a string. Do you maybe know why?
@user9347049 ahh yes, thats happening because of the parseFloat(). In onSearchHandler(), just get rid of the parseFloat so it will look like term: e.target.value and then in the .filter() use double equals ==, so return room.nb_guests == term Also see updated sandbox: codesandbox.io/s/thirsty-dan-vjt7o
Thank you it really did the trick! May I have one more question as I am trying to solve it by myself but also kinda stuck :/ for example if I would like to do search also for other fields in room collection how would I change roomList() function. For example one search input for number of guests other for price then for room type and so on.. I have put some code in my question update like idea of how to do it can you please check
Thank you a lot for your detailed answers and effort :) I really appreciate it :)
@user9347049 you're very welcome! I hope you found this helpful
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.