Filter react-table and react-leaflet marker at the same time using textfield (Show filter data in table and marker in the map)

最后都变了- 提交于 2019-12-12 17:10:50

问题


I am new to react-leaflet. Need little help to fix my issue. Follow up with Previous post

I have textfield which filter data. I was able to filter data in the table but not able to filter the data in the map. For example: if I search for name: 'VaiBike' it should show in table and marker in the map. Note: only show the data which is filter in map as well as in the table. so does for the other data.

How can I change my code so that I can show marker and data in table at the same time.

Running code

import React, { Component } from 'react'
    import { Map, TileLayer, Marker, Popup } from 'react-leaflet'
    import './style.css'
    import 'leaflet/dist/leaflet.css'
    import L from 'leaflet'
    import icon from 'leaflet/dist/images/marker-icon.png'
    import iconShadow from 'leaflet/dist/images/marker-shadow.png'
    import TextField from '@material-ui/core/TextField'
    // Import React Table
    import ReactTable from 'react-table'
    import 'react-table/react-table.css'
    import matchSorter from 'match-sorter'

    var myIcon = L.icon({
      iconUrl:
        'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAApCAYAAADAk4LOAAAFgUlEQVR4Aa1XA5BjWRTN2oW17d3YaZtr2962HUzbDNpjszW24mRt28p47v7zq/bXZtrp/lWnXr337j3nPCe85NcypgSFdugCpW5YoDAMRaIMqRi6aKq5E3YqDQO3qAwjVWrD8Ncq/RBpykd8oZUb/kaJutow8r1aP9II0WmLKLIsJyv1w/kqw9Ch2MYdB++12Onxee/QMwvf4/Dk/Lfp/i4nxTXtOoQ4pW5Aj7wpici1A9erdAN2OH64x8OSP9j3Ft3b7aWkTg/Fm91siTra0f9on5sQr9INejH6CUUUpavjFNq1B+Oadhxmnfa8RfEmN8VNAsQhPqF55xHkMzz3jSmChWU6f7/XZKNH+9+hBLOHYozuKQPxyMPUKkrX/K0uWnfFaJGS1QPRtZsOPtr3NsW0uyh6NNCOkU3Yz+bXbT3I8G3xE5EXLXtCXbbqwCO9zPQYPRTZ5vIDXD7U+w7rFDEoUUf7ibHIR4y6bLVPXrz8JVZEql13trxwue/uDivd3fkWRbS6/IA2bID4uk0UpF1N8qLlbBlXs4Ee7HLTfV1j54APvODnSfOWBqtKVvjgLKzF5YdEk5ewRkGlK0i33Eofffc7HT56jD7/6U+qH3Cx7SBLNntH5YIPvODnyfIXZYRVDPqgHtLs5ABHD3YzLuespb7t79FY34DjMwrVrcTuwlT55YMPvOBnRrJ4VXTdNnYug5ucHLBjEpt30701A3Ts+HEa73u6dT3FNWwflY86eMHPk+Yu+i6pzUpRrW7SNDg5JHR4KapmM5Wv2E8Tfcb1HoqqHMHU+uWDD7zg54mz5/2BSnizi9T1Dg4QQXLToGNCkb6tb1NU+QAlGr1++eADrzhn/u8Q2YZhQVlZ5+CAOtqfbhmaUCS1ezNFVm2imDbPmPng5wmz+gwh+oHDce0eUtQ6OGDIyR0uUhUsoO3vfDmmgOezH0mZN59x7MBi++WDL1g/eEiU3avlidO671bkLfwbw5XV2P8Pzo0ydy4t2/0eu33xYSOMOD8hTf4CrBtGMSoXfPLchX+J0ruSePw3LZeK0juPJbYzrhkH0io7B3k164hiGvawhOKMLkrQLyVpZg8rHFW7E2uHOL888IBPlNZ1FPzstSJM694fWr6RwpvcJK60+0HCILTBzZLFNdtAzJaohze60T8qBzyh5ZuOg5e7uwQppofEmf2++DYvmySqGBuKaicF1blQjhuHdvCIMvp8whTTfZzI7RldpwtSzL+F1+wkdZ2TBOW2gIF88PBTzD/gpeREAMEbxnJcaJHNHrpzji0gQCS6hdkEeYt9DF/2qPcEC8RM28Hwmr3sdNyht00byAut2k3gufWNtgtOEOFGUwcXWNDbdNbpgBGxEvKkOQsxivJx33iow0Vw5S6SVTrpVq11ysA2Rp7gTfPfktc6zhtXBBC+adRLshf6sG2RfHPZ5EAc4sVZ83yCN00Fk/4kggu40ZTvIEm5g24qtU4KjBrx/BTTH8ifVASAG7gKrnWxJDcU7x8X6Ecczhm3o6YicvsLXWfh3Ch1W0k8x0nXF+0fFxgt4phz8QvypiwCCFKMqXCnqXExjq10beH+UUA7+nG6mdG/Pu0f3LgFcGrl2s0kNNjpmoJ9o4B29CMO8dMT4Q5ox8uitF6fqsrJOr8qnwNbRzv6hSnG5wP+64C7h9lp30hKNtKdWjtdkbuPA19nJ7Tz3zR/ibgARbhb4AlhavcBebmTHcFl2fvYEnW0ox9xMxKBS8btJ+KiEbq9zA4RthQXDhPa0T9TEe69gWupwc6uBUphquXgf+/FrIjweHQS4/pduMe5ERUMHUd9xv8ZR98CxkS4F2n3EUrUZ10EYNw7BWm9x1GiPssi3GgiGRDKWRYZfXlON+dfNbM+GgIwYdwAAAAASUVORK5CYII=',
      iconSize: [25, 41],
      iconAnchor: [12.5, 41],
      popupAnchor: [0, -41],
    })
    let DefaultIcon = L.icon({
      iconUrl: icon,
      shadowUrl: iconShadow,
    })

    L.Marker.prototype.options.icon = DefaultIcon

    export default class App extends Component {
      constructor(props) {
        super(props)
        this.state = {
        location: {
          lat: 51.505,
          lng: -0.09,
          filterAll: '',
        },
        bikeData: [],
        haveUsersLocation: false,
        zoom: 3,
      }
      }
      //lifecycle method to get the bike information
      componentDidMount() {
        fetch('https://api.citybik.es/v2/networks')
          .catch(error => {
            console.log(error)
          })
          .then(res => res.json())
          .then(response => {
            const networkData = response.networks
            this.setState({
              bikeData: networkData,
            })
          })
      }
      filterAll = e => {
        const { value } = e.target
        const filterAll = value
        const filtered = [{ id: 'all', value: filterAll }]
        const filterdMap =[{id:'bikeData', value: filterAll}]
        this.setState({ filterAll, filtered ,filterdMap})
      }

      render() {
        const position = [this.state.location.lat, this.state.location.lng]
        const bikeData = this.state.bikeData
        return (
          <div
            style={{
              height: '100vh',
            }}
            id="map"
          >
            <div align="right">
              <form noValidate autoComplete="off">
                <TextField
                  id="row"
                  label="Search Bike"
                  margin="normal"
                  value={this.state.filterAll}
                  onChange={this.filterAll}
                />
              </form>
            </div>
            <Map className="map" center={position} zoom={this.state.zoom}>
              <TileLayer
                attribution="&amp;copy <a href=&quot;http://osm.org/copyright&quot;>OpenStreetMap</a> contributors"
                url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
              />
              {bikeData &&
                bikeData.map(data => {
                  console.log(data)
                  return (
                    <Marker
                      icon={myIcon}
                      key={data.id}
                      position={[data.location.latitude, data.location.longitude]}
                    >
                      <Popup>
                        Name: {data.name} <br />
                        Station Details:{' '}
                        {[data.location.city, data.location.country]}
                      </Popup>
                    </Marker>
                  )
                })}
            </Map>
            <div>
              <ReactTable
                filtered={this.state.filtered}
                defaultFilterMethod={(filter, row) =>
                  String(row[filter.id]) === filter.value
                }
                data={bikeData}
                columns={[
                  {
                    columns: [
                      {
                        Header: ' Name',
                        accessor: 'name',
                        filterAll: true,
                      },

                      {
                        Header: '',
                        id: 'all',
                        width: 0,
                        resizable: false,
                        sortable: false,
                        Filter: () => {},
                        getProps: () => {
                          return {}
                        },
                        filterMethod: (filter, rows) => {
                          const result = matchSorter(rows, filter.value, {
                            keys: ['name'],
                            threshold: matchSorter.rankings.WORD_STARTS_WITH,
                          })

                          return result
                        },
                        filterAll: true,
                      },
                    ],
                  },
                ]}
                defaultPageSize={10}
              />
              <br />
            </div>
          </div>
        )
      }
    }

Help with running code highly appreciated. Thanks in advance.


回答1:


If I understand your question correctly, you'll need to make a few adjustments to your code. First, add state to track the "filtered bike data" (ie the data that is visible to users in the UI). You can do so by adding something like this in your constructor:

constructor(props) {
    super(props)
    this.state = {
    location: {
      lat: 51.505,
      lng: -0.09,
      filterAll: '',
    },
    bikeData: [],
    filteredBikeData : [], // Add this
    haveUsersLocation: false,
    zoom: 3,
  }
  }

Now, in you filterAll all text field change handler, you'll want to update the filteredBikeData state based on the current field value. You can do so with something as follows:

filterAll = e => {
    const { value } = e.target

    // Get a filtered list of bikes based on original list
    const filteredBikes = this.state.bikeData.filter(bike => {

        // Filter bikes by name. Use toLowerCase to avoid case sensitivity issues
        return bike.name.toLowerCase().indexOf(value.toLowerCase()) !== -1
    })

    const filterAll = value
    const filtered = [{ id: 'all', value: filterAll }]
    const filterdMap =[{id:'bikeData', value: filterAll}]

    // Update state to include filtered bikes array
    this.setState({ filterAll, filtered ,filterdMap, filteredBikes})
}

Finally, you'll want to render markers based on the filtered array of bikes - update your render method like so:

{ /* use filteredBikes instead of bikes */
{ this.state.filteredBikes && this.state.filteredBikes.map(data => {
    console.log(data)
    return (
    <Marker
        icon={myIcon}
        key={data.id}
        position={[data.location.latitude, data.location.longitude]}
    >
        <Popup>
        Name: {data.name} <br />
        Station Details:{' '}
        {[data.location.city, data.location.country]}
        </Popup>
    </Marker>
    )
})}

As an extra, you might also want to default the value of filteredBikes to the response that you get from the server, so that the user initially sees something on screen:

componentDidMount() {
    fetch('https://api.citybik.es/v2/networks')
      .catch(error => {
        console.log(error)
      })
      .then(res => res.json())
      .then(response => {
        const networkData = response.networks
        this.setState({
          bikeData: networkData,
          filteredBikeData : networkData // Add this
        })
      })
  }


来源:https://stackoverflow.com/questions/52637614/filter-react-table-and-react-leaflet-marker-at-the-same-time-using-textfield-sh

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!