docs(Displaying Data): copy edits (#2435)
This commit is contained in:
parent
4bb79953be
commit
6c7f330620
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
"displaying-data": {
|
"displaying-data": {
|
||||||
"title": "Displaying Data",
|
"title": "Displaying Data",
|
||||||
"intro": "Interpolation and other forms of property binding help us show app data in the UI.",
|
"intro": "Property binding helps show app data in the UI.",
|
||||||
"nextable": true,
|
"nextable": true,
|
||||||
"basics": true
|
"basics": true
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,13 +2,12 @@ block includes
|
||||||
include ../_util-fns
|
include ../_util-fns
|
||||||
- var _iterableUrl = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols';
|
- var _iterableUrl = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols';
|
||||||
- var _boolean = 'truthy/falsey';
|
- var _boolean = 'truthy/falsey';
|
||||||
|
|
||||||
:marked
|
|
||||||
We typically display data in Angular by binding controls in an HTML template
|
|
||||||
to properties of an Angular component.
|
|
||||||
|
|
||||||
In this chapter, we'll create a component with a list of heroes. Each hero has a name.
|
:marked
|
||||||
We'll display the list of hero names and
|
You can display data by binding controls in an HTML template to properties of an Angular component.
|
||||||
|
|
||||||
|
In this page, you'll create a component with a list of heroes.
|
||||||
|
You'll display the list of hero names and
|
||||||
conditionally show a message below the list.
|
conditionally show a message below the list.
|
||||||
|
|
||||||
The final UI looks like this:
|
The final UI looks like this:
|
||||||
|
@ -17,42 +16,42 @@ figure.image-display
|
||||||
img(src="/resources/images/devguide/displaying-data/final.png" alt="Final UI")
|
img(src="/resources/images/devguide/displaying-data/final.png" alt="Final UI")
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
# Table Of Contents
|
# Contents
|
||||||
|
|
||||||
* [Showing component properties with interpolation](#interpolation)
|
* [Showing component properties with interpolation](#interpolation).
|
||||||
* [Showing !{_an} !{_array} property with NgFor](#ngFor)
|
* [Showing !{_an} !{_array} property with NgFor](#ngFor).
|
||||||
* [Conditional display with NgIf](#ngIf)
|
* [Conditional display with NgIf](#ngIf).
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
The <live-example></live-example> demonstrates all of the syntax and code
|
The <live-example></live-example> demonstrates all of the syntax and code
|
||||||
snippets described in this chapter.
|
snippets described in this page.
|
||||||
|
|
||||||
.l-main-section#interpolation
|
.l-main-section#interpolation
|
||||||
:marked
|
:marked
|
||||||
## Showing component properties with interpolation
|
## Showing component properties with interpolation
|
||||||
The easiest way to display a component property
|
The easiest way to display a component property
|
||||||
is to bind the property name through interpolation.
|
is to bind the property name through interpolation.
|
||||||
With interpolation, we put the property name in the view template, enclosed in double curly braces: `{{myHero}}`.
|
With interpolation, you put the property name in the view template, enclosed in double curly braces: `{{myHero}}`.
|
||||||
|
|
||||||
Let's build a small illustrative example together.
|
To build an illustrative example, start by creating a new project folder called <ngio-ex path="displaying-data"></ngio-ex>
|
||||||
|
and following the steps in [QuickStart](../quickstart.html).
|
||||||
Create a new project folder (<ngio-ex path="displaying-data"></ngio-ex>) and follow the steps in the [QuickStart](../quickstart.html).
|
|
||||||
|
|
||||||
block quickstart-repo
|
block quickstart-repo
|
||||||
include ../_quickstart_repo
|
include ../_quickstart_repo
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Then modify the <ngio-ex path="app.component.ts"></ngio-ex> file by
|
Then modify the <ngio-ex path="app.component.ts"></ngio-ex> file by
|
||||||
changing the template and the body of the component.
|
changing the template and the body of the component.
|
||||||
When we're done, it should look like this:
|
|
||||||
|
When you're done, it should look like this:
|
||||||
|
|
||||||
+makeExample('app/app.component.1.ts')
|
+makeExample('app/app.component.1.ts')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We added two properties to the formerly empty component: `title` and `myHero`.
|
You added two properties to the formerly empty component: `title` and `myHero`.
|
||||||
|
|
||||||
Our revised template displays the two component properties using double curly brace
|
The revised template displays the two component properties using double curly brace
|
||||||
interpolation:
|
interpolation:
|
||||||
|
|
||||||
+makeExcerpt('app/app.component.1.ts', 'template', '')
|
+makeExcerpt('app/app.component.1.ts', 'template', '')
|
||||||
|
@ -61,10 +60,9 @@ block quickstart-repo
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
The template is a multi-line string within ECMAScript 2015 backticks (<code>\`</code>).
|
The template is a multi-line string within ECMAScript 2015 backticks (<code>\`</code>).
|
||||||
The backtick (<code>\`</code>) — which is *not* the same character as a single
|
The backtick (<code>\`</code>)—which is *not* the same character as a single
|
||||||
quote (`'`) — has many nice features. The feature we're exploiting here
|
quote (`'`)—allows you to compose a string over several lines, which makes the
|
||||||
is the ability to compose the string over several lines, which makes for
|
HTML more readable.
|
||||||
much more readable HTML.
|
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Angular automatically pulls the value of the `title` and `myHero` properties from the component and
|
Angular automatically pulls the value of the `title` and `myHero` properties from the component and
|
||||||
|
@ -74,43 +72,42 @@ block quickstart-repo
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
More precisely, the redisplay occurs after some kind of asynchronous event related to
|
More precisely, the redisplay occurs after some kind of asynchronous event related to
|
||||||
the view such as a keystroke, a timer completion, or an async `XHR` response.
|
the view, such as a keystroke, a timer completion, or a response to an HTTP request.
|
||||||
We don't have those in this sample.
|
|
||||||
But then the properties aren't changing on their own either. For the moment we must operate on faith.
|
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Notice that we haven't called **new** to create an instance of the `AppComponent` class.
|
Notice that you don't call **new** to create an instance of the `AppComponent` class.
|
||||||
Angular is creating an instance for us. How?
|
Angular is creating an instance for you. How?
|
||||||
|
|
||||||
Notice the CSS `selector` in the `@Component` !{_decorator} that specifies an element named `my-app`.
|
The CSS `selector` in the `@Component` !{_decorator} specifies an element named `my-app`.
|
||||||
Remember back in [QuickStart](../quickstart.html) that we added the `<my-app>` element to the body of our `index.html` file:
|
Remember back in [QuickStart](../quickstart.html) that you added the `<my-app>`
|
||||||
|
element to the body of your `index.html` file:
|
||||||
|
|
||||||
+makeExcerpt('index.html', 'body')
|
+makeExcerpt('index.html', 'body')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
When we bootstrap with the `AppComponent` class (in <ngio-ex path="main.ts"></ngio-ex>), Angular looks for a `<my-app>`
|
When you bootstrap with the `AppComponent` class (in <ngio-ex path="main.ts"></ngio-ex>), Angular looks for a `<my-app>`
|
||||||
in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it
|
in the `index.html`, finds it, instantiates an instance of `AppComponent`, and renders it
|
||||||
inside the `<my-app>` tag.
|
inside the `<my-app>` tag.
|
||||||
|
|
||||||
Try running the app. It should display the title and hero name:
|
Now run the app. It should display the title and hero name:
|
||||||
figure.image-display
|
figure.image-display
|
||||||
img(src="/resources/images/devguide/displaying-data/title-and-hero.png" alt="Title and Hero")
|
img(src="/resources/images/devguide/displaying-data/title-and-hero.png" alt="Title and Hero")
|
||||||
|
|
||||||
+ifDocsFor('ts')
|
+ifDocsFor('ts')
|
||||||
:marked
|
:marked
|
||||||
Let's review some of the choices we made and consider alternatives.
|
The next few sections review some of the coding choices in the app.
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
## Template inline or template file?
|
## Template inline or template file?
|
||||||
|
|
||||||
We can store our component's template in one of two places.
|
You can store your component's template in one of two places.
|
||||||
We can define it *inline* using the `template` property, as we do here.
|
You can define it *inline* using the `template` property, or you can define
|
||||||
Or we can define the template in a separate HTML file and link to it in
|
the template in a separate HTML file and link to it in
|
||||||
the component metadata using the `@Component` !{_decorator}'s `templateUrl` property.
|
the component metadata using the `@Component` !{_decorator}'s `templateUrl` property.
|
||||||
|
|
||||||
The choice between inline and separate HTML is a matter of taste,
|
The choice between inline and separate HTML is a matter of taste,
|
||||||
circumstances, and organization policy.
|
circumstances, and organization policy.
|
||||||
Here we're using inline HTML because the template is small, and the demo
|
Here the app uses inline HTML because the template is small and the demo
|
||||||
is simpler without the additional HTML file.
|
is simpler without the additional HTML file.
|
||||||
|
|
||||||
In either style, the template data bindings have the same access to the component's properties.
|
In either style, the template data bindings have the same access to the component's properties.
|
||||||
|
@ -119,49 +116,44 @@ figure.image-display
|
||||||
:marked
|
:marked
|
||||||
## Constructor or variable initialization?
|
## Constructor or variable initialization?
|
||||||
|
|
||||||
We initialized our component properties using variable assignment.
|
Although this example uses variable assignment to initialize the components, you can instead declare and initialize the properties using a constructor:
|
||||||
This is a wonderfully concise and compact technique.
|
|
||||||
|
|
||||||
Some folks prefer to declare the properties and initialize them within a constructor like this:
|
|
||||||
+makeExcerpt('app/app-ctor.component.ts', 'class')
|
+makeExcerpt('app/app-ctor.component.ts', 'class')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
That's fine too. The choice is a matter of taste and organization policy.
|
This app uses more terse "variable assignment" style simply for brevity.
|
||||||
We'll adopt the more terse "variable assignment" style in this chapter simply because
|
|
||||||
there will be less code to read.
|
|
||||||
|
|
||||||
.l-main-section#ngFor
|
.l-main-section#ngFor
|
||||||
:marked
|
:marked
|
||||||
## Showing !{_an} !{_array} property with ***ngFor**
|
## Showing !{_an} !{_array} property with ***ngFor**
|
||||||
|
|
||||||
We want to display a list of heroes. We begin by adding !{_an} !{_array} of hero names to the component and redefine `myHero` to be the first name in the !{_array}.
|
To display a list of heroes, begin by adding !{_an} !{_array} of hero names to the component and redefine `myHero` to be the first name in the !{_array}.
|
||||||
|
|
||||||
+makeExcerpt('app/app.component.2.ts', 'class')
|
+makeExcerpt('app/app.component.2.ts', 'class')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Now we use the Angular `ngFor` directive in the template to display
|
Now use the Angular `ngFor` directive in the template to display
|
||||||
each item in the `heroes` list.
|
each item in the `heroes` list.
|
||||||
|
|
||||||
+makeExcerpt('app/app.component.2.ts', 'template')
|
+makeExcerpt('app/app.component.2.ts', 'template')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Our presentation is the familiar HTML unordered list with `<ul>` and `<li>` tags. Let's focus on the `<li>` tag.
|
This UI uses the HTML unordered list with `<ul>` and `<li>` tags. The `*ngFor`
|
||||||
|
in the `<li>` element is the Angular "repeater" directive.
|
||||||
|
It marks that `<li>` element (and its children) as the "repeater template":
|
||||||
|
|
||||||
+makeExcerpt('app/app.component.2.ts ()', 'li', '')
|
+makeExcerpt('app/app.component.2.ts ()', 'li', '')
|
||||||
|
|
||||||
:marked
|
|
||||||
We added a somewhat mysterious `*ngFor` to the `<li>` element.
|
|
||||||
That's the Angular "repeater" directive.
|
|
||||||
Its presence on the `<li>` tag marks that `<li>` element (and its children) as the "repeater template".
|
|
||||||
|
|
||||||
.alert.is-important
|
.alert.is-important
|
||||||
:marked
|
:marked
|
||||||
Don't forget the leading asterisk (\*) in `*ngFor`. It is an essential part of the syntax.
|
Don't forget the leading asterisk (\*) in `*ngFor`. It is an essential part of the syntax.
|
||||||
Learn more about this and `ngFor` in the [Template Syntax](./template-syntax.html#ngFor) chapter.
|
For more information, see the [Template Syntax](./template-syntax.html#ngFor) page.
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Notice the `hero` in the `ngFor` double-quoted instruction;
|
Notice the `hero` in the `ngFor` double-quoted instruction;
|
||||||
it is an example of a [template input variable](./template-syntax.html#ngForMicrosyntax).
|
it is an example of a template input variable. Read
|
||||||
|
more about template input variables in the [microsyntax](./template-syntax.html#ngForMicrosyntax) section of
|
||||||
|
the [Template Syntax](./template-syntax.html) page.
|
||||||
|
|
||||||
Angular duplicates the `<li>` for each item in the list, setting the `hero` variable
|
Angular duplicates the `<li>` for each item in the list, setting the `hero` variable
|
||||||
to the item (the hero) in the current iteration. Angular uses that variable as the
|
to the item (the hero) in the current iteration. Angular uses that variable as the
|
||||||
|
@ -169,9 +161,8 @@ figure.image-display
|
||||||
|
|
||||||
.l-sub-section
|
.l-sub-section
|
||||||
:marked
|
:marked
|
||||||
We happened to give `ngFor` !{_an} !{_array} to display.
|
In this case, `ngFor` is displaying !{_an} !{_array}, but `ngFor` can
|
||||||
In fact, `ngFor` can repeat items for any [iterable](!{_iterableUrl})
|
repeat items for any [iterable](!{_iterableUrl}) object.
|
||||||
object.
|
|
||||||
:marked
|
:marked
|
||||||
Now the heroes appear in an unordered list.
|
Now the heroes appear in an unordered list.
|
||||||
|
|
||||||
|
@ -182,25 +173,25 @@ figure.image-display
|
||||||
:marked
|
:marked
|
||||||
## Creating a class for the data
|
## Creating a class for the data
|
||||||
|
|
||||||
We are defining our data directly inside our component.
|
The app's code defines the data directly inside the component, which isn't best practice.
|
||||||
That's fine for a demo but certainly isn't a best practice. It's not even a good practice.
|
In a simple demo, however, it's fine.
|
||||||
Although we won't do anything about that in this chapter, we'll make a mental note to fix this down the road.
|
|
||||||
|
|
||||||
At the moment, we're binding to !{_an} !{_array} of strings. We do that occasionally in real applications, but
|
At the moment, the binding is to !{_an} !{_array} of strings.
|
||||||
most of the time we're binding to more specialized objects.
|
In real applications, most bindings are to more specialized objects.
|
||||||
|
|
||||||
Let's turn our !{_array} of hero names into !{_an} !{_array} of `Hero` objects. For that we'll need a `Hero` class.
|
To convert this binding to use specialized objects, turn the !{_array}
|
||||||
|
of hero names into !{_an} !{_array} of `Hero` objects. For that you'll need a `Hero` class.
|
||||||
|
|
||||||
Create a new file in the `!{_appDir}` folder called <ngio-ex path="hero.ts"></ngio-ex> with the following code:
|
Create a new file in the `!{_appDir}` folder called <ngio-ex path="hero.ts"></ngio-ex> with the following code:
|
||||||
|
|
||||||
+makeExcerpt('app/hero.ts')
|
+makeExcerpt('app/hero.ts')
|
||||||
|
|
||||||
block hero-class
|
block hero-class
|
||||||
:marked
|
:marked
|
||||||
We've defined a class with a constructor and two properties: `id` and `name`.
|
You've defined a class with a constructor and two properties: `id` and `name`.
|
||||||
|
|
||||||
It might not look like we have properties, but we do. We're taking
|
It might not look like the class has properties, but it does.
|
||||||
advantage of a TypeScript shortcut in our declaration of the constructor parameters.
|
The declaration of the constructor parameters takes advantage of a TypeScript shortcut.
|
||||||
|
|
||||||
Consider the first parameter:
|
Consider the first parameter:
|
||||||
|
|
||||||
|
@ -208,26 +199,28 @@ block hero-class
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
That brief syntax does a lot:
|
That brief syntax does a lot:
|
||||||
* Declares a constructor parameter and its type
|
* Declares a constructor parameter and its type.
|
||||||
* Declares a public property of the same name
|
* Declares a public property of the same name.
|
||||||
* Initializes that property with the corresponding argument when we "new" an instance of the class
|
* Initializes that property with the corresponding argument when creating an instance of the class.
|
||||||
|
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Using the Hero class
|
## Using the Hero class
|
||||||
Let's make the `heroes` property in our component return !{_an} !{_array} of these `Hero` objects.
|
|
||||||
|
The `heroes` property in the component can now use the `Hero` class to return !{_an} !{_array}
|
||||||
|
of `Hero` objects:
|
||||||
|
|
||||||
+makeExcerpt('app/app.component.3.ts', 'heroes')
|
+makeExcerpt('app/app.component.3.ts', 'heroes')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
We'll have to update the template.
|
Next, update the template.
|
||||||
At the moment it displays the hero's `id` and `name`.
|
At the moment it displays the hero's `id` and `name`.
|
||||||
Let's fix that so we display only the hero's `name` property.
|
Fix that to display only the hero's `name` property.
|
||||||
|
|
||||||
+makeExcerpt('app/app.component.3.ts', 'template')
|
+makeExcerpt('app/app.component.3.ts', 'template')
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Our display looks the same, but now we know much better what a hero really is.
|
The display looks the same, but the code is clearer.
|
||||||
|
|
||||||
.l-main-section#ngIf
|
.l-main-section#ngIf
|
||||||
:marked
|
:marked
|
||||||
|
@ -235,29 +228,31 @@ block hero-class
|
||||||
|
|
||||||
Sometimes an app needs to display a view or a portion of a view only under specific circumstances.
|
Sometimes an app needs to display a view or a portion of a view only under specific circumstances.
|
||||||
|
|
||||||
In our example, we'd like to display a message if we have a large number of heroes, say, more than 3.
|
Let's change the example to display a message if there are more than three heroes.
|
||||||
|
|
||||||
The Angular `ngIf` directive inserts or removes an element based on a !{_boolean} condition.
|
The Angular `ngIf` directive inserts or removes an element based on a !{_boolean} condition.
|
||||||
We can see it in action by adding the following paragraph at the bottom of the template:
|
To see it in action, add the following paragraph at the bottom of the template:
|
||||||
|
|
||||||
+makeExcerpt('app/app.component.ts', 'message')
|
+makeExcerpt('app/app.component.ts', 'message')
|
||||||
|
|
||||||
.alert.is-important
|
.alert.is-important
|
||||||
:marked
|
:marked
|
||||||
Don't forget the leading asterisk (\*) in `*ngIf`. It is an essential part of the syntax.
|
Don't forget the leading asterisk (\*) in `*ngIf`. It is an essential part of the syntax.
|
||||||
Learn more about this and `ngIf` in the [Template Syntax](./template-syntax.html#ngIf) chapter.
|
Read more about `ngIf` and `*` in the [ngIf section](./template-syntax.html#ngIf) of the [Template Syntax](./template-syntax.html) page.
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
The [template expression](./template-syntax.html#template-expressions) inside the double quotes
|
The template expression inside the double quotes,
|
||||||
looks much like !{_Lang}, and it _is_ much like !{_Lang}.
|
`*ngIf="heros.length > 3"`, looks and behaves much like !{_Lang}.
|
||||||
When the component's list of heroes has more than 3 items, Angular adds the paragraph to the DOM and the message appears.
|
When the component's list of heroes has more than three items, Angular adds the paragraph
|
||||||
If there are 3 or fewer items, Angular omits the paragraph, so no message appears.
|
to the DOM and the message appears. If there are three or fewer items, Angular omits the
|
||||||
|
paragraph, so no message appears. For more information,
|
||||||
|
see the [template expressions](./template-syntax.html#template-expressions) section of the
|
||||||
|
[Template Syntax](./template-syntax.html) page.
|
||||||
|
|
||||||
.alert.is-helpful
|
.alert.is-helpful
|
||||||
:marked
|
:marked
|
||||||
Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM.
|
Angular isn't showing and hiding the message. It is adding and removing the paragraph element from the DOM. That improves performance, especially in larger projects when conditionally including or excluding
|
||||||
That hardly matters here. But it would matter a great deal, from a performance perspective, if
|
big chunks of HTML with many data bindings.
|
||||||
we were conditionally including or excluding a big chunk of HTML with many data bindings.
|
|
||||||
|
|
||||||
:marked
|
:marked
|
||||||
Try it out. Because the !{_array} has four items, the message should appear.
|
Try it out. Because the !{_array} has four items, the message should appear.
|
||||||
|
@ -267,13 +262,13 @@ block hero-class
|
||||||
.l-main-section
|
.l-main-section
|
||||||
:marked
|
:marked
|
||||||
## Summary
|
## Summary
|
||||||
Now we know how to use:
|
Now you know how to use:
|
||||||
- **Interpolation** with double curly braces to display a component property
|
- **Interpolation** with double curly braces to display a component property.
|
||||||
- **ngFor** to display !{_an} !{_array} of items
|
- **ngFor** to display !{_an} !{_array} of items.
|
||||||
- A !{_Lang} class to shape the **model data** for our component and display properties of that model
|
- A !{_Lang} class to shape the **model data** for your component and display properties of that model.
|
||||||
- **ngIf** to conditionally display a chunk of HTML based on a boolean expression
|
- **ngIf** to conditionally display a chunk of HTML based on a boolean expression.
|
||||||
|
|
||||||
Here's our final code:
|
Here's the final code:
|
||||||
|
|
||||||
block final-code
|
block final-code
|
||||||
+makeTabs(`displaying-data/ts/app/app.component.ts,
|
+makeTabs(`displaying-data/ts/app/app.component.ts,
|
||||||
|
@ -281,4 +276,4 @@ block final-code
|
||||||
displaying-data/ts/app/app.module.ts,
|
displaying-data/ts/app/app.module.ts,
|
||||||
displaying-data/ts/app/main.ts`,
|
displaying-data/ts/app/main.ts`,
|
||||||
'final,,,',
|
'final,,,',
|
||||||
'app/app.component.ts, app/hero.ts, app.module.ts, main.ts')
|
'app/app.component.ts, app/hero.ts, app.module.ts, main.ts')
|
Loading…
Reference in New Issue