190 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			190 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
include ../_util-fns
 | 
						||
 | 
						||
:marked
 | 
						||
  # Once Upon a Time
 | 
						||
 | 
						||
  Every story starts somewhere. Our story starts where the [QuickStart](../quickstart.html) ends.
 | 
						||
 | 
						||
:marked
 | 
						||
  Follow the "QuickStart" steps. They provide the prerequisites, the folder structure,
 | 
						||
  and the core files for our Tour of Heroes.
 | 
						||
 | 
						||
  <!--
 | 
						||
    TODO: Recommend stagehand?
 | 
						||
  -->
 | 
						||
 | 
						||
  Copy the "QuickStart" code to a new folder and rename the folder `angular2_tour_of_heroes`.
 | 
						||
  We should have the following structure:
 | 
						||
 | 
						||
.filetree
 | 
						||
  .file angular2_tour_of_heroes
 | 
						||
  .children
 | 
						||
    .file lib
 | 
						||
    .children
 | 
						||
      .file app_component.dart
 | 
						||
    .file web
 | 
						||
    .children
 | 
						||
      .file index.html
 | 
						||
      .file main.dart
 | 
						||
    .file pubspec.yaml
 | 
						||
 | 
						||
// Add       .file styles.css
 | 
						||
 | 
						||
.p  
 | 
						||
 | 
						||
.callout.is-helpful
 | 
						||
  header Source code
 | 
						||
  :marked
 | 
						||
    The complete source code for the example app in this chapter is
 | 
						||
    [in GitHub](https://github.com/angular/angular.io/tree/master/public/docs/_examples/toh-1/dart).
 | 
						||
 | 
						||
:marked
 | 
						||
  ## Keep the app compiling and running
 | 
						||
  We want to start the Dart compiler, have it watch for changes, and start our server. We'll do this by typing
 | 
						||
 | 
						||
code-example(format="" language="bash").
 | 
						||
  pub serve
 | 
						||
 | 
						||
:marked
 | 
						||
  This command runs the compiler in watch mode, starts the server,
 | 
						||
  and keeps the app running while we continue to build the Tour of Heroes.
 | 
						||
 | 
						||
.l-main-section
 | 
						||
  :marked
 | 
						||
    ## Show our Hero
 | 
						||
    We want to display Hero data in our app.
 | 
						||
 | 
						||
    Let's add two properties to our `AppComponent`, a `title` property for the application name and a `hero` property
 | 
						||
    for a hero named "Windstorm".
 | 
						||
 | 
						||
  +makeExample('toh-1/dart-snippets/app_component_snippets_pt1.dart', 'app-component-1', 'app_component.dart (AppComponent class)')(format=".")
 | 
						||
 | 
						||
  :marked
 | 
						||
    Now we update the template in the `@Component` annotation with data bindings to these new properties.
 | 
						||
 | 
						||
  +makeExample('toh-1/dart-snippets/app_component_snippets_pt1.dart', 'show-hero')
 | 
						||
 | 
						||
  :marked
 | 
						||
    The browser should refresh and display our title and hero.
 | 
						||
 | 
						||
    The double curly braces tell our app to read the `title` and `hero` properties from the component and render them.
 | 
						||
    This is the "interpolation" form of one-way data binding.
 | 
						||
.l-sub-section
 | 
						||
  :marked
 | 
						||
    Learn more about interpolation in the [Displaying Data chapter](../guide/displaying-data.html).
 | 
						||
:marked
 | 
						||
  ### Hero object
 | 
						||
 | 
						||
  At the moment, our hero is just a name.  Our hero needs more properties.
 | 
						||
  Let's convert the `hero` from a literal string to a class.
 | 
						||
 | 
						||
  Create a `Hero` class with `id` and `name` properties.
 | 
						||
  Keep this near the top of the `app_component.dart` file for now.
 | 
						||
 | 
						||
+makeExample('toh-1/dart/lib/app_component.dart', 'hero-class-1', 'app_component.dart (Hero class)')(format=".")
 | 
						||
 | 
						||
:marked
 | 
						||
  Now that we have a `Hero` class, let’s refactor our component’s `hero` property to be of type `Hero`.
 | 
						||
  Then initialize it with an id of `1` and the name, "Windstorm".
 | 
						||
 | 
						||
+makeExample('toh-1/dart-snippets/app_component_snippets_pt1.dart', 'hero-property-1', 'app_component.dart (Hero property)')(format=".")
 | 
						||
 | 
						||
:marked
 | 
						||
  Because we changed the hero from a string to an object,
 | 
						||
  we update the binding in the template to refer to the hero’s `name` property.
 | 
						||
 | 
						||
+makeExample('toh-1/dart-snippets/app_component_snippets_pt1.dart', 'show-hero-2')
 | 
						||
:marked
 | 
						||
  The browser refreshes and continues to display our hero’s name.
 | 
						||
 | 
						||
  ### Adding more HTML
 | 
						||
  Displaying a name is good, but we want to see all of our hero’s properties.
 | 
						||
  We’ll add a `<div>` for our hero’s `id` property and another `<div>` for our hero’s `name`.
 | 
						||
 | 
						||
+makeExample('toh-1/dart-snippets/app_component_snippets_pt1.dart', 'show-hero-properties')
 | 
						||
:marked
 | 
						||
  Uh oh, our template string is getting long. We better take care of that to avoid the risk of making a typo in the template.
 | 
						||
 | 
						||
  ### Multi-line template strings
 | 
						||
 | 
						||
  We could make a more readable template with string concatenation
 | 
						||
  but that gets ugly fast, it is harder to read, and
 | 
						||
  it is easy to make a spelling error. Instead,
 | 
						||
  let’s take advantage of the template strings feature
 | 
						||
  in Dart to maintain our sanity.
 | 
						||
 | 
						||
  Change the quotes around the template to triple quotes and
 | 
						||
  put the `<h1>`, `<h2>` and `<div>` elements on their own lines.
 | 
						||
 | 
						||
+makeExample('toh-1/dart-snippets/app_component_snippets_pt1.dart', 'multi-line-strings', 'app_component.dart (AppComponent\'s template)')(format=".")
 | 
						||
 | 
						||
// omit back-tick warning
 | 
						||
 | 
						||
.l-main-section
 | 
						||
:marked
 | 
						||
  ## Editing Our Hero
 | 
						||
 | 
						||
  We want to be able to edit the hero name in a textbox.
 | 
						||
 | 
						||
  Refactor the hero name `<label>` with `<label>` and `<input>` elements as shown below:
 | 
						||
 | 
						||
+makeExample('toh-1/dart-snippets/app_component_snippets_pt1.dart', 'editing-Hero', 'app_component.dart (input element)')(format=".")
 | 
						||
:marked
 | 
						||
  We see in the browser that the hero’s name does appear in the `<input>` textbox.
 | 
						||
  But something doesn’t feel right.
 | 
						||
  When we change the name, we notice that our change
 | 
						||
  is not reflected in the `<h2>`. We won't get the desired behavior
 | 
						||
  with a one-way binding to `<input>`.
 | 
						||
 | 
						||
  ### Two-Way Binding
 | 
						||
 | 
						||
  We intend to display the name of the hero in the `<input>`, change it,
 | 
						||
  and see those changes wherever we bind to the hero’s name.
 | 
						||
  In short, we want two-way data binding.
 | 
						||
 | 
						||
  Let’s update the template to use the  **`ngModel`** built-in directive for two-way binding.
 | 
						||
 | 
						||
.l-sub-section
 | 
						||
  :marked
 | 
						||
    Learn more about `ngModel` in the
 | 
						||
    [Forms](../guide/forms.html#ngModel) and
 | 
						||
    [Template Syntax](../guide/template-syntax.html#ngModel) chapters.
 | 
						||
:marked
 | 
						||
  Replace the `<input>` with the following HTML
 | 
						||
 | 
						||
code-example(language="html").
 | 
						||
  <input [(ngModel)]="hero.name" placeholder="name">
 | 
						||
 | 
						||
:marked
 | 
						||
  The browser refreshes. We see our hero again. We can edit the hero’s name and
 | 
						||
  see the changes reflected immediately in the `<h2>`.
 | 
						||
 | 
						||
.l-main-section
 | 
						||
:marked
 | 
						||
  ## The Road We’ve Travelled
 | 
						||
  Let’s take stock of what we’ve built.
 | 
						||
 | 
						||
  * Our Tour of Heroes uses the double curly braces of interpolation (a form of one-way data binding)
 | 
						||
  to display the application title and properties of a `Hero` object.
 | 
						||
  * We wrote a multi-line template using Dart's template strings to make our template readable.
 | 
						||
  * We can both display and change the hero’s name after adding a two-way data binding to the `<input>` element
 | 
						||
  using the built-in `ngModel` directive.
 | 
						||
  * The `ngModel` directive also propagates changes to every other binding of the `hero.name`.
 | 
						||
 | 
						||
  <!-- TODO:
 | 
						||
    add [Run the live example for part 1](https://tour-of-heroes.firebaseapp.com/toh1/)
 | 
						||
  -->
 | 
						||
 | 
						||
  Here's the complete `app_component.dart` as it stands now:
 | 
						||
 | 
						||
+makeExample('toh-1/dart/lib/app_component.dart', 'pt1', 'app_component.dart')
 | 
						||
 | 
						||
.l-main-section
 | 
						||
:marked
 | 
						||
  ## The Road Ahead
 | 
						||
  Our Tour of Heroes only displays one hero and we really want to display a list of heroes.
 | 
						||
  We also want to allow the user to select a hero and display their details.
 | 
						||
  We’ll learn more about how to retrieve lists, bind them to the
 | 
						||
  template, and allow a user to select it in the
 | 
						||
  [next tutorial chapter](./toh-pt2.html).
 |