change from "template: '{{ myName }} <ul> <li *for="#name of names"<{{ name }}>/li< >/ul<',"
to "template: '{{ myName }} <ul> <li *for="#name of names">{{ name }}</li> </ul>',"
		
	
			
		
			
				
	
	
		
			351 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			351 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| .statement
 | |
|   h4 Live Examples
 | |
|   p.
 | |
|     If you want to skip to the working examples you can check out these links on Plunker. <a href='http://plnkr.co/edit/pQojSb3CTfTEejX0wGjO?p=preview')> TypeScript Example</a> or <a href='http://plnkr.co/edit/GOJiWOEem9jrOyEeY3uW?p=preview'> ES5 Example</a>.
 | |
| 
 | |
| .l-main-section
 | |
| 
 | |
|   h2#section-displaying-controller-properties Displaying controller properties
 | |
| 
 | |
| 
 | |
|   p.
 | |
|     Let's walk through how we'd display a property, a list of properties, and then conditionally show content
 | |
|     based on state. We'll end up with a UI that looks like this:
 | |
| 
 | |
|   figure.image-display
 | |
|     img(src='displaying-data-example1.png')
 | |
| 
 | |
| .l-main-section
 | |
|     h2#section-create-an-entry-point Create an entry point
 | |
| 
 | |
|     p Open your favorite editor and create a show-properties.html file with the content:
 | |
|     pre.prettyprint.linenums.lang-html
 | |
|       code.
 | |
|          <display></display>
 | |
|     p
 | |
|      | The <code><display></code> component here acts as the site where you'll insert your application.
 | |
|      | We'll assume a structure like this for the rest of the examples here and just focus on the parts that
 | |
|      | are different.
 | |
| 
 | |
| .l-main-section
 | |
|     h2#section-showing-properties-with-interpolation Showing properties with interpolation
 | |
|     p.text-body
 | |
|      | The simple method for binding text into templates is through interpolation where you put the name of a property
 | |
|      | inside <strong>{{ }}</strong>.
 | |
| 
 | |
|     p To see this working, create another file, <code>show-properties.js</code>, and add the following:
 | |
| 
 | |
|     .code-box
 | |
|       pre.prettyprint.linenums.lang-javascript(data-name="es5")
 | |
|           code.
 | |
|             // ES5
 | |
|             function DisplayComponent() {
 | |
|               this.myName = "Alice";
 | |
|             }
 | |
|             DisplayComponent.annotations = [
 | |
|               new angular.Component({
 | |
|                 selector: "display"
 | |
|               }),
 | |
|               new angular.View({
 | |
|                 template:
 | |
|                    '<p>My name: {{ myName }}</p>',
 | |
|                 directives: [angular.For, angular.If]
 | |
|               })
 | |
|             ];
 | |
| 
 | |
|       pre.prettyprint.linenums.lang-typescript(data-name="typescript")
 | |
|           code.
 | |
|               // TypeScript
 | |
|               import {Component, View, bootstrap, For} from 'angular2/angular2';
 | |
| 
 | |
|               @Component({
 | |
|                selector: 'display'
 | |
|               })
 | |
|               @View({
 | |
|                 template: `
 | |
|                  <p>My name: {{ myName }}</p>
 | |
|                `,
 | |
|                directives: [For]
 | |
|               })
 | |
|               class DisplayComponent {
 | |
|                myName: string;
 | |
|                todos: Array<string>;
 | |
| 
 | |
|                constructor() {
 | |
|                  this.myName = "Alice";
 | |
|                }
 | |
|               }
 | |
|     p.
 | |
|      You've just defined a component that encompases a view and controller for the app. The view
 | |
|      defines a template:
 | |
|     pre.prettyprint.lang-html
 | |
|      code.
 | |
|        <p>My name: {{ myName }}</p>
 | |
| 
 | |
|     p.
 | |
|      Angular will automatically pull the value of <code>myName</code> and insert it into the browser and
 | |
|      update it whenever it changes without work on your part.
 | |
| 
 | |
|     p.
 | |
|      One thing to notice here is that though you've written your <code>DisplayComponent</code> class, you haven't
 | |
|      called new to create one anywhere.  By associating your class with elements named 'display' in
 | |
|      the DOM, Angular knows to automatically call new 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 the <code>DisplayComponent</code> that has
 | |
|      just one property, myName.
 | |
| 
 | |
|     .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 So you can see Angular dynamically update content, add a line after
 | |
| 
 | |
|         pre.prettyprint.lang-html
 | |
|             code.
 | |
|                 <p>My name: {{ myName }}</p>
 | |
|     p to this:
 | |
|         pre.prettyprint.lang-html
 | |
|             code.
 | |
|                 <p>Current time: {{ time }}</p>
 | |
|     p.
 | |
|         Then give the <code>DisplayComponent</code> a starting value for time and a call to update time
 | |
|         via <code>setInterval</code>.
 | |
| 
 | |
|     pre.prettyprint.lang-javascript
 | |
|         code.
 | |
|             setInterval(function () { this.time = (new Date()).toString(); }.bind(this), 1000);
 | |
|     p Reload the page in your browser and you'll now see the seconds updating automatically.
 | |
| .l-main-section
 | |
|     h2#Create-an-array Create an array property and use For on the view
 | |
|     p Moving up from a single property, create an array to display as a list.
 | |
|     .code-box
 | |
|       pre.prettyprint.lang-javascript(data-name="es5")
 | |
|           code.
 | |
|               //ES5
 | |
|               function DisplayComponent() {
 | |
|                 this.myName = "Alice";
 | |
|                 this.names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"];
 | |
|               }
 | |
|       pre.prettyprint.lang-typescript(data-name="typescript")
 | |
|           code.
 | |
|               //Typescript
 | |
|               constructor() {
 | |
|                 this.myName = "Alice";
 | |
|                 this.names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"];
 | |
|               }
 | |
|     p.
 | |
|         You can then use this array in your template with the <code>for</code> directive to create copies of DOM elements
 | |
|         with one for each item in the array.
 | |
|     .code-box
 | |
|       pre.prettyprint.lang-javascript(data-name="es5")
 | |
|           code.
 | |
|               //ES5
 | |
|               template:
 | |
|                  '<p>My name: {{ myName }}</p>' +
 | |
|                  '<p>Friends:</p>' +
 | |
|                  '<ul>' +
 | |
|                  '<li *for="#name of names">' +
 | |
|                  '{{ name }}' +
 | |
|                  '</li>' +
 | |
|                  '</ul>',
 | |
| 
 | |
|       pre.prettyprint.lang-typescript(data-name="typescript")
 | |
|           code.
 | |
|               //Typescript
 | |
|               template: `
 | |
|                 <p>My name: {{ myName }}</p>
 | |
|                 <p>Friends:</p>
 | |
|                 <ul>
 | |
|                    <li *for="#name of names">
 | |
|                       {{ name }}
 | |
|                    </li>
 | |
|                 </ul>
 | |
|               `,
 | |
|     p.
 | |
|         To make this work, you'll also need to add the <code>angular.For</code> directive used by the template so
 | |
|         that Angular knows to include it:
 | |
| 
 | |
|     .code-box
 | |
|       pre.prettyprint.lang-javascript(data-name="es5")
 | |
|           code.
 | |
|               //ES5
 | |
|               directives: [angular.For]
 | |
|       pre.prettyprint.lang-typescript(data-name="typescript")
 | |
|           code.
 | |
|               //Typescript
 | |
|               import {Component, View, bootstrap, For} from
 | |
|               ...
 | |
|                 directives: [For]
 | |
|     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:
 | |
|     pre.prettyprint.lang-html
 | |
|         code.
 | |
|             //HTML
 | |
|             <li *for="#name of names">
 | |
|                {{ name }}
 | |
|             </li>
 | |
|     p The way to read this is:
 | |
|     ul
 | |
|         li.
 | |
|             <code>*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>
 | |
|              like an array
 | |
|         li <code>#name</code> : refer to individual values of the iterable as 'name'
 | |
|         li <code>of names</code> : the iterable to use is called 'names' 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 class for the array property and inject into component
 | |
|     p.
 | |
|         Before we get too much further, we should mention that putting our model (array) directly in our 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 provide the model with the list of friends.
 | |
|     pre.prettyprint.lang-javascript
 | |
|         code.
 | |
|             function FriendsService() {
 | |
|               this.names = ["Alice", "Aarav", "Martín", "Shannon", "Ariana", "Kai"];
 | |
|             }
 | |
|     p.
 | |
|         Replace the current list of friends in DisplayComponent by passing in the FriendsService and setting the list of
 | |
|         names in DisplayComponent to the names provided by the service you passed in.
 | |
|     pre.prettyprint.lang-javascript
 | |
|         code.
 | |
|             function DisplayComponent(friends) {
 | |
|               this.myName = "Alice";
 | |
|               this.names = friends.names;
 | |
|             }
 | |
|     p And then make FriendsService available to dependency injection
 | |
|     pre.prettyprint.lang-javascript
 | |
|         code.
 | |
|             DisplayComponent.annotations = [
 | |
|               new angular.Component({
 | |
|                 selector: "display",
 | |
|                 injectables: [FriendsService]
 | |
|               }),
 | |
|             ...
 | |
|             DisplayComponent.parameters = [[FriendsService]];
 | |
|     .callout.is-helpful
 | |
|         header ES5 Note
 | |
|         p.
 | |
|             The dependency injection syntax here is using the low-level API and is...well...not very nice.  We're
 | |
|             working on sugaring the syntax to match the way it works in Angular 1.  Expect this to change soon.
 | |
| 
 | |
|     .code-box
 | |
|       pre.prettyprint.lang-javascript(data-name="es5")
 | |
|           code.
 | |
|               //ES5
 | |
|               function FriendsService() {
 | |
|                 this.names = ["Alice", "Aarav", "Martín", "Shannon", "Ariana", "Kai"];
 | |
|               }
 | |
|               function DisplayComponent(friends) {
 | |
|                 this.myName = "Alice";
 | |
|                 this.names = friends.names;
 | |
|               }
 | |
|               DisplayComponent.annotations = [
 | |
|                 new angular.Component({
 | |
|                   selector: "display",
 | |
|                   injectables: [FriendsService]
 | |
|                 }),
 | |
|                 new angular.View({
 | |
|                   template: '{{ myName }} <ul> <li *for="#name of names">{{ name }}</li> </ul>',
 | |
|                   directives: [angular.For, angular.If]
 | |
|                 })
 | |
|               ];
 | |
|               DisplayComponent.parameters = [[FriendsService]];
 | |
|               document.addEventListener("DOMContentLoaded", function() {
 | |
|                 angular.bootstrap(DisplayComponent);
 | |
|               });
 | |
|       pre.prettyprint.lang-typescript(data-name="typescript")
 | |
|           code.
 | |
|               //TypeScript
 | |
|               import {Component, View, bootstrap, For} from
 | |
|               ...
 | |
|                 directives: [For]
 | |
| .l-main-section
 | |
|     h2#Conditionally-displaying-data-with-If Conditionally displaying data with If
 | |
|     p.
 | |
|         Lastly, before we move on, let's handle showing parts of our UI conditionally with <code>If</code>.  The
 | |
|         <code>If</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
 | |
|     pre.prettyprint.lang-html
 | |
|         code.
 | |
|             <p *if="names.length > 3">You have many friends!</p>
 | |
|     p You'll also need to add the If directive so Angular knows to include it.
 | |
| 
 | |
|     .code-box
 | |
|       pre.prettyprint.lang-javascript(data-name="es5")
 | |
|           code.
 | |
|               //ES5
 | |
|               directives: [angular.For, angular.If]
 | |
|       pre.prettyprint.lang-typescript(data-name="typescript")
 | |
|           code.
 | |
|               //Typescript
 | |
|               import {Component, View, bootstrap, For, If} from
 | |
|               ...
 | |
|                 directives: [For, If]
 | |
|     p.
 | |
|         As there are currently 5 items it the list, 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.
 | |
|     .code-box
 | |
|       pre.prettyprint.lang-javascript(data-name="es5")
 | |
|           code.
 | |
|               //ES5
 | |
|               function DisplayComponent() {
 | |
|                 this.myName = "Alice";
 | |
|                 this.names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"];
 | |
|               }
 | |
|               DisplayComponent.annotations = [
 | |
|                 new angular.Component({
 | |
|                   selector: "display"
 | |
|                 }),
 | |
|                 new angular.View({
 | |
|                   template:
 | |
|                     '<p>My name: {{ myName }}</p>' +
 | |
|                     '<p>Friends:</p>' +
 | |
|                     '<ul>' +
 | |
|                     '<li *for="#name of names">' +
 | |
|                     '{{ name }}' +
 | |
|                     '</li>' +
 | |
|                     '</ul>' +
 | |
|                     '<p *if="names.length > 3">You have many friends!</p>',
 | |
|                   directives: [angular.For, angular.If]
 | |
|                 })
 | |
|               ];
 | |
|       pre.prettyprint.lang-typescript(data-name="typescript")
 | |
|           code.
 | |
|               //TypeScript
 | |
|               import {Component, View, bootstrap, For, If} from 'angular2/angular2';
 | |
|               @Component({
 | |
|                 selector: 'display'
 | |
|               })
 | |
|               @View({
 | |
|                 template: `
 | |
|                   <p>My name: {{ myName }}</p>
 | |
|                   <p>Friends:</p>
 | |
|                   <ul>
 | |
|                     <li *for="#name of names">
 | |
|                       {{ name }}
 | |
|                     </li>
 | |
|                   </ul>
 | |
|                   <p *if="names.length > 3">You have many friends!</p>
 | |
|                 `,
 | |
|                 directives: [For, If]
 | |
|               })
 | |
|               class DisplayComponent {
 | |
|                 myName: string;
 | |
|                 todos: Array<string>;
 | |
|                 constructor() {
 | |
|                   this.myName = "Alice";
 | |
|                   this.names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"];
 | |
|                 }
 | |
|               }
 |