Advertisement
Guest User

Untitled

a guest
Oct 15th, 2019
114
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.01 KB | None | 0 0
  1. So I was using a `TreeSelect` for creating a cascading select for an object shaped like `country => state => city => neighborhood`.
  2.  
  3. E.g.:
  4.  
  5. ```json
  6. {
  7. "BR": {
  8. "PR": {
  9. "Curitiba": [
  10. "Bigorrilho",
  11. "Jardim Botânico"
  12. ]
  13. },
  14. "SP": {
  15. "São Paulo": [
  16. "Vila Mariana"
  17. ]
  18. }
  19. },
  20. "FR": {
  21. "Île-de-France": {
  22. "Arrondissement de Paris": [
  23. "---"
  24. ]
  25. }
  26. }
  27. }
  28. ```
  29.  
  30. And I wanted to pass it to TreeSelect so that the values can be nested, each one being its `title`, giving each an unique `key`, and each one having an array `value`, in order to capture all parts.
  31.  
  32. So firstly it went like:
  33.  
  34. ```javascript
  35. // addressesKeys => json above
  36.  
  37. <TreeSelect
  38. treeData={Object.entries(addressesKeys).reduce(
  39. (countries, [country, countryStates]) => ([
  40. ...countries, {
  41. title: country,
  42. value: country,
  43. key: country,
  44. children: Object.entries(countryStates).reduce(
  45. (states, [state, stateCities]) => ([
  46. ...states, {
  47. title: state,
  48. value: [country, state],
  49. key: country + state,
  50. children: Object.entries(stateCities).reduce(
  51. (cities, [city, cityNeighborhoods]) => ([
  52. ...cities, {
  53. title: city,
  54. value: [country, state, city],
  55. key: country + state + city,
  56. children: cityNeighborhoods.map(
  57. (neighborhood) => ({
  58. title: neighborhood,
  59. value: [country, state, city, neighborhood],
  60. key: country + state + city + neighborhood,
  61. }))
  62. }])
  63. , []),
  64. }])
  65. , []),
  66. }])
  67. , [])}
  68. />
  69. ```
  70.  
  71. The first thing that appears repeatly is the `{ title, value, key, children? }`. Let's make a function for that:
  72.  
  73. ```javascript
  74. function treeNode(value, children) {
  75. return {
  76. value,
  77. title: value[0],
  78. key: value.join('_'),
  79. children,
  80. };
  81. }
  82. ```
  83.  
  84. Now we have:
  85.  
  86. ```javascript
  87. <TreeSelect
  88. treeData={Object.entries(addressesKeys).reduce(
  89. (countries, [country, countryStates]) => ([
  90. ...countries,
  91. treeNode([country], Object.entries(countryStates).reduce(
  92. (states, [state, stateCities]) => ([
  93. ...states,
  94. treeNode([state, country], Object.entries(stateCities).reduce(
  95. (cities, [city, cityNeighborhoods]) => ([
  96. ...cities,
  97. treeNode([city, state, country], cityNeighborhoods.map(
  98. (neighborhood) => treeNode([neighborhood, city, state, country])
  99. ))
  100. ])
  101. , [])),
  102. ])
  103. , [])),
  104. ])
  105. , [])}
  106. />
  107. ```
  108.  
  109. Cool. But there are some repeated structure yet: `reduce` (for `Object.entries(obj)`) and `map` (for `array`, only last iteration). Let's make another function:
  110.  
  111. ```javascript
  112. function mapToTreeNode(items, oldValue = []) {
  113. // if item is an array
  114. if (Array.isArray(items)) return items.map(
  115. (item) => treeNode([
  116. item,
  117. ...oldValue,
  118. ])
  119. );
  120. // if item is an object
  121. return Object.entries(items).reduce(
  122. (oldItems, [item, children]) => ([
  123. ...oldItems,
  124. treeNode([
  125. item,
  126. ...oldValue,
  127. ], children),
  128. ])
  129. , []);
  130. }
  131. ```
  132.  
  133. Also, we need to change the previous function for calling the last one:
  134.  
  135. ```diff
  136. function treeNode(value, children) {
  137. return {
  138. value,
  139. title: value[0],
  140. key: value.join('_'),
  141. - children,
  142. + children: children && mapToTreeNode(children, value),
  143. };
  144. }
  145. ```
  146.  
  147. This way, we finally get:
  148.  
  149. ```javascript
  150. <TreeSelect treeData={mapToTreeNode(addressesKeys)} />
  151. ```
  152.  
  153. In order to test this, let's make an `onChange` function (use this in every step, because it will work):
  154.  
  155. ```javascript
  156. function handleChange(value) {
  157. let [country, state, city, neighborhood] = value;
  158. console.log({ country, state, city, neighborhood });
  159. }
  160. ```
  161.  
  162. Pass it as a prop, change the component's value and check your console.
  163.  
  164. The full final code is:
  165.  
  166. ```javascript
  167. function mapToTreeNode(items, oldValue = []) {
  168. if (Array.isArray(items)) return items.map(
  169. (item) => treeNode([
  170. item,
  171. ...oldValue,
  172. ])
  173. );
  174. return Object.entries(items).reduce(
  175. (oldItems, [item, children]) => ([
  176. ...oldItems,
  177. treeNode([
  178. item,
  179. ...oldValue,
  180. ], children),
  181. ])
  182. , []);
  183. }
  184.  
  185. function treeNode(value, children) {
  186. return {
  187. value,
  188. title: value[0],
  189. key: value.join('_'),
  190. children: children && mapToTreeNode(children, value),
  191. };
  192. }
  193.  
  194. function handleChange(value) {
  195. let [country, state, city, neighborhood] = value.reverse();
  196. console.log({ country, state, city, neighborhood });
  197. }
  198.  
  199. return (
  200. <TreeSelect
  201. treeData={mapToTreeNode(addressesKeys)}
  202. onChange={handleChange}
  203. />
  204. );
  205. ```
  206.  
  207. With `mapToTreeNode` and `treeNode`, it is possible to nest as much objects as you want, with different depths (i.e. you don't need to know how deep it is in order to programatically call each one), if only the last value in the branch (considering object like a tree) is an array.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement