{"componentChunkName":"component---src-templates-lesson-post-js","path":"/lesson/rendering-models","result":{"data":{"strapiLesson":{"id":"Lesson_117","author":{"email":"tshedor@gmail.com","username":"Tim Shedor","twitter":"tshedor"},"content":"\nNow that the repository can fetch and create the model using generated code, the model needs to be rendered. First, the repository needs to be initially configured to set its base API URL:\n\n```dart\nclass MyHomePage extends StatefulWidget {\n  MyHomePage({Key key, this.title}) : super(key: key);\n\n  final String title;\n\n  @override\n  _MyHomePageState createState() => _MyHomePageState();\n}\n\nclass _MyHomePageState extends State<MyHomePage> {\n  @override\n  void initState() {\n    // be sure to run `dart server.dart` before using this example\n    Repository.configure('http://localhost:8080');\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(widget.title),\n      ),\n      body: Container()\n  }\n}\n```\n\nThe Repository also needs to run some setup code. In our case with `OfflineFirstWithRest`, that's SQLite migrations. We'll add a `migrated` member to track whether this setup has been completed:\n\n```dart\nclass _MyHomePageState extends State<MyHomePage> {\n  var migrated = false;\n  @override\n  void initState() {\n    // be sure to run `dart server.dart` before using this example\n    Repository.configure('http://localhost:8080');\n    // Note that subsequent boots of the app will use cached data\n    // To clear this, wipe data on android or tap-press on iOS and delete the app\n    Repository().initialize().then((_) => setState(() => migrated = true));\n    super.initState();\n  }\n```\n\nAnd in our widget, a toggle to prevent data fetching while the database is being migrated:\n\n```dart\nWidget build(BuildContext context) {\n  return Scaffold(\n    appBar: AppBar(\n      title: Text(widget.title),\n    ),\n    body: migrated ? Container() : Text(\"Migrating database...\"),\n  );\n}\n```\n\nBrick should be accessed outside a widget to prevent duplicate refetching on every rerender. However, to keep this complicated example straightforward, fetching will be handled by a `FutureBuilder` widget:\n\n```dart\nFutureBuilder(\n  future: Repository().get<Customer>(),\n  builder: (context, AsyncSnapshot<List<Customer>> customerList) {\n    final customers = customerList.data;\n  },\n),\n```\n\nNext, in anticipation of receiving a list of customers, we'll create a widget that accepts an instance of the model and renders its basic properties:\n\n```dart\nclass CustomerTile extends StatelessWidget {\n  final Customer customer;\n\n  CustomerTile(this.customer);\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      mainAxisAlignment: MainAxisAlignment.start,\n      children: <Widget>[\n        Text('id: ${customer.id}'),\n        Text('name: ${customer.firstName} ${customer.lastName}'),\n      ],\n    );\n  }\n}\n```\n\nFinally we combine everything and render a `ListView` of `CustomerTile`s:\n\n```dart\nclass MyHomePage extends StatefulWidget {\n  MyHomePage({Key key, this.title}) : super(key: key);\n\n  final String title;\n\n  @override\n  _MyHomePageState createState() => _MyHomePageState();\n}\n\nclass _MyHomePageState extends State<MyHomePage> {\n  var migrated = false;\n  @override\n  void initState() {\n    // be sure to run `dart server.dart` before using this example\n    Repository.configure('http://localhost:8080');\n    // Note that subsequent boots of the app will use cached data\n    // To clear this, wipe data on android or tap-press on iOS and delete the app\n    Repository().initialize().then((_) => setState(() => migrated = true));\n    super.initState();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(widget.title),\n      ),\n      body: migrated\n          ? Container(\n              padding: const EdgeInsets.all(20.0),\n              child: FutureBuilder(\n                future: Repository().get<Customer>(),\n                builder: (context, AsyncSnapshot<List<Customer>> customerList) {\n                  final customers = customerList.data;\n\n                  return ListView.builder(\n                    itemCount: customers?.length ?? 0,\n                    itemBuilder: (ctx, index) => CustomerTile(customers[index]),\n                  );\n                },\n              ),\n            )\n          : Text(\"Migrating database...\"),\n    );\n  }\n}\n\nclass CustomerTile extends StatelessWidget {\n  final Customer customer;\n\n  CustomerTile(this.customer);\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      mainAxisAlignment: MainAxisAlignment.start,\n      children: <Widget>[\n        Text('id: ${customer.id}'),\n        Text('name: ${customer.firstName} ${customer.lastName}'),\n        Text('pizzas:'),\n        Padding(\n          padding: const EdgeInsets.only(left: 20.0),\n          child: Column(\n            mainAxisAlignment: MainAxisAlignment.start,\n            children: <Widget>[\n              for (var pizza in customer.pizzas) Text('id: ${pizza.id}\\nfrozen: ${pizza.frozen}'),\n            ],\n          ),\n        )\n      ],\n    );\n  }\n}\n```\n","updated_at":"Saturday, 25th of July, 2020","slug":"rendering-models","strapiId":117,"title":"Rendering Models","tutorial":{"category":"Flutter","title":"Handling Data with Brick: Offline First with Rest"}},"strapiTutorial":{"lessons":[{"author":2,"content":"A [Repository](https://github.com/greenbits/brick#repository) in Brick is the **only** interaction point between your app and Brick. It accepts requests and queries and chooses which [Provider](https://github.com/greenbits/brick#provider) will satisfy with data.\n\nMost domains will contain a repository to extend in your app with minimal configuration. We'll use the `OfflineFirstWithRest` domain, which will connect our app with a [memory cache provider], a [SQLite provider], and a [REST provider]. First, import required packages and app data (saved in `lib/app/repository.dart`):\n\n```dart\n// import packages that include repository and provider definitions\nimport 'package:brick_offline_first/offline_first_with_rest.dart';\n// import our generated migrations\nimport 'db/schema.g.dart';\n// import our model dictionaries\n// model dictionaries are lower-level, generated code. Read more about them here: https://github.com/greenbits/brick#translation-and-the-model-dictionary\nimport 'brick.g.dart';\n```\n\nUsing the generated code and package data, we'll construct our repository. As the repository will most likely be accessed outside the widget tree in a state manager (such as a BLoC), we'll set it up as a Singleton:\n\n```dart\nclass Repository extends OfflineFirstWithRestRepository {\n  Repository._(String baseApiUrl)\n      : super();\n\n  factory Repository() => _singleton ?? Exception(\"Must call #configure first\");\n\n  static Repository _singleton;\n\n  static void configure(String baseApiUrl) {\n    _singleton = Repository._(baseApiUrl);\n  }\n}\n```\n\n`OfflineFirstWithRestRepository` requires some customization to setup. We'll pass the consistent arguments into `super`:\n\n```dart\nRepository._(String baseApiUrl) : super(\n  restProvider: RestProvider(\n    // this is the protocol + domain that all generated endpoint will suffix\n    baseApiUrl,\n    modelDictionary: restModelDictionary, // provided in brick.g.dart\n  ),\n  sqliteProvider: SqliteProvider(\n    // this could be any name, and it's recommended to end with .sqlite\n    \"myApp.sqlite\",\n    modelDictionary: sqliteModelDictionary, // provided in brick.g.dart\n  ),\n  migrations: migrations, // provided in schema.g.dart\n);\n```\n\nOur complete repository:\n\n```dart\nimport 'package:brick_offline_first/offline_first_with_rest.dart';\nimport 'db/schema.g.dart';\nimport 'brick.g.dart';\n\nclass Repository extends OfflineFirstWithRestRepository {\n  Repository._(String endpoint)\n      : super(\n          restProvider: RestProvider(\n            endpoint,\n            modelDictionary: restModelDictionary,\n          ),\n          sqliteProvider: SqliteProvider(\n            \"myApp.sqlite\",\n            modelDictionary: sqliteModelDictionary,\n          ),\n          migrations: migrations,\n        );\n\n  factory Repository() => _singleton ?? Exception(\"Must call #configure first\");\n\n  static Repository _singleton;\n\n  static void configure(String endpoint) {\n    _singleton = Repository._(endpoint);\n  }\n}\n```\n","created_at":"2020-07-25T15:14:18.594Z","id":114,"slug":"adding-a-repository","title":"Adding a Repository","tutorial":12,"updated_at":"2020-07-25T15:14:18.605Z"},{"author":2,"content":"Now that we can query data, we need to have data to query. Models are unique to apps, containing the business logic layer required for the system to function. This is analogous to models in Rails or Phoenix.\n\nWe'll create a common customer model, saved in `lib/app/models/customer.dart`:\n\n```dart\n// import the classes to extend\nimport 'package:brick_offline_first/offline_first_with_rest.dart';\n```\n\nBrick works by generating files through Dart's [build_runner](https://pub.dev/packages/build_runner). To discover these files, all models **must** be in the `model/` directory and they **must** have a domain annotation. Since we're using `OfflineFirstWithRest`, we'll use the `ConnectOfflineFirstWithRest` annotation:\n\n```dart\n@ConnectOfflineFirstWithRest()\nclass Customer extends OfflineFirstWithRestModel {}\n```\n\nSince every API is different, the endpoints are very difficult to predict. For each `RestModel` that interacts with a `RestProvider`, an `endpoint:` must be defined. Brick accepts a **function body** (`{...}` or `=> ...;`) with the guaranteed arguments of `instance` (if an instance is provided, such as in an `upsert` or a `delete` call) and `query`. This is stringified as annotations must be constant and functions are not currently considered constant by Dart's type system. This code will be injected unwrapped into our [Adapter](https://github.com/greenbits/brick/tree/master/packages/brick_build#adapter):\n\n```dart\n@ConnectOfflineFirstWithRest(\n  restConfig: RestSerializable(\n    // these match the endpoints configured by our stub server in server.dart\n    endpoint: r'''{\n    if (query.action == QueryAction.upsert) {\n      return \"/customers\";\n    }\n\n    // member endpoint\n    if (query.action == QueryAction.get && instance != null) {\n      return \"/customer/${instance.id}\";\n    }\n\n    return \"/customers\";\n  }''',\n  ),\n)\n```\n\nThe model should reflect the endpoint's data, or at least what we want to send to it. Examining `_api/customer.json`, we apply the JSON property keys as model members:\n\n```dart\nclass Customer extends OfflineFirstWithRestModel {\n  @Sqlite(unique: true)\n  final int id;\n\n  final String firstName;\n\n  final String lastName;\n\n  Customer({\n    this.id,\n    this.firstName,\n    this.lastName,\n  });\n}\n```\n\nOur endpoint response includes a `pizza_ids` property, but as we haven't created the `Pizza` model yet, we'll add that member when we're ready.\n\nOur complete `Customer` model:\n\n```dart\nimport 'package:brick_offline_first/offline_first_with_rest.dart';\n\n@ConnectOfflineFirstWithRest(\n  restConfig: RestSerializable(\n    endpoint: r'''{\n    if (query.action == QueryAction.upsert) {\n      return \"/customers\";\n    }\n\n    // member endpoint\n    if (query.action == QueryAction.get && instance != null) {\n      return \"/customer/${instance.id}\";\n    }\n\n    return \"/customers\";\n  }''',\n  ),\n)\nclass Customer extends OfflineFirstWithRestModel {\n  @Sqlite(unique: true)\n  final int id;\n\n  final String firstName;\n\n  final String lastName;\n\n  Customer({\n    this.id,\n    this.firstName,\n    this.lastName,\n  });\n}\n```\n","created_at":"2020-07-25T15:14:39.805Z","id":115,"slug":"adding-a-model","title":"Adding a Model","tutorial":12,"updated_at":"2020-07-25T15:14:39.814Z"},{"author":2,"content":"\n<div class=\"aside\">\nYou can find the same content in video form <a href=\"https://www.youtube.com/channel/UCNVrhIPfoA6otGTvlzYb7DA/\">on the Flutter by Example youtube channel.</a>\n</div>\n\n[Brick](https://github.com/greenbits/brick) is a data persistence library in Flutter. It filters data from multiple sources through a single entrypoint - for example, when requesting a list of users, Brick will poll users in-memory, users in SQLite, and, if all else fails, users in Firestore. All of this happens through a consistent query interface and a bunch of generated code, leaving your app to focus on simply _using_ the data.\n\nThis tutorial will walk through creating models, interacting with an API endpoint, and finally, rendering data.\n\nAs every API varies, one has to be stubbed to plainly illustrate the example.\n\nSave each API response in a `_api` folder in the root of a new Flutter app:\n\n1. `_api/customer.json`\n    ```json\n    {\n      \"customer\": {\n        \"id\": 1,\n        \"pizza_ids\": [\n          1\n        ],\n        \"firstName\": \"Wallace\",\n        \"lastName\": \"Wallaceton\"\n      }\n    }\n    ```\n1. `_api/customers.json`\n    ```json\n    {\n      \"customers\": [\n        {\n          \"id\": 1,\n          \"pizza_ids\": [\n            1\n          ],\n          \"firstName\": \"Wallace\",\n          \"lastName\": \"Wallaceton\"\n        }\n      ]\n    }\n    ```\n1. `_api/pizza.json`\n    ```json\n    {\n      \"pizza\": {\n        \"id\": 1,\n        \"customer_id\": 1,\n        \"frozen\": false,\n        \"toppings\": [\n          \"pepperoni\",\n          \"olives\"\n        ]\n      }\n    }\n    ```\n1. `_api/pizzas.json`\n    ```json\n    {\n      \"pizzas\": [\n        {\n          \"id\": 1,\n          \"customer_id\": 1,\n          \"frozen\": false,\n          \"toppings\": [\n            \"pepperoni\",\n            \"olives\"\n          ]\n        }\n      ]\n    }\n    ```\n\nNow add `shelf: any` to your pubspec.yaml. And lastly, create the file that will power our local API server:\n\n`server.dart`\n```dart\nimport 'package:shelf/shelf.dart' as shelf;\nimport 'package:shelf/shelf_io.dart' as io;\nimport 'dart:io';\n\nvoid main() {\n  var handler = const shelf.Pipeline().addMiddleware(shelf.logRequests()).addHandler(_echoRequest);\n\n  io.serve(handler, 'localhost', 8080).then((server) {\n    print('Serving at http://${server.address.host}:${server.port}');\n  });\n}\n\nFuture<shelf.Response> _echoRequest(shelf.Request request) async {\n  final endpoints = [\"customers\", \"pizza\", \"pizzas\"];\n\n  return await endpoints\n      .fold(shelf.Response.notFound(\"Request ${request.url} does not match a known endpoint\"),\n          (acc, endpoint) async {\n    final resp = await _jsonForRequest(request, endpoint);\n    if (resp != null) return shelf.Response.ok(resp, headers: {\"Content-Type\": \"application/json\"});\n    return acc;\n  });\n}\n\nFuture<String> _jsonForRequest(shelf.Request request, String fileName) async {\n  if (!request.url.toString().startsWith(fileName)) return null;\n  return await File(\"_api/$fileName.json\").readAsString();\n}\n```\n\nNow that our API is stubbed, we can do the regular Brick install:\n\n1. Add the packages to `pubspec.yaml`:\n    ```yaml\n    dependencies:\n      brick_offline_first: any\n    dev_dependencies:\n      brick_offline_first_with_rest_build:\n        git:\n          url: https://github.com/greenbits/brick.git\n          path: packages/brick_offline_first_with_rest_build\n      build_runner: any\n    ```\n1. Setup Brick's expected folders:\n    ```shell\n    mkdir -p lib/app/adapters lib/app/db lib/app/models;\n    ```\n\nNow we can get to the fun part.\n","created_at":"2020-07-25T15:12:06.073Z","id":113,"slug":"about-brick-and-setup","title":"About Brick and setup","tutorial":12,"updated_at":"2020-07-25T15:17:30.039Z"},{"author":2,"content":"Say our system tracks every pizza a customer orders. This is an association, with the pizza as a child model or the parent customer model. Brick automagically syncs and hydrates associations, removing all the painful boilerplate of writing this out manually.\n\nFirst, we'll make the association model in `lib/app/models/pizza.dart`:\n\n```dart\n@ConnectOfflineFirst()\nclass Pizza extends OfflineFirstWithRestModel {\n  /// Read more about `@Sqlite`: https://github.com/greenbits/brick/tree/master/packages/brick_sqlite#fields\n  @Sqlite(unique: true)\n  final int id;\n\n  /// Read more about `@Rest`: https://github.com/greenbits/brick/tree/master/packages/brick_rest#fields\n  @Rest(enumAsString: true)\n  final List<Topping> toppings;\n\n  final bool frozen;\n\n  Pizza({\n    this.id,\n    this.toppings,\n    this.frozen,\n  });\n}\n\nenum Topping { olive, pepperoni }\n```\n\nWe'll apply similar endpoint code to our `Pizza`:\n\n```dart\n@ConnectOfflineFirstWithRest(\n  restConfig: RestSerializable(\n    endpoint: r'''{\n    if (query.action == QueryAction.upsert) {\n      return \"/pizzas\";\n    }\n\n    if (query.action == QueryAction.get && query?.where != null) {\n      final byId = Where.firstByField('id', query.where);\n      // member endpoint\n      if (byId.value != null) {\n        return \"/pizza/${byId.value}\";\n      }\n    }\n\n    if (query.action == QueryAction.get) {\n      return \"/pizzas\";\n    }\n\n    return null;\n  }''',\n  ),\n)\n```\n\nGreat. Let's generate the new migration for `Pizza` as well as its adapter:\n\n```shell\nflutter pub run build_runner build\n```\n\nOur complete `Pizza` model:\n\n```dart\nimport 'package:brick_offline_first/offline_first_with_rest.dart';\n\n@ConnectOfflineFirstWithRest(\n  restConfig: RestSerializable(\n    endpoint: r'''{\n    if (query.action == QueryAction.upsert) {\n      return \"/pizzas\";\n    }\n\n    if (query.action == QueryAction.get && query?.where != null) {\n      final byId = Where.firstByField('id', query.where);\n      // member endpoint\n      if (byId.value != null) {\n        return \"/pizza/${byId.value}\";\n      }\n    }\n\n    if (query.action == QueryAction.get) {\n      return \"/pizzas\";\n    }\n\n    return null;\n  }''',\n  ),\n)\nclass Pizza extends OfflineFirstWithRestModel {\n  /// Read more about `@Sqlite`: https://github.com/greenbits/brick/tree/master/packages/brick_sqlite#fields\n  @Sqlite(unique: true)\n  final int id;\n\n  /// Read more about `@Rest`: https://github.com/greenbits/brick/tree/master/packages/brick_rest#fields\n  @Rest(enumAsString: true)\n  final List<Topping> toppings;\n\n  final bool frozen;\n\n  Pizza({\n    this.id,\n    this.toppings,\n    this.frozen,\n  });\n}\n\nenum Topping { olive, pepperoni }\n```\n\n### Adding the Association to a Parent Model\n\nThe Customer model is now ready to have the Pizza association. Using the `@OfflineFirst` annotation, the key will specify the lookup field of the child model. The value will be the input source, including the deserializing variable name. `data` is always used when deserializing. Some APIs may return a nested map (such as `data['pizza']['ids']`). However, our API is simple and uses a top-level property. Note that `data['pizza_ids']` could be a JSON array or a single value, and these would be defined to `OfflineFirst(where:)` identically.\n\n```dart\nclass Customer extends OfflineFirstWithRestModel {\n  @OfflineFirst(where: {'id': \"data['pizza_ids']\"})\n  // Specifying the `@Rest` name is necessary for upsert and delete methods\n  @Rest(name: 'pizza_ids')\n  final List<Pizza> pizzas;\n}\n```\n\nA foreign key migration is now necessary on the parent model. Generate a new migration:\n\n```shell\nflutter pub run build_runner build\n```\n\n### Rendering\n\nBack in our Flutter app, the `CustomerTile` widget needs to be adjusted to display the pizzas and their properties:\n\n```dart\nclass CustomerTile extends StatelessWidget {\n  final Customer customer;\n\n  CustomerTile(this.customer);\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      mainAxisAlignment: MainAxisAlignment.start,\n      children: <Widget>[\n        Text('id: ${customer.id}'),\n        Text('name: ${customer.firstName} ${customer.lastName}'),\n        Text('pizzas:'),\n        Padding(\n          padding: const EdgeInsets.only(left: 20.0),\n          child: Column(\n            mainAxisAlignment: MainAxisAlignment.start,\n            children: <Widget>[\n              for (var pizza in customer.pizzas) Text('id: ${pizza.id}\\nfrozen: ${pizza.frozen}'),\n            ],\n          ),\n        )\n      ],\n    );\n  }\n}\n```\n\nWhen we load the homepage, we should now see a list of users with their pizzas.\n","created_at":"2020-07-25T15:16:11.456Z","id":118,"slug":"adding-an-association","title":"Adding an Association","tutorial":12,"updated_at":"2020-07-25T15:16:11.463Z"},{"author":2,"content":"Brick hides away the ugly part of fetching data from different sources. Now that we have a model, we need to create its [Adapter](https://github.com/greenbits/brick/tree/master/packages/brick_build#adapter). The Adapter (de)serializes model instances to and from multiple providers.\n\nTo generate all the necessary code for Brick run in the console:\n\n```shell\nflutter pub run build_runner build\n```\n\n:warning: Sometimes `schema.g.dart` does not detect the new migration on a first build. Run `flutter pub run build_runner build` again if this is the case.\n\nTo keep generated code up-to-date and making a new migration on every model save, use build_runner's watch:\n\n```shell\nflutter pub run build_runner watch\n```\n\n### Optional Steps\n\nGenerated code should not be committed. Adding these lines to `.gitignore` is not required, but it is strongly recommended:\n\n```\n*.g.dart\n# alternately, uncomment the lines below to only target brick files\n# app/adapters/*.dart\n# app/db/*.g.dart\n# app/brick.g.dart\n```\n\n\nWhile not required, it's recommend to run this command on every checkout from git. Adding these lines to `.git/hooks/post-checkout` help keep teams in sync when generated code is not committed\n\n```\n# .git/post-checkout\n#!/bin/sh\n\ncd `dirname \"$0\"`\ncd ../../\nflutter pub get\nflutter pub run build_runner build\n```\n","created_at":"2020-07-25T15:15:13.254Z","id":116,"slug":"generating-code","title":"Generating Code","tutorial":12,"updated_at":"2020-07-25T15:15:13.260Z"},{"author":2,"content":"\nNow that the repository can fetch and create the model using generated code, the model needs to be rendered. First, the repository needs to be initially configured to set its base API URL:\n\n```dart\nclass MyHomePage extends StatefulWidget {\n  MyHomePage({Key key, this.title}) : super(key: key);\n\n  final String title;\n\n  @override\n  _MyHomePageState createState() => _MyHomePageState();\n}\n\nclass _MyHomePageState extends State<MyHomePage> {\n  @override\n  void initState() {\n    // be sure to run `dart server.dart` before using this example\n    Repository.configure('http://localhost:8080');\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(widget.title),\n      ),\n      body: Container()\n  }\n}\n```\n\nThe Repository also needs to run some setup code. In our case with `OfflineFirstWithRest`, that's SQLite migrations. We'll add a `migrated` member to track whether this setup has been completed:\n\n```dart\nclass _MyHomePageState extends State<MyHomePage> {\n  var migrated = false;\n  @override\n  void initState() {\n    // be sure to run `dart server.dart` before using this example\n    Repository.configure('http://localhost:8080');\n    // Note that subsequent boots of the app will use cached data\n    // To clear this, wipe data on android or tap-press on iOS and delete the app\n    Repository().initialize().then((_) => setState(() => migrated = true));\n    super.initState();\n  }\n```\n\nAnd in our widget, a toggle to prevent data fetching while the database is being migrated:\n\n```dart\nWidget build(BuildContext context) {\n  return Scaffold(\n    appBar: AppBar(\n      title: Text(widget.title),\n    ),\n    body: migrated ? Container() : Text(\"Migrating database...\"),\n  );\n}\n```\n\nBrick should be accessed outside a widget to prevent duplicate refetching on every rerender. However, to keep this complicated example straightforward, fetching will be handled by a `FutureBuilder` widget:\n\n```dart\nFutureBuilder(\n  future: Repository().get<Customer>(),\n  builder: (context, AsyncSnapshot<List<Customer>> customerList) {\n    final customers = customerList.data;\n  },\n),\n```\n\nNext, in anticipation of receiving a list of customers, we'll create a widget that accepts an instance of the model and renders its basic properties:\n\n```dart\nclass CustomerTile extends StatelessWidget {\n  final Customer customer;\n\n  CustomerTile(this.customer);\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      mainAxisAlignment: MainAxisAlignment.start,\n      children: <Widget>[\n        Text('id: ${customer.id}'),\n        Text('name: ${customer.firstName} ${customer.lastName}'),\n      ],\n    );\n  }\n}\n```\n\nFinally we combine everything and render a `ListView` of `CustomerTile`s:\n\n```dart\nclass MyHomePage extends StatefulWidget {\n  MyHomePage({Key key, this.title}) : super(key: key);\n\n  final String title;\n\n  @override\n  _MyHomePageState createState() => _MyHomePageState();\n}\n\nclass _MyHomePageState extends State<MyHomePage> {\n  var migrated = false;\n  @override\n  void initState() {\n    // be sure to run `dart server.dart` before using this example\n    Repository.configure('http://localhost:8080');\n    // Note that subsequent boots of the app will use cached data\n    // To clear this, wipe data on android or tap-press on iOS and delete the app\n    Repository().initialize().then((_) => setState(() => migrated = true));\n    super.initState();\n  }\n\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(widget.title),\n      ),\n      body: migrated\n          ? Container(\n              padding: const EdgeInsets.all(20.0),\n              child: FutureBuilder(\n                future: Repository().get<Customer>(),\n                builder: (context, AsyncSnapshot<List<Customer>> customerList) {\n                  final customers = customerList.data;\n\n                  return ListView.builder(\n                    itemCount: customers?.length ?? 0,\n                    itemBuilder: (ctx, index) => CustomerTile(customers[index]),\n                  );\n                },\n              ),\n            )\n          : Text(\"Migrating database...\"),\n    );\n  }\n}\n\nclass CustomerTile extends StatelessWidget {\n  final Customer customer;\n\n  CustomerTile(this.customer);\n\n  @override\n  Widget build(BuildContext context) {\n    return Column(\n      mainAxisAlignment: MainAxisAlignment.start,\n      children: <Widget>[\n        Text('id: ${customer.id}'),\n        Text('name: ${customer.firstName} ${customer.lastName}'),\n        Text('pizzas:'),\n        Padding(\n          padding: const EdgeInsets.only(left: 20.0),\n          child: Column(\n            mainAxisAlignment: MainAxisAlignment.start,\n            children: <Widget>[\n              for (var pizza in customer.pizzas) Text('id: ${pizza.id}\\nfrozen: ${pizza.frozen}'),\n            ],\n          ),\n        )\n      ],\n    );\n  }\n}\n```\n","created_at":"2020-07-25T15:15:37.497Z","id":117,"slug":"rendering-models","title":"Rendering Models","tutorial":12,"updated_at":"2020-07-25T15:15:37.506Z"}]},"strapiTableOfContents":{"contents":"{\n  \"Dart\": {\n    \"Getting Started with Dart\": [\n      \"About Dart\",\n      \"Install Dart on your machine\",\n      \"Dartpad\",\n      \"Text Editors: Intellij and VSCode\",\n      \"Resources: Documentation and Pub.dev\",\n      \"Hello World\",\n      \"The main function\",\n      \"Print to the console\"\n    ],\n    \"Dart Fundamentals\": [\n      \"Values and variables\",\n      \"Comments\",\n      \"const and final variables\",\n      \"Arithmetic and Comparison Operators\",\n      \"Assignment Operators\",\n      \"Logical Operators\",\n      \"Null Aware Operators\",\n      \"Type Test Operators\",\n      \"Bitwise and Shift Operators\",\n      \"Control Flow: if, else, else if\",\n      \"Switch statements and case\",\n      \"Ternary Conditional operator\",\n      \"Loops: for and while\",\n      \"Anatomy of Dart Functions\",\n      \"Arrow functions\",\n      \"Function arguments: default, optional, named\",\n      \"Lexical Scope\",\n      \"Cascade notation\"\n    ],\n    \"Data Types\": [\n      \"Intro to Dart's Type System\",\n      \"Numbers\",\n      \"Strings\",\n      \"Booleans\",\n      \"dynamic\",\n      \"lists\",\n      \"sets\",\n      \"maps\"\n    ],\n    \"Object-Oriented Programming\": [\n      \"Intro to OOP\",\n      \"Classes\",\n      \"Constructors\",\n      \"Properties and methods\",\n      \"Methods: static, private, etc\",\n      \"Getters and setters\",\n      \"Extending classes (inheritance)\",\n      \"Initializer lists and final properties\",\n      \"Factory methods\",\n      \"Singletons\",\n      \"Abstract classes (and interfaces)\",\n      \"Mixins\",\n      \"Extension methods\"\n    ],\n    \"Iterables, Iterators, and Collections\": [\n      \"What are collections (and iterables)?\",\n      \"Looping: for-in and forEach\",\n      \"Reading elements pt 1: first, last\",\n      \"Adding elements: add and insert (all)\",\n      \"Checking for elements: contains, indexOf, any, every\",\n      \"Removing elements: remove, clear, removeWhere\",\n      \"Filtering elements: where, takeWhile, and skipWhile\",\n      \"Changing elements: map and expand\",\n      \"Deriving values from elements: fold, reduce, join\",\n      \"Type casting collections: cast, as, retype, toSet, toList\",\n      \"Iterators: understanding and creating your own\",\n      \"Iterable-like methods on maps (and putIfAbsent)\"\n    ]\n  },\n  \"Flutter\": {\n    \"Getting started with Flutter\": [\n      \"About Flutter\",\n      \"IDEs and resources\"\n    ],\n    \"Widgets\": [\n      \"Intro to Widgets\",\n      \"Widget types: Stateful and Stateless\",\n      \"StatefulWidget lifecycle\",\n      \"The Widget tree\",\n      \"BuildContext\",\n      \"Inherited Widgets\",\n      \"Thinking in widgets\"\n    ],\n    \"Intro Flutter App\": [\n      \"Intro and Setup\",\n      \"Data Model and HTTP\",\n      \"Build a custom widget\",\n      \"ListView and builder pattern\",\n      \"Gradient Backgrounds\",\n      \"Routing: Add a detail page\",\n      \"Routing 2: Add a form page\",\n      \"User Input\",\n      \"Sliders and Buttons\",\n      \"Snackbars and Dialogs\",\n      \"Built-in Animation: AnimatedCrossFade\",\n      \"Built-in Animation: Hero transition\"\n    ],\n    \"Custom Animation: Progress Indicator\": [\n      \"Intro and Overview\",\n      \"Build the example app boiler-plate\",\n      \"Custom Widget: Peg\",\n      \"Tween and AnimationController classes\",\n      \"Tween by example\",\n      \"Using Tweens and Intervals\",\n      \"Wrap the Pegs in AnimatedWidgets\",\n      \"Bring it all together\"\n    ],\n    \"State Management: Blocs without Libraries\": [\n      \"What are blocs?\",\n      \"Calendar App introduction\",\n      \"Create bloc one\",\n      \"Create a bloc provider\",\n      \"Using StreamBuilders with blocs\",\n      \"Create bloc two: Add/Edit Tasks\",\n      \"Consume the second bloc's streams\",\n      \"Complete source code\"\n    ],\n    \"State Management: Provider\": [\n      \"What is Provider?\",\n      \"The most basic example using Provider\",\n      \"ChangeNotifierProvider\",\n      \"Rebuilding widgets with Consumer\",\n      \"Finer build control with Selector\",\n      \"Future Provider\",\n      \"MultiProvider micro lesson\",\n      \"Stream Provider\",\n      \"Using context extensions for more control\",\n      \"ProxyProvider\",\n      \"Using .value constructors\",\n      \"The final example (A shopping cart app)\",\n      \"For the curious: How is provider implemented\"\n    ],\n    \"Handling Data with Brick: Offline First with Rest\": [\n      \"About Brick and setup\",\n      \"Adding a Repository\",\n      \"Adding a Model\",\n      \"Generating Code\",\n      \"Rendering Models\",\n      \"Adding an Association\"\n    ]\n  }\n}"}},"pageContext":{"slug":"rendering-models","tutorialTitle":"Handling Data with Brick: Offline First with Rest","previous":{"author":2,"content":"Brick hides away the ugly part of fetching data from different sources. Now that we have a model, we need to create its [Adapter](https://github.com/greenbits/brick/tree/master/packages/brick_build#adapter). The Adapter (de)serializes model instances to and from multiple providers.\n\nTo generate all the necessary code for Brick run in the console:\n\n```shell\nflutter pub run build_runner build\n```\n\n:warning: Sometimes `schema.g.dart` does not detect the new migration on a first build. Run `flutter pub run build_runner build` again if this is the case.\n\nTo keep generated code up-to-date and making a new migration on every model save, use build_runner's watch:\n\n```shell\nflutter pub run build_runner watch\n```\n\n### Optional Steps\n\nGenerated code should not be committed. Adding these lines to `.gitignore` is not required, but it is strongly recommended:\n\n```\n*.g.dart\n# alternately, uncomment the lines below to only target brick files\n# app/adapters/*.dart\n# app/db/*.g.dart\n# app/brick.g.dart\n```\n\n\nWhile not required, it's recommend to run this command on every checkout from git. Adding these lines to `.git/hooks/post-checkout` help keep teams in sync when generated code is not committed\n\n```\n# .git/post-checkout\n#!/bin/sh\n\ncd `dirname \"$0\"`\ncd ../../\nflutter pub get\nflutter pub run build_runner build\n```\n","created_at":"2020-07-25T15:15:13.254Z","id":116,"slug":"generating-code","title":"Generating Code","tutorial":12,"updated_at":"2020-07-25T15:15:13.260Z"},"next":null}},"staticQueryHashes":["2185715291","3564968493","63159454"]}