Advertisement
Guest User

Untitled

a guest
Apr 25th, 2019
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.75 KB | None | 0 0
  1. # Shouldn't be difficult to convert to ES6
  2. # JQuery is used for the API call ONLY. I did this because I had to. DON'T DO THIS!
  3. # Note: additionalInfoOptions is used to store additional data about the record. If data is
  4. # coming and going from the same interface its should not be needed. This was not case of writing this code.
  5.  
  6. modulejs.define 'react/autocomplete_input',
  7. ['react', 'prop-types', 'underscore', 'jquery'],
  8. (React, PropTypes, _, $) ->
  9.  
  10. class AutocompleteInput extends React.Component
  11. @propTypes:
  12. inputType: PropTypes.string
  13. inputName: PropTypes.string
  14. placeHolder: PropTypes.string
  15. dataListID: PropTypes.string
  16. selectListID: PropTypes.string
  17. searchKeys: PropTypes.array
  18. optionAdded: PropTypes.func
  19. optionRemoved: PropTypes.func
  20. url: PropTypes.string
  21. selected: PropTypes.array
  22. additionalInfo: PropTypes.array
  23. additionalInfoOptions: PropTypes.object
  24. optionAddedOptions: PropTypes.array
  25. optionFormatterOptions: PropTypes.object
  26.  
  27. @defaultProps:
  28. inputType: 'text'
  29. inputName: 'generic-input'
  30. placeHolder: 'Start typing'
  31. dataListID: 'generic-data-list'
  32. selectListID: 'generic-selected-list'
  33. searchKeys: ['name', 'email','username']
  34. optionAddedOptions: ['id', 'name', 'email']
  35. optionFormatterOptions: {key: 'id', value: 'name', display: 'name'}
  36. additionalInfoOptions: {match: 'id', key: 'id', data_id: 'id', display: 'name'}
  37.  
  38. constructor: (props) ->
  39. super(props)
  40.  
  41. @state =
  42. searchText: ""
  43. data: []
  44.  
  45. # Format records returned from search into option elements for datalist
  46. # @params record [Object], a record object
  47. # @params options [Object], specified attributes of the object to build the option element
  48. # @returns JSX option <object>
  49. # see optionFormatterOptions default props
  50. optionFormatter: (record, options) =>
  51. return `<option key={record[options.key]}
  52. value={record[options.value]}
  53. >
  54. {record[options.display]}
  55. </option>`
  56.  
  57. # Format records as unordered list elements for displaying the selecteded list
  58. # @params id [Number], the record id
  59. # @params options [Object], the specified attributes of the object to build the list element (based on additionalInfo prop)
  60. # returns JSX <li>
  61. # see additionalInfo default props
  62. listFormatter: (id, options) =>
  63. that = this
  64.  
  65. info = _.find this.props.additionalInfo, (i) -> i[options.match] == id
  66.  
  67. if info != undefined # ignore while searching for a user
  68. display = info[options.display]
  69.  
  70. return `<li key={info[options.key]}
  71. className="picked_item"
  72. >
  73. {display}
  74. <a
  75. data-id={info[options.data_id]}
  76. onClick={that.deleteSelected}
  77. href='#'
  78. >
  79. &times;
  80. </a>
  81. </li>`
  82.  
  83. # Filter results of partial matches to full matches
  84. # @params searchText [String], the text in the input from the onChange func.
  85. # @returns [Array], an array of matching results as objects.
  86. # see searchKeys prop
  87. # see data state
  88. fullMatch: (searchText) =>
  89. that = this
  90.  
  91. _.find this.state.data, (record) ->
  92. for search_key in that.props.searchKeys
  93. if record[search_key] == searchText
  94. return record
  95. break
  96.  
  97. # Filter results from search to partial matches
  98. # @returns [Array], the list of partial matches as objects.
  99. # see searchKeys prop
  100. filterResults: () =>
  101. regx = new RegExp(this.state.searchText, 'gi')
  102. that = this
  103.  
  104. _.filter this.state.data, (record) ->
  105. for search_key in that.props.searchKeys
  106. if record[search_key].match(regx)
  107. return record
  108. break
  109.  
  110. # Get data based on search text
  111. # @params searchText [String], the text used for the pull of records
  112. # @returns data [array], array of record as objects
  113. getData: (searchText) =>
  114. that = this
  115. $.ajax
  116. async: true,
  117. type: "GET",
  118. global: false,
  119. dataType: 'JSON',
  120. url: this.props.url,
  121. data: { 'value': searchText },
  122. success: (data) ->
  123. that.setState
  124. searchText: searchText
  125. data: data
  126.  
  127. # Search and narrow options down
  128. # @params e [Event], the input event
  129. # see getData func
  130. # see fullMatch func
  131. # see addSelected func
  132. onChangeHandler: (e) =>
  133. e.preventDefault()
  134. prevSearchText = this.state.searchText
  135. searchText = e.target.value
  136.  
  137. this.setState
  138. searchText: searchText
  139.  
  140. # Clear data list when user clears the input field.
  141. if searchText == ""
  142. this.setState
  143. searchText: ""
  144. data: []
  145. return
  146.  
  147. # Don't run any code until the user types at leaast 2 characters
  148. if searchText.length >= 2
  149. starterRegx = new RegExp('^' + searchText.substring(0,2), 'i')
  150. # Get data in the event the first 2 characters do not match otherwise continue to update the searchText
  151. if this.state.searchText.match(starterRegx)
  152. this.setState
  153. searchText: searchText
  154. else
  155. this.getData(searchText)
  156.  
  157. # Check for full match
  158. fullMatch = this.fullMatch(searchText)
  159.  
  160. # Add user if full match exists
  161. if typeof fullMatch == 'object'
  162. this.addSelected(fullMatch)
  163.  
  164. # Add record to component (redux).
  165. # @params fullMatch [String], the record object
  166. # see optionAddedOptions prop
  167. # see optionAdded prop
  168. addSelected: (fullMatch) =>
  169. if this.props.optionAddedOptions.length > 0
  170. options = {}
  171.  
  172. for key in this.props.optionAddedOptions
  173. options[key] = fullMatch[key]
  174.  
  175. this.setState
  176. searchText: ''
  177. data: []
  178. this.props.optionAdded?(options) # redux action
  179.  
  180. # Delete record from component (redux)
  181. # @params e [Event], the click event
  182. # see optionRemoved prop
  183. deleteSelected: (e) =>
  184. e.preventDefault()
  185.  
  186. id = e.target.dataset['id']
  187.  
  188. this.props.optionRemoved?(id) # redux action
  189.  
  190. event.stopPropagation()
  191.  
  192. render: ->
  193. selected_items = []
  194.  
  195. # Find partial matches based on regx object
  196. results = this.filterResults()
  197.  
  198. that = this
  199.  
  200. # Convert results to array of JSX <option></option>
  201. formattedResults = _.map results, (record) -> that.optionFormatter(record, that.props.optionFormatterOptions)
  202.  
  203. # Convert users in redux to to JSX <li></li> for displaying
  204. _.each this.props.selected, (id) -> selected_items.push(that.listFormatter(id, that.props.additionalInfoOptions))
  205.  
  206. `<div>
  207. <input
  208. type={this.props.inputType}
  209. name={this.props.inputName}
  210. placeholder={this.props.placeHolder}
  211. list={this.props.dataListID}
  212. onChange={this.onChangeHandler}
  213. value={this.state.searchText}
  214. />
  215.  
  216. <datalist id={this.props.dataListID}>
  217. {formattedResults}
  218. </datalist>
  219.  
  220. <div className='filter-selector'>
  221. <ul id={this.props.selectListID} className="picked_item_list">
  222. {selected_items}
  223. </ul>
  224. </div>
  225. </div>`
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement