Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Shouldn't be difficult to convert to ES6
- # JQuery is used for the API call ONLY. I did this because I had to. DON'T DO THIS!
- # Note: additionalInfoOptions is used to store additional data about the record. If data is
- # coming and going from the same interface its should not be needed. This was not case of writing this code.
- modulejs.define 'react/autocomplete_input',
- ['react', 'prop-types', 'underscore', 'jquery'],
- (React, PropTypes, _, $) ->
- class AutocompleteInput extends React.Component
- @propTypes:
- inputType: PropTypes.string
- inputName: PropTypes.string
- placeHolder: PropTypes.string
- dataListID: PropTypes.string
- selectListID: PropTypes.string
- searchKeys: PropTypes.array
- optionAdded: PropTypes.func
- optionRemoved: PropTypes.func
- url: PropTypes.string
- selected: PropTypes.array
- additionalInfo: PropTypes.array
- additionalInfoOptions: PropTypes.object
- optionAddedOptions: PropTypes.array
- optionFormatterOptions: PropTypes.object
- @defaultProps:
- inputType: 'text'
- inputName: 'generic-input'
- placeHolder: 'Start typing'
- dataListID: 'generic-data-list'
- selectListID: 'generic-selected-list'
- searchKeys: ['name', 'email','username']
- optionAddedOptions: ['id', 'name', 'email']
- optionFormatterOptions: {key: 'id', value: 'name', display: 'name'}
- additionalInfoOptions: {match: 'id', key: 'id', data_id: 'id', display: 'name'}
- constructor: (props) ->
- super(props)
- @state =
- searchText: ""
- data: []
- # Format records returned from search into option elements for datalist
- # @params record [Object], a record object
- # @params options [Object], specified attributes of the object to build the option element
- # @returns JSX option <object>
- # see optionFormatterOptions default props
- optionFormatter: (record, options) =>
- return `<option key={record[options.key]}
- value={record[options.value]}
- >
- {record[options.display]}
- </option>`
- # Format records as unordered list elements for displaying the selecteded list
- # @params id [Number], the record id
- # @params options [Object], the specified attributes of the object to build the list element (based on additionalInfo prop)
- # returns JSX <li>
- # see additionalInfo default props
- listFormatter: (id, options) =>
- that = this
- info = _.find this.props.additionalInfo, (i) -> i[options.match] == id
- if info != undefined # ignore while searching for a user
- display = info[options.display]
- return `<li key={info[options.key]}
- className="picked_item"
- >
- {display}
- <a
- data-id={info[options.data_id]}
- onClick={that.deleteSelected}
- href='#'
- >
- ×
- </a>
- </li>`
- # Filter results of partial matches to full matches
- # @params searchText [String], the text in the input from the onChange func.
- # @returns [Array], an array of matching results as objects.
- # see searchKeys prop
- # see data state
- fullMatch: (searchText) =>
- that = this
- _.find this.state.data, (record) ->
- for search_key in that.props.searchKeys
- if record[search_key] == searchText
- return record
- break
- # Filter results from search to partial matches
- # @returns [Array], the list of partial matches as objects.
- # see searchKeys prop
- filterResults: () =>
- regx = new RegExp(this.state.searchText, 'gi')
- that = this
- _.filter this.state.data, (record) ->
- for search_key in that.props.searchKeys
- if record[search_key].match(regx)
- return record
- break
- # Get data based on search text
- # @params searchText [String], the text used for the pull of records
- # @returns data [array], array of record as objects
- getData: (searchText) =>
- that = this
- $.ajax
- async: true,
- type: "GET",
- global: false,
- dataType: 'JSON',
- url: this.props.url,
- data: { 'value': searchText },
- success: (data) ->
- that.setState
- searchText: searchText
- data: data
- # Search and narrow options down
- # @params e [Event], the input event
- # see getData func
- # see fullMatch func
- # see addSelected func
- onChangeHandler: (e) =>
- e.preventDefault()
- prevSearchText = this.state.searchText
- searchText = e.target.value
- this.setState
- searchText: searchText
- # Clear data list when user clears the input field.
- if searchText == ""
- this.setState
- searchText: ""
- data: []
- return
- # Don't run any code until the user types at leaast 2 characters
- if searchText.length >= 2
- starterRegx = new RegExp('^' + searchText.substring(0,2), 'i')
- # Get data in the event the first 2 characters do not match otherwise continue to update the searchText
- if this.state.searchText.match(starterRegx)
- this.setState
- searchText: searchText
- else
- this.getData(searchText)
- # Check for full match
- fullMatch = this.fullMatch(searchText)
- # Add user if full match exists
- if typeof fullMatch == 'object'
- this.addSelected(fullMatch)
- # Add record to component (redux).
- # @params fullMatch [String], the record object
- # see optionAddedOptions prop
- # see optionAdded prop
- addSelected: (fullMatch) =>
- if this.props.optionAddedOptions.length > 0
- options = {}
- for key in this.props.optionAddedOptions
- options[key] = fullMatch[key]
- this.setState
- searchText: ''
- data: []
- this.props.optionAdded?(options) # redux action
- # Delete record from component (redux)
- # @params e [Event], the click event
- # see optionRemoved prop
- deleteSelected: (e) =>
- e.preventDefault()
- id = e.target.dataset['id']
- this.props.optionRemoved?(id) # redux action
- event.stopPropagation()
- render: ->
- selected_items = []
- # Find partial matches based on regx object
- results = this.filterResults()
- that = this
- # Convert results to array of JSX <option></option>
- formattedResults = _.map results, (record) -> that.optionFormatter(record, that.props.optionFormatterOptions)
- # Convert users in redux to to JSX <li></li> for displaying
- _.each this.props.selected, (id) -> selected_items.push(that.listFormatter(id, that.props.additionalInfoOptions))
- `<div>
- <input
- type={this.props.inputType}
- name={this.props.inputName}
- placeholder={this.props.placeHolder}
- list={this.props.dataListID}
- onChange={this.onChangeHandler}
- value={this.state.searchText}
- />
- <datalist id={this.props.dataListID}>
- {formattedResults}
- </datalist>
- <div className='filter-selector'>
- <ul id={this.props.selectListID} className="picked_item_list">
- {selected_items}
- </ul>
- </div>
- </div>`
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement