1# Building a Food Category List Layout 2 3 4Use the List component and ForEach loop to build the food category list layout. 5 6 71. Create a page file named FoodCategoryList.ets in the pages directory, rename the index.ets file FoodDetail.ets, and add the renamed file to the "pages" tag in the config.json file. The first page under the tag is the home page. 8 9 ``` 10 "js": [ 11 { 12 "pages": [ 13 "pages/FoodCategoryList", 14 "pages/FoodDetail" 15 ], 16 ] 17 ``` 18 192. Create a List component named FoodList as the page entry point. Then, add a ListItem component named FoodListItem as its child component. The List component is used to display data of the same type. Its child component \<ListItem> is used to display specific items in the list. 20 21 ``` 22 @Component 23 struct FoodListItem { 24 build() {} 25 } 26 27 @Entry 28 @Component 29 struct FoodList { 30 build() { 31 List() { 32 ListItem() { 33 FoodListItem() 34 } 35 } 36 } 37 } 38 ``` 39 403. Import the FoodData class and initializeOnStartup method. 41 42 ``` 43 import { FoodData } from '../model/FoodData' 44 import { initializeOnStartup } from '../model/FoodDataModels' 45 ``` 46 474. Configure the FoodList and FoodListItem components to pass values. Create a member variable named foodItems of the FoodData[] type in the FoodList component and invoke the initializeOnStartup method to assign a value to the variable. Create a member variable foodItem of the FoodData type in the FoodListItem component. Pass the foodItems[0] of the first element in the parent foodItems array as a parameter to FoodListItem. 48 49 ``` 50 import { FoodData } from '../model/FoodData' 51 import { initializeOnStartup } from '../model/FoodDataModels' 52 53 @Component 54 struct FoodListItem { 55 private foodItem: FoodData 56 build() {} 57 } 58 59 @Entry 60 @Component 61 struct FoodList { 62 private foodItems: FoodData[] = initializeOnStartup() 63 build() { 64 List() { 65 ListItem() { 66 FoodListItem({ foodItem: this.foodItems[0] }) 67 } 68 } 69 } 70 } 71 ``` 72 735. Declare the UI layout of the FoodListItem child component. Create a Flex component, including the food image thumbnail, food name, and calories in the food. 74 75 ``` 76 import { FoodData } from '../model/FoodData' 77 import { initializeOnStartup } from '../model/FoodDataModels' 78 79 @Component 80 struct FoodListItem { 81 private foodItem: FoodData 82 build() { 83 Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 84 Image(this.foodItem.image) 85 .objectFit(ImageFit.Contain) 86 .height(40) 87 .width(40) 88 .backgroundColor('#FFf1f3f5') 89 .margin({ right: 16 }) 90 Text(this.foodItem.name) 91 .fontSize(14) 92 .flexGrow(1) 93 Text(this.foodItem.calories + ' kcal') 94 .fontSize(14) 95 } 96 .height(64) 97 .margin({ right: 24, left:32 }) 98 } 99 } 100 101 @Entry 102 @Component 103 struct FoodList { 104 private foodItems: FoodData[] = initializeOnStartup() 105 build() { 106 List() { 107 ListItem() { 108 FoodListItem({ foodItem: this.foodItems[0] }) 109 } 110 } 111 } 112 } 113 ``` 114 115  116 1176. Create two FoodListItem objects. Create two FoodListItem objects in the List component and pass the first element this.foodItems[0] and the second element foodItem: this.foodItems[1] to the FoodListItem. 118 119 ``` 120 import { FoodData } from '../model/FoodData' 121 import { initializeOnStartup } from '../model/FoodDataModels' 122 123 @Component 124 struct FoodListItem { 125 private foodItem: FoodData 126 build() { 127 Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 128 Image(this.foodItem.image) 129 .objectFit(ImageFit.Contain) 130 .height(40) 131 .width(40) 132 .backgroundColor('#FFf1f3f5') 133 .margin({ right: 16 }) 134 Text(this.foodItem.name) 135 .fontSize(14) 136 .flexGrow(1) 137 Text(this.foodItem.calories + ' kcal') 138 .fontSize(14) 139 } 140 .height(64) 141 .margin({ right: 24, left:32 }) 142 } 143 } 144 145 @Entry 146 @Component 147 struct FoodList { 148 private foodItems: FoodData[] = initializeOnStartup() 149 build() { 150 List() { 151 ListItem() { 152 FoodListItem({ foodItem: this.foodItems[0] }) 153 } 154 ListItem() { 155 FoodListItem({ foodItem: this.foodItems[1] }) 156 } 157 } 158 } 159 } 160 ``` 161 162  163 1647. Import ForEach so that you do not need to create FoodListItem objects one by one. 165 166 ``` 167 ForEach( 168 arr: any[], // Array to be iterated 169 itemGenerator: (item: any) => void, // child component generator 170 keyGenerator?: (item: any) => string // (optional) Unique key generator, which is recommended. 171 ) 172 ``` 173 174 The ForEach group has three parameters. The first parameter is the array to be traversed, the second parameter is the lambda function for generating child components, and the third parameter is the key value generator. The third parameter is optional. Yet, for performance reasons, it is strongly recommended that you provide it. keyGenerator enables the development framework to better recognize array changes without having to rebuild all nodes after item changes. 175 176 Traverse the foodItems array to cyclically create the ListItem component. Pass each item in foodItems as a parameter to the FoodListItem component. 177 178 179 ``` 180 ForEach(this.foodItems, item => { 181 ListItem() { 182 FoodListItem({ foodItem: item }) 183 } 184 }, item => item.id.toString()) 185 ``` 186 187 The code is as follows: 188 189 190 ``` 191 import { FoodData } from '../model/FoodData' 192 import { initializeOnStartup } from '../model/FoodDataModels' 193 194 @Component 195 struct FoodListItem { 196 private foodItem: FoodData 197 build() { 198 Flex({ justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center }) { 199 Image(this.foodItem.image) 200 .objectFit(ImageFit.Contain) 201 .height(40) 202 .width(40) 203 .backgroundColor('#FFf1f3f5') 204 .margin({ right: 16 }) 205 Text(this.foodItem.name) 206 .fontSize(14) 207 .flexGrow(1) 208 Text(this.foodItem.calories + ' kcal') 209 .fontSize(14) 210 } 211 .height(64) 212 .margin({ right: 24, left:32 }) 213 } 214 } 215 216 @Entry 217 @Component 218 struct FoodList { 219 private foodItems: FoodData[] = initializeOnStartup() 220 build() { 221 List() { 222 ForEach(this.foodItems, item => { 223 ListItem() { 224 FoodListItem({ foodItem: item }) 225 } 226 }, item => item.id.toString()) 227 } 228 } 229 } 230 ``` 231 2328. Add a title for the FoodList. 233 234 ``` 235 @Entry 236 @Component 237 struct FoodList { 238 private foodItems: FoodData[] = initializeOnStartup() 239 build() { 240 Column() { 241 Flex({justifyContent: FlexAlign.Start, alignItems: ItemAlign.Center}) { 242 Text('Food List') 243 .fontSize(20) 244 .margin({ left:20 }) 245 } 246 .height('7%') 247 .backgroundColor('#FFf1f3f5') 248 List() { 249 ForEach(this.foodItems, item => { 250 ListItem() { 251 FoodListItem({ foodItem: item }) 252 } 253 }, item => item.id.toString()) 254 } 255 .height('93%') 256 } 257 } 258 } 259 ``` 260 261  262