Working with Models in Flutter

Summary

In this lesson we'll cover:

The Code for This Lesson

Check out the tourismandco repo's step/step05 branch for the code we'll cover in this lesson.

The Significance of an App's Data Model

Our Data Model

How We'll Use Our Models

  1. App loads
  2. Our Location Detail screen loads
  3. Using a hardcoded Location ID (for now), we load the name of our Location and a list of TextSection widgets for each "Location Facts" that it relates to.

Adding Our Models

location.dart

// models/location.dart

import './location_fact.dart';

/// Represents a tourism location a user can visit.
class Location {
  final String name;
  final String imagePath;
  final List<LocationFact> facts;

  Location(this.name, this.imagePath, this.facts);

  // NOTE: implementing functionality here in the next step!
}

Using Generics in Dart

location_fact.dart

// models/location_fact.dart

/// Represents some descriptive information about a [Location].
class LocationFact {
  final String title;
  final String text;

  LocationFact(this.title, this.text);
}

Adding Business Logic to Models

// models/location.dart

// ...

class Location {

  // ...

  static List<Location> fetchAll() {
    return [
      Location('Arashiyama Bamboo Grove', 'assets/images/kiyomizu-dera.jpg', [
        LocationFact('Summary',
            'While we could go on about the ethereal glow and seemingly endless heights of this bamboo grove on the outskirts of Kyoto, the sight\'s pleasures extend beyond the visual realm.'),
        LocationFact('How to Get There',
            'Kyoto airport, with several terminals, is located 16 kilometres south of the city and is also known as Kyoto. Kyoto can also be reached by transport links from other regional airports.'),
      ]),
    ];
  }
}

Making Our Code Dynamic

Updating location_detail.dart

// screens/location_detail/location_detail.dart

import 'package:flutter/material.dart';
import '../../models/location.dart';
import 'image_banner.dart';
import 'text_section.dart';

class LocationDetail extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // simply fetch the first location we have
    // NOTE: we'll be moving this to a scoped_model later
    final locations = Location.fetchAll();
    final location = locations.first;

    return Scaffold(
      appBar: AppBar(
        title: Text(location.name),
      ),
      body: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            ImageBanner(location.imagePath),
          ]..addAll(textSections(location))),
    );
  }

  List<Widget> textSections(Location location) {
    return location.facts
        .map((fact) => TextSection(fact.title, fact.text))
        .toList();
  }
}

Using Cascades in Dart

map() and Anonymous Functions

NOTE: you don't need to master these features of Dart early on. They're used quite often enough so you should naturally get used to them as you write more Dart code.

Summary

In this lesson: