470 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			470 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| .l-main-section
 | |
|   p.
 | |
|       Let's walk through how to display a property and a list of properties,
 | |
|       and then to conditionally show content
 | |
|       based on state. The final UI looks like this:
 | |
| 
 | |
|   figure.image-display
 | |
|     img(src='/resources/images/examples/displaying-data-example1.png' alt="Example of Todo App")
 | |
| 
 | |
| .l-main-section
 | |
|   h2#section-create-an-entry-point Create entry points and pubspec
 | |
| 
 | |
|   p.
 | |
|     Open your favorite editor and create a directory with
 | |
|     a <code>web/main.dart</code> file,
 | |
|     a <code>web/index.html</code> file, and
 | |
|     a <code>pubspec.yaml</code> file:
 | |
| 
 | |
|   code-tabs
 | |
|     code-pane(language="dart" name="web/main.dart" format="linenums").
 | |
|       import 'package:angular2/bootstrap.dart';
 | |
|       import 'package:displaying_data/show_properties.dart';
 | |
| 
 | |
|       main() {
 | |
|         bootstrap(DisplayComponent);
 | |
|       }
 | |
|     code-pane(language="html" name="web/index.html" format="linenums").
 | |
|       <!DOCTYPE html>
 | |
|       <html>
 | |
|         <head>
 | |
|           <title>Displaying Data</title>
 | |
|           <link rel="stylesheet" href="style.css">
 | |
|           <script async src="main.dart" type="application/dart"></script>
 | |
|           <script async src="packages/browser/dart.js"></script>
 | |
|         </head>
 | |
|         <body>
 | |
|           <display></display>
 | |
|         </body>
 | |
|       </html>
 | |
|     code-pane(language="yaml" name="pubspec.yaml" format="linenums").
 | |
|       name: displaying_data
 | |
|       description: Dart version of Angular 2 example, Displaying Data
 | |
|       version: 0.0.1
 | |
|       dependencies:
 | |
|         angular2: 2.0.0-alpha.39
 | |
|         browser: ^0.10.0
 | |
|       transformers:
 | |
|       - angular2:
 | |
|           entry_points: web/main.dart
 | |
|   p.
 | |
|    All of this code should look familiar from the previous page,
 | |
|    except for the imports in <code>main.dart</code>.
 | |
|    The import of <code>show_properties.dart</code>
 | |
|    lets you implement part of the app in a different Dart file.
 | |
|    You've previously seen <code>angular2.dart</code> imported,
 | |
|    but that's unnecessary here because this version of <code>main.dart</code>
 | |
|    doesn't implement any components or other injectable types.
 | |
| 
 | |
|   p.
 | |
|    All three of these files remain similar in the rest of the examples,
 | |
|    so we'll focus on what changes.
 | |
| 
 | |
| .l-main-section
 | |
|   h2#section-showing-properties-with-interpolation Showing properties with interpolation
 | |
|   p.
 | |
|     The simple method for binding text into templates is through interpolation,
 | |
|     where you put the name of a property
 | |
|     inside <strong ng-non-bindable="">{{ }}</strong>.
 | |
| 
 | |
|   p.
 | |
|     To see this working, first create a <code>lib</code> directory.
 | |
|     Under it, put a Dart file named <code>show_properties.dart</code>
 | |
|     that contains the following code:
 | |
| 
 | |
|   code-example(language="dart" format="linenums" escape="html").
 | |
|     // lib/show_properties.dart
 | |
|     library displaying_data.show_properties;
 | |
| 
 | |
|     import 'package:angular2/angular2.dart';
 | |
| 
 | |
|     @Component(selector: 'display')
 | |
|     @View(template: '''
 | |
|     <p>My name: {{ myName }}</p>
 | |
|     ''')
 | |
|     class DisplayComponent {
 | |
|       String myName = 'Alice';
 | |
|     }
 | |
| 
 | |
|   p.
 | |
|     You've just defined a component that encompasses a view and controller for the app. The view
 | |
|     defines a template:
 | |
| 
 | |
|   code-example(language="html" escape="html").
 | |
|     <p>My name: {{ myName }}</p>
 | |
| 
 | |
|   p.
 | |
|    Angular will automatically pull the value of <code>myName</code> and
 | |
|    insert it into the browser,
 | |
|    automatically updating it whenever it changes.
 | |
| 
 | |
|   .callout.is-helpful
 | |
|     header Note
 | |
|     p.
 | |
|       While you've used <code>template:</code> to specify an inline view, for larger templates you'd
 | |
|       want to move them to a separate file and load them with <code>templateUrl:</code> instead.
 | |
| 
 | |
|   p.
 | |
|    One thing to notice is that although you've written
 | |
|    your <code>DisplayComponent</code> class, you haven't
 | |
|    used <code>new</code> to instantiate it.
 | |
|    Because your class is associated with <code><display></code> elements in
 | |
|    the DOM, Angular automatically calls <code>new</code> on
 | |
|    <code>DisplayComponent</code> and bind its properties to
 | |
|    that part of the template.
 | |
| 
 | |
|   p.
 | |
|    When you're building templates, data bindings like these have access to
 | |
|    the same scope of
 | |
|    properties as your controller class does.
 | |
|    Here your class is <code>DisplayComponent</code>, which has
 | |
|    just one property, <code>myName</code>.
 | |
| 
 | |
|   p.
 | |
|     Add a second line to the template,
 | |
|     so you can see Angular dynamically update content:
 | |
| 
 | |
|   code-example(language="html").
 | |
|     <p>Current time: {{ time }}</p>
 | |
| 
 | |
|   p.
 | |
|     Then import <code>dart:async</code> so you can use a Timer,
 | |
|     and give the <code>DisplayComponent</code> a starting value for time and
 | |
|     create a periodic Timer call to update the time:
 | |
| 
 | |
|   code-example(language="dart").
 | |
|     import 'dart:async';
 | |
|     ...
 | |
|     class DisplayComponent {
 | |
|       String myName = 'Alice';
 | |
|       String time;
 | |
|       Timer _timer;
 | |
| 
 | |
|       DisplayComponent() {
 | |
|         _updateTime(null);
 | |
|         _timer = new Timer.periodic(new Duration(seconds: 1), _updateTime);
 | |
|       }
 | |
| 
 | |
|       _updateTime(Timer _) {
 | |
|         time = new DateTime.now().toString();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   p Reload the app, and you'll now see the seconds updating automatically.
 | |
| 
 | |
| .l-main-section
 | |
|   h2#Create-an-array Display an iterable using *ng-for
 | |
|   p Moving up from a single value, create a property that's a list of values.
 | |
| 
 | |
|   code-example(language="dart").
 | |
|     class DisplayComponent {
 | |
|       String myName = 'Alice';
 | |
|       List<String> friendNames = const [
 | |
|         'Aarav',
 | |
|         'Martín',
 | |
|         'Shannon',
 | |
|         'Ariana',
 | |
|         'Kai'
 | |
|       ];
 | |
|     }
 | |
| 
 | |
|   p.
 | |
|     You can then use this list in your template with
 | |
|     the <code>ng-for</code> directive to create copies of DOM elements
 | |
|     with one for each item in the list.
 | |
| 
 | |
|   code-example(language="dart").
 | |
|     @View(template: '''
 | |
|     <p>My name: {{ myName }}</p>
 | |
|     <p>Friends:</p>
 | |
|     <ul>
 | |
|        <li <span class="pnk">*ng-for="#name of friendNames"</span>>
 | |
|           {{ name }}
 | |
|        </li>
 | |
|     </ul>
 | |
|     ''', <span class="pnk">directives: const [NgFor]</span>)
 | |
| 
 | |
|   p.
 | |
|     To make <code>ng-for</code> work,
 | |
|     you need to add the Angular <code>NgFor</code> directive,
 | |
|     so that Angular knows to include it.
 | |
|     Add <code>NgFor</code> using the optional <code>directives</code> parameter.
 | |
| 
 | |
|   p Reload and you've got your list of friends!
 | |
|   p.
 | |
|     Again, Angular will mirror changes you make to this list over in the DOM.
 | |
|     Add a new item and it appears in your list.
 | |
|     Delete one and Angular deletes the <li>.
 | |
|     Reorder items and Angular makes the corresponding reorder of the DOM list.
 | |
| 
 | |
|   p Let's look at the few lines that do the work again:
 | |
| 
 | |
|   code-example(language="html").
 | |
|     <li *ng-for="#name of friendNames">
 | |
|        {{ name }}
 | |
|     </li>
 | |
| 
 | |
|   p The way to read this is:
 | |
|   ul
 | |
|     li.
 | |
|       <code>*ng-for</code>: Create a DOM element for each item in an
 | |
|       <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols">iterable</a>
 | |
|        such as a list.
 | |
|     li <code>#name</code>: Refer to individual values of the iterable as <code>name</code>.
 | |
|     li <code>of friendNames</code>: The iterable to use is called <code>friendNames</code> in the current controller.
 | |
| 
 | |
|   p Using this syntax, you can build UI lists from any iterable object.
 | |
| 
 | |
| .l-main-section
 | |
|   h2#Create-a-class Create a model and inject it
 | |
|   p.
 | |
|     Before we get too much further, we should mention that
 | |
|     putting the model (list) directly into the controller isn't proper form.
 | |
|     We should separate the concerns by having another class
 | |
|     serve the role of model and inject it into the controller.
 | |
| 
 | |
|   p.
 | |
|     Make a <code>FriendsService</code> class to implement a model
 | |
|     containing a list of friends.
 | |
|     Put this in a new file under <code>lib/</code>
 | |
|     named <code>friends_service.dart</code>. Here's what the class looks like:
 | |
| 
 | |
|   code-example(language="dart" format="linenums").
 | |
|     // lib/friends_service.dart
 | |
|     library displaying_data.friends_service;
 | |
| 
 | |
|     import 'package:angular2/angular2.dart';
 | |
| 
 | |
|     @Injectable()
 | |
|     class FriendsService {
 | |
|       List<String> names = ['Aarav', 'Martín', 'Shannon', 'Ariana', 'Kai'];
 | |
|     }
 | |
| 
 | |
|   p.
 | |
|     Now you can replace the current list of friends in DisplayComponent.
 | |
|     Import <code>friends_service.dart</code>,
 | |
|     and add a FriendsService parameter to the constructor.
 | |
|     Then set <code>friendNames</code> to the names provided by the service.
 | |
| 
 | |
|   code-example(language="dart").
 | |
|     // In lib/show_properties.dart
 | |
|     ...
 | |
|     <span class="pnk">import 'package:displaying_data/friends_service.dart';</span>
 | |
|     ...
 | |
|     class DisplayComponent {
 | |
|       String myName = 'Alice';
 | |
|       List<String> friendNames;
 | |
| 
 | |
|       DisplayComponent(<span class="pnk">FriendsService friendsService</span>) {
 | |
|         <span class="pnk">friendNames = friendsService.names;</span>
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   p.
 | |
|     Next, make FriendsService available to dependency injection
 | |
|     by adding a <code>viewBindings</code> parameter to DisplayComponent's
 | |
|     <code>@Component</code> annotation:
 | |
| 
 | |
|   code-example(language="dart").
 | |
|     @Component(selector: 'display', <span class="pnk">viewBindings: const [FriendsService]</span>)
 | |
| 
 | |
| .l-main-section
 | |
|   h2#Conditionally-displaying-data-with-NgIf Conditionally display data using *ng-if
 | |
|   p.
 | |
|     Lastly, before we move on, let's handle showing parts of our UI conditionally with <code>*ng-if</code>.  The
 | |
|     <code>NgIf</code> directive adds or removes elements from the DOM based on the expression you provide.
 | |
| 
 | |
|   p See it in action by adding a paragraph at the end of your template:
 | |
| 
 | |
|   code-example(language="html").
 | |
|     <p *ng-if="friendNames.length > 3">You have many friends!</p>
 | |
| 
 | |
|   p.
 | |
|     Also add <code>NgIf</code> to the list of directives,
 | |
|     so Angular knows to include it:
 | |
| 
 | |
|   code-example(language="dart").
 | |
|     directives: const[NgFor, <span class="pnk">NgIf</span>]
 | |
|   p.
 | |
|     The list currently has 5 items, so if you run the app you'll see the message
 | |
|     congratulating you on your many friends.
 | |
|     Remove two items from the list, reload your browser,
 | |
|     and see that the message no longer displays.
 | |
| 
 | |
|   p Here's the final code.
 | |
| 
 | |
|   code-tabs
 | |
|     code-pane(language="dart" name="lib/show_properties.dart" format="linenums").
 | |
|       library displaying_data.show_properties;
 | |
| 
 | |
|       import 'package:angular2/angular2.dart';
 | |
|       import 'package:displaying_data/friends_service.dart';
 | |
| 
 | |
|       @Component(selector: 'display', viewBindings: const [FriendsService])
 | |
|       @View(template: '''
 | |
|       <p>My name: {{ myName }}</p>
 | |
|       <p>Friends:</p>
 | |
|       <ul>
 | |
|          <li *ng-for="#name of friendNames">
 | |
|             {{ name }}
 | |
|          </li>
 | |
|       </ul>
 | |
|       <p *ng-if="friendNames.length > 3">You have many friends!</p>
 | |
|       ''', directives: const [NgFor, NgIf])
 | |
|       class DisplayComponent {
 | |
|         String myName = 'Alice';
 | |
|         List<String> friendNames;
 | |
| 
 | |
|         DisplayComponent(FriendsService friendsService) {
 | |
|           friendNames = friendsService.names;
 | |
|         }
 | |
|       }
 | |
|     code-pane(language="dart" name="lib/friends_service.dart" format="linenums").
 | |
|       library displaying_data.friends_service;
 | |
| 
 | |
|       import 'package:angular2/angular2.dart';
 | |
| 
 | |
|       @Injectable()
 | |
|       class FriendsService {
 | |
|         List<String> names = ['Aarav', 'Martín', 'Shannon', 'Ariana', 'Kai'];
 | |
|       }
 | |
|     code-pane(language="dart" name="web/main.dart" format="linenums").
 | |
|       import 'package:angular2/bootstrap.dart';
 | |
|       import 'package:displaying_data/show_properties.dart';
 | |
| 
 | |
|       main() {
 | |
|         bootstrap(DisplayComponent);
 | |
|       }
 | |
|     code-pane(language="html" name="web/index.html" format="linenums").
 | |
|       <!DOCTYPE html>
 | |
|       <html>
 | |
|         <head>
 | |
|           <title>Displaying Data</title>
 | |
|           <link rel="stylesheet" href="style.css">
 | |
|           <script async src="main.dart" type="application/dart"></script>
 | |
|           <script async src="packages/browser/dart.js"></script>
 | |
|         </head>
 | |
|         <body>
 | |
|           <display></display>
 | |
|         </body>
 | |
|       </html>
 | |
|     code-pane(language="yaml" name="pubspec.yaml" format="linenums").
 | |
|       name: displaying_data
 | |
|       description: Displaying Data example
 | |
|       version: 0.0.1
 | |
|       dependencies:
 | |
|         angular2: 2.0.0-alpha.39
 | |
|         browser: ^0.10.0
 | |
|       transformers:
 | |
|       - angular2:
 | |
|           entry_points: web/main.dart
 | |
| .l-main-section
 | |
|   h2#section-explanations Explanations
 | |
| 
 | |
|   .l-sub-section
 | |
|     h3 Using multiple Dart files in an Angular app
 | |
| 
 | |
|     p.
 | |
|       Dart offers a few ways to implement an app in multiple files.
 | |
|       In this guide, each example is in a single package,
 | |
|       and each Dart file implements a separate library.
 | |
|       For a bigger project, you might split the code into libraries
 | |
|       in two or more packages.
 | |
| 
 | |
|     p.
 | |
|       To use the API defined in <code>show_properties.dart</code>,
 | |
|       <code>main.dart</code> must import that file.
 | |
|       The import statement uses the package name
 | |
|       (defined in <code>pubspec.yaml</code> to be <b>displaying_data</b>)
 | |
|       and the path to <code>show_properties.dart</code>
 | |
|       (starting at the app's top directory,
 | |
|       but omitting the <code>lib/</code> directory).
 | |
| 
 | |
|     code-example(language="dart").
 | |
|       // In web/main.dart:
 | |
|       ...
 | |
|       import 'package:displaying_data/show_properties.dart';
 | |
|       ...
 | |
| 
 | |
|       // In lib/show_properties.dart:
 | |
|       library displaying_data.show_properties;
 | |
|       ...
 | |
| 
 | |
|     p.
 | |
|       The name that <code>show_properties.dart</code> specifies for its library
 | |
|       is similar to the path used to import the library,
 | |
|       but with no ".dart" suffix and
 | |
|       with dots (<code>.</code>) instead of slashes (<code>/</code>).
 | |
|       <a href="https://www.dartlang.org/articles/style-guide/#do-name-libraries-and-source-files-using-lowercasewithunderscores">Naming
 | |
|       conventions for libraries</a>,
 | |
|       along with lots of other helpful information, are in the
 | |
|       <a href="https://www.dartlang.org/articles/style-guide/">Dart Style Guide</a>.
 | |
| 
 | |
|     p.
 | |
|       Another import lets <code>show_properties.dart</code>
 | |
|       use the API defined in <code>friends_service.dart</code>:
 | |
| 
 | |
|     code-example(language="dart").
 | |
|       // In lib/show_properties.dart:
 | |
|       library displaying_data.show_properties;
 | |
|       ...
 | |
|       import 'package:displaying_data/friends_service.dart';
 | |
|       ...
 | |
| 
 | |
|       // In lib/friends_service.dart:
 | |
|       library displaying_data.friends_service;
 | |
|       ...
 | |
| 
 | |
|     p.
 | |
|       Because both <code>show_properties.dart</code> and <code>friends_service.dart</code>
 | |
|       are under <code>lib</code>,
 | |
|       the import could instead use a relative path:
 | |
| 
 | |
|     code-example(language="dart").
 | |
|       // In lib/show_properties.dart:
 | |
|       library displaying_data.show_properties;
 | |
|       ...
 | |
|       import 'friends_service.dart';
 | |
|       ...
 | |
| 
 | |
|       // In lib/friends_service.dart:
 | |
|       library displaying_data.friends_service;
 | |
|       ...
 | |
| 
 | |
|     p.
 | |
|       The app's entry point—<code>main.dart</code>—imports
 | |
|       <code>bootstrap.dart</code> so that it can call <code>bootstrap()</code>.
 | |
|       Both <code>show_properties.dart</code> and <code>friends_service.dart</code>
 | |
|       import <code>angular2.dart</code>
 | |
|       so that they can define Angular components and models.
 | |
| 
 | |
|     code-example(language="dart").
 | |
|       // In web/main.dart:
 | |
|       import 'package:angular2/bootstrap.dart';
 | |
|       ...
 | |
|       bootstrap(...)
 | |
|       ...
 | |
| 
 | |
|       // In lib/show_properties.dart:
 | |
|       ...
 | |
|       import 'package:angular2/angular2.dart';
 | |
|       ...
 | |
|       @Component(...)
 | |
|       @View(...)
 | |
|       ...
 | |
| 
 | |
|       // In lib/friends_service.dart:
 | |
|       ...
 | |
|       import 'package:angular2/angular2.dart';
 | |
|       ...
 | |
|       @Injectable()
 | |
|       ...
 | |
| 
 | |
| 
 | |
|     p.
 | |
|       For more information on implementing Dart libraries, see
 | |
|       <a href="https://www.dartlang.org/docs/dart-up-and-running/ch02.html#libraries-and-visibility">Libraries and visibility</a>
 | |
|       in the
 | |
|       <a href="https://www.dartlang.org/docs/dart-up-and-running/ch02.html">Dart language tour</a>.
 | |
| 
 |