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>.
|
|
|