Hi everybody,
I have been surfing the web for a while now, looking for the best pattern for my use case. It might interest people that suffer, like me, from the #TodoAppFatigue and who like complex example.
Here it is : I am building a “CityAutocomplete” module. That’s it, an autocomplete that complete the city name while you type it.
Obviously, there are a lot of cities in France, because we like our villages and our countryside. And to make things easier, I don’t want to be dependant on any existing API (critical feature).
Here is the structure of my MongoDb collection containing all my city names :
...
{_id:XXX, citiesIdx:"mar", cities:["marseille", "marseillan","marly-gomont",...]},
{_id:XXX, citiesIdx:"mon", cities:["montpellier", "montélimar",...]},
...
This way, I can start autocompleting only after 3 characters without loading the whole database. I only load the city names that match the first 3 letters of the input, using my citiesIdx
index.
Okay, now things get complicated : since I subscribe only to the relevant data, I must update my subscription depending on the user input.
- I cannot pass the
citiesIdx
as a prop of the component, since it depends on the user input - I cannot simply use
createContainer
, since I must update the subscription based on state, not on props
I have working solutions, but I’d like to find a satisfying pattern. What’s your opinion on this ?
Here is my current sample code, using only one component:
import AutoComplete from 'material-ui/AutoComplete'
import Cities from '../../../../collections/Cities'
import React, { Component, PropTypes } from 'react'
export class CityAutocomplete extends Component{
constructor(){
super()
this.state = {currentSub:null, cities:[]}
this.updateCities = this.updateCities.bind(this)
this.updateSubscription = this.updateSubscription.bind(this)
}
updateSubscription(cityName){
const {currentSub} = this.state
const { updateCities } = this
// remove existing subscription
if (currentSub && currentSub.stop) currentSub.stop()
// update the subscription
this.setState({
currentSub: Meteor.subscribe('cities.list', cityName.toLowerCase(),{
onReady(){
updateCities()
}
})
})
}
updateCities(){
// update the cities when subscription is ready
this.setState({
cities: Cities.findOne().cities || []
})
}
render(){
const { cities } = this.state
return(
<div>
<AutoComplete
dataSource={cities}
onUpdateInput={this.updateSubscription}
/>
</div>
)
}
}
export default CityAutocomplete