-1

I'm doing a map project in React and using the google-maps-react api. I am able to type characters in the search box, but it doesn't filter my list or markers. How can I make that work?


Here's the code for my App.js. I have the updateQuery which should update with whatever is typed in the search box. filterItems is supposed to filter all the locations. addRealMarkers is supposed to replace with the filtered markers:

var foursquare = require("react-foursquare")({
  clientID: "BTMAGTC2Y5G1IXAKA4VN4QN55R2DSN1105Y1XGHB0WZ5THHR",
  clientSecret: "4HOKQ0ON1V1XEHKSUSEABQMNRFZGCGPIKIUIE5JMUMWVRG5W",
  url: "https://api.foursquare.com/v2/venues/search?"
});

var params = {
  ll: "31.462170,-97.195732",
  query: "Hewitt"
};

class App extends Component {
  /* Basic state object that must be kept at the highest "parent" level per 
Doug Brown's training video */
  constructor(props) {
    super(props);
    this.state = {
      lat: 31.46217,
      lon: -97.195732,
      zoom: 13,
      items: [],
      filtered: null,
      open: false,
      selectedId: null,
      activeMarker: null
    };
  }
  realMarkers = [];
  componentDidMount() {
    foursquare.venues.getVenues(params).then(res => {
      this.setState({ items: res.response.venues });
    });
    fetch("react-foursquare")
      .then(response => response.json())
      .then(response => {
        const items = json.response.items;
        this.setState({
          items,
          filtered: this.filterItems(items, "")
        });
      })
      .catch(error => {
        alert("Foursquare data could not be retrieved");
      });
  }

  //Fetches the locations requested for this map.
  /*fetchPlaces(mapProps, map) {
    const { google } = mapProps;
    const service = new google.maps.places.PlacesService(map);
  }

  //fetch Foursquare API data and use Axios to catch errors, instructed by 
  Yahya Elharony.
  // Source: https://github.com/foursquare/react-foursquare
  getPlaces = () => {
    const endPoint = "https://api.foursquare.com/v2/venues/explore?";
    const params = {
      client_id: "BTMAGTC2Y5G1IXAKA4VN4QN55R2DSN1105Y1XGHB0WZ5THHR",
      client_secret: "4HOKQ0ON1V1XEHKSUSEABQMNRFZGCGPIKIUIE5JMUMWVRG5W",
      near: "Hewitt",
      query: "query",
      v: 20181117
    };
    // axios site: https://www.npmjs.com/package/axios
    axios
      .get(endPoint + new URLSearchParams(params))
      .then(response => {
        this.setState(
          {
            venues: response.data.response.groups[0].items
          },
          this.fetchPlaces()
        );
      })
      .catch(error => {
        console.log("ERROR! " + error);
      });
  };*/

  // Creating the replacement markers that goes with the list. Based on my 
  1:1 training from Doug Brown
  addRealMarker = marker => {
    let checkList = this.realMarkers.filter(
      m => m.marker.id === marker.marker.id
    );
    if (!checkList.length) this.realMarkers.push(marker);
  };

  updateQuery = query => {
    this.setState({
      selectedIndex: null,
      filtered: this.filterItems(this.state.items, query)
    });
  };

  filterItems = (items, query) => {
    return items.filter(item =>
      item.name.toLowerCase().includes(query.toLowerCase())
    );
  };

  clickListItem = id => {
    const marker = this.realMarkers.filter(
      marker => marker.marker.id === id
    )[0];
    this.setState({
      selectedId: id,
      activeMarker: marker
    });
  };

  /*Google Maps React Component courtesy of 
  https://www.npmjs.com/package/google-maps-react*/
  render() {
    const style = {
      width: "100%",
      height: "100%"
    };

    return (
      <div className="App">
        <HewittMap
          lat={this.state.lat}
          lng={this.state.lng}
          zoom={this.state.zoom}
          style={style}
          items={this.state.items}
          addRealMarker={this.addRealMarker}
          activeMarker={this.state.activeMarker}
          clickListItem={this.clickListItem}
        />
        <Sidebar
          items={this.state.items}
          clickListItem={this.clickListItem}
          filterItems={this.updateQuery}
        />
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

export default App;

And here's the Sidebar Code. Added another updateQuery function that's supposed to call the props then you'll see some more code in the InputBase component:

class Sidebar extends Component {
  state = {
    mobileOpen: false,
    query: ""
  };

  handleDrawerOpen = () => {
    this.setState({ open: true });
  };

  handleDrawerClose = () => {
    this.setState({ open: false });
  };

  updateQuery = newQuery => {
    // Save the new query string in state and pass the string up the call 
    tree
    this.setState({ query: newQuery });
    this.props.filterItems(newQuery);
  };

  render() {
    const { classes, theme } = this.props;
    const { open } = this.state;
    const items = this.props.items;

    return (
      <div className={classes.root}>
        <CssBaseline />
        <AppBar
          position="fixed"
          className={classNames(classes.appBar, {
            [classes.appBarShift]: open
          })}
    >
      <Toolbar disableGutters={!open}>
        <IconButton
          color="inherit"
          aria-label="Open drawer"
          onClick={this.handleDrawerOpen}
          className={classNames(classes.menuButton, open && classes.hide)}
        >
          <MenuIcon />
        </IconButton>
        <Typography variant="h6" color="inherit" noWrap>
          City of Hewitt
        </Typography>
        <div className={classes.search}>
          <div className={classes.searchIcon}>
            <SearchIcon places={this.state.places} />
          </div>
          <InputBase
            classes={{
              root: classes.inputRoot,
              input: classes.inputInput
            }}
            placeholder="Search…"
            name="filter"
            type="text"
            value={this.state.query}
            onChange={e => {
              this.updateQuery(e.target.value);
            }}
          />
        </div>
      </Toolbar>
    </AppBar>
    <Drawer
      className={classes.drawer}
      variant="persistent"
      anchor="left"
      open={open}
      classes={{
        paper: classes.drawerPaper
      }}
    >
      <div className={classes.drawerHeader}>
        <IconButton onClick={this.handleDrawerClose}>
          {theme.direction === "ltr" ? (
            <ChevronLeftIcon />
          ) : (
            <ChevronRightIcon />
          )}
        </IconButton>
      </div>
      <Divider />
      <List>
        {this.props.items &&
          this.props.items.map((item, index) => {
            return (
              <ListItem key={item.id}>
                <button
                  key={index}
                  onClick={e => this.props.clickListItem(item.id)}
                >
                  <ListItemText primary={item.name}> </ListItemText>
                </button>
              </ListItem>
            );
          })}
      </List>

      <Divider />
    </Drawer>
    <main
      className={classNames(classes.content, {
        [classes.contentShift]: open
      })}
    >
      <div className={classes.drawerHeader} />
    </main>
  </div>
);


 }
}

Sidebar.propTypes = {
  classes: PropTypes.object.isRequired,
  // Injected by the documentation to work in an iframe.
  // You won't need it on your project.
  container: PropTypes.object,
  theme: PropTypes.object.isRequired
};

export default withStyles(styles, { withTheme: true })(Sidebar); 

You can click in my CodeSandbox to see for yourself.

Jerome
  • 9
  • 4

1 Answers1

0

You are filtering your data and assigning it to filtered but you use items to drive your map, not filtered. It would need more refactoring, but what if you did this?

  updateQuery = query => {
    this.setState({
      selectedIndex: null,
      //filtered: this.filterItems(this.state.items, query) // -
      items: this.filterItems(this.state.items, query) // +
    });
  };

You might want an indicator, say isFiltered, that is true when the search bar has a value in it. If true, use the filtered data, else, use the original items

go_diego
  • 393
  • 2
  • 7