• No se han encontrado resultados

Temperaturdifferenz Kollektor – Speicher [K]

gelante 6 °C, el circuito de carga se desactiva

11 Contador de energía

You might be wondering at this point how we would manage the data flow if we started adding more functionality to this app.

For instance, say we wanted to add a shopping cart view and then we would add items to our cart. How could we implement this?

The only tools we’ve talked about are emitting output events. When we click add-to-cart do we simply bubble up anaddedToCartevent and handle at the root component? That feels a bit awkward. Data architecture is a large topic with many opinions. Thankfully, Angular is flexible enough to handle a wide variety of data architectures, but that means that you have to decide for yourself which to use.

In Angular 1, the default option was two-way data binding. Two-way data binding is super easy to get started: your controllers have data, your forms manipulate that data directly, and your views show the data.

The problem with two-way data binding is that it often causes cascading effects throughout your application and makes it really difficult to trace data flow as your project grows.

Another problem with two-way data binding is that because you’re passing data down through components it often forces your “data layout tree” to match your “dom view tree”. In practice, these two things should really be separate.

One way you might handle this scenario would be to create aShoppingCartService, which would be a singleton that would hold the list of the current items in the cart. This service could notify any interested objects when the items in the cart changes.

The idea is easy enough, but in practice there’s a lot of details to be worked out.

The recommended way in Angular 2, and in many modern web frameworks (such as React) is to adopt a pattern of one-way data binding. That is, your data flows only down through components. If you need to make changes, you emit events that cause changes to happen “at the top” which then trickle down.

One-way data binding can seem like it adds some overhead in the beginning but it saves a lot of complication around change detection and it makes your systems easier to reason about.

Thankfully there are two major contenders for managing your data architecture: 1. Use an Observables-based architecture like RxJS

2. Use a Flux-based architecture

Later in this book we’ll talk about how to implement a scalable data architecture for your app. For now, bask in the joy of your new Component-based application!

Introduction

Angular 2 provides a number of built-in components. In this chapter, we’re going to cover each built-in component and show you examples of how to use them.

The built-in components are imported and made available to your components automat- ically, so you don’t need to inject it as a directive like you would do with your own components.

NgIf

ThengIfdirective is used when you want to display or hide an element based on a condition. The condition is determined by the result of the expression that you pass in to the directive.

If the result of the expression returns a false value, the element will be removed from the DOM. Some examples are:

1 <div *ngIf="false"></div> <!-- never displayed -->

2 <div *ngIf="a > b"></div> <!-- displayed if a is more than b -->

3 <div *ngIf="str == 'yes'"></div> <!-- displayed if str holds the string "yes" -\

4 ->

5 <div *ngIf="myFunc()"></div> <!-- displayed if myFunc returns a true value \

6 -->

If you have experience with Angular 1, you probably usedngIfdirective before. You can

think of the Angular 2 version as a direct substitute. On the other hand, Angular 2 offers no built-in alternative forng-show. So, if your goal is to just change the CSS visibility of an

element, you should look into either theng_styleor theclassdirectives, described later

in this chapter.

NgSwitch

Sometimes you need to render different elements depending on a given condition. When you run into this situation, you could usengIfseveral times like this:

1 <div class="container">

2 <div *ngIf="myVar == 'A'">Var is A</div>

3 <div *ngIf="myVar == 'B'">Var is B</div>

4 <div *ngIf="myVar != 'A' && myVar != 'B'">Var is something else</div>

5 </div>

But as you can see, the scenario wheremyVaris neither A nor B is pretty verbose, all we’re really trying to express is anelse. And as we add more values the lastngIfcondition will become more complex.

To illustrate this growth in completexity, let’s say we wanted to handle a new hypoteticalCvalue. In order to do that, we’d have to not only add the new element withngIf, but also change the last case:

1 <div class="container">

2 <div *ngIf="myVar == 'A'">Var is A</div> 3 <div *ngIf="myVar == 'B'">Var is B</div> 4 <div *ngIf="myVar == 'C'">Var is C</div>

5 <div *ngIf="myVar != 'A' && myVar != 'B' && myVar != 'C'">Var is something els\ 6 e</div>

7 </div>

For cases like this, Angular 2 introduces thengSwitchdirective.

If you’re familiar with theswitchstatement then you’ll feel very at home.

The idea behind this directive is the same: allow a single evaluation of an expression, and then display nested elements based on the value that resulted from that evaluation.

Once we have the result then we can:

• Describe the known results, using thengSwitchCasedirective • Handle all the other unknown cases withngSwitchDefault Let’s rewrite our example using this new set of directives:

1 <div class="container" [ngSwitch]="myVar"> 2 <div *ngSwitchCase="'A'">Var is A</div>

3 <div *ngSwitchCase="'B'">Var is B</div>

4 <div *ngSwitchDefault>Var is something else</div>

5 </div>

1 <div class="container" [ngSwitch]="myVar"> 2 <div *ngSwitchCase="'A'">Var is A</div> 3 <div *ngSwitchCase="'B'">Var is B</div> 4 <div *ngSwitchCase="'C'">Var is C</div>

5 <div *ngSwitchDefault>Var is something else</div> 6 </div>

And we don’t have to touch the default (i.e. fallback) condition.

Having thengSwitchDefaultelement is optional. If we leave it out, nothing will be rendered when myVarfails to match any of the expected values.

You can also declare the same*ngSwitchCasevalue for different elements. Here’s an example: code/built_in_components/app/ts/ng_switch/ng_switch.ts

7 template: `

8 <h4 class="ui horizontal divider header">

9 Current choice is {{ choice }}

10 </h4>

11

12 <div class="ui raised segment">

13 <ul [ngSwitch]="choice">

14 <li *ngSwitchCase="1">First choice</li>

15 <li *ngSwitchCase="2">Second choice</li>

16 <li *ngSwitchCase="3">Third choice</li>

17 <li *ngSwitchCase="4">Fourth choice</li>

18 <li *ngSwitchCase="2">Second choice, again</li>

19 <li *ngSwitchDefault>Default choice</li>

20 </ul>

21 </div>

22

23 <div style="margin-top: 20px;">

24 <button class="ui primary button" (click)="nextChoice()">

25 Next choice

26 </button>

27 </div>

28 `

Another nice feature of ngSwitchCaseis that you’re not limited to matching only a single time. For instance, in the example above when thechoiceis2, both the second and fifthlis will be rendered.

NgStyle

With the NgStyle directive, you can set a given DOM element CSS properties from Angular expressions.

The simplest way to use this directive is by doing[style.<cssproperty>]="value". For example: code/built_in_components/app/ts/ng_style/ng_style.ts

12 <div [style.background-color]="'yellow'"> 13 Uses fixed yellow background

14 </div>

This snippet is using theNgStyledirective to set thebackground-colorCSS property to the literal string'yellow'.

Another way to set fixed values is by using theNgStyleattribute and using key value pairs for each property you want to set, like this:

code/built_in_components/app/ts/ng_style/ng_style.ts

20 <div [ngStyle]="{color: 'white', 'background-color': 'blue'}"> 21 Uses fixed white text on blue background

22 </div>

Notice that in theng-stylespecification we have single quotes aroundbackground-color

but not around color. Why is that? Well, the argument tong-styleis a Javascript object and coloris a valid key, without quotes. Withbackground-color, however, the dash character

isn’t allowed in an object key, unless it’s a string so we have to quote it.

Generally I’d leave out quoting as much as possible in object keys and only quote keys when we have to.

Here we are setting both thecolorand thebackground-colorproperties. But the real power of theNgStyledirective comes with using dynamic values. In our example, we are defining two input boxes:

code/built_in_components/app/ts/ng_style/ng_style.ts

63 <div class="ui input">

64 <input type="text" name="color" value="{{color}}" #colorinput> 65 </div>

66

67 <div class="ui input">

68 <input type="text" name="fontSize" value="{{fontSize}}" #fontinput> 69 </div>

And then using their values to set the CSS properties for three elements. On the first one, we’re setting the font size based on the input value: code/built_in_components/app/ts/ng_style/ng_style.ts

28 <div>

29 <span [ngStyle]="{color: 'red'}" [style.font-size.px]="fontSize">

30 red text

31 </span>

32 </div>

It’s important to note that we have to specify units where appropriate. For instance, it isn’t valid CSS to set afont-sizeof 12- we have to specify a unit such as12pxor1.2em. Angular provides a handy syntax for specifying units: here we used the notation[style.fontSize.px].

The.pxsuffix indicates that we’re setting thefont-sizeproperty value in pixels. You could easily replace that by[style.fontSize.em] to express the font size in ems or even in percentage using [style.fontSize.%].

The other two elements use the#colorinputto set the text and background colors: code/built_in_components/app/ts/ng_style/ng_style.ts

40 <h4 class="ui horizontal divider header"> 41 ngStyle with object property from variable 42 </h4>

43

44 <div>

45 <span [ngStyle]="{color: colorinput.value}"> 46 {{ colorinput.value }} text

47 </span>

48 </div>

50 <h4 class="ui horizontal divider header"> 51 style from variable

52 </h4>

53

54 <div [style.background-color]="colorinput.value"

55 style="color: white;">

56 {{ colorinput.value }} background 57 </div>

This way, when we click the Apply settings button, we call a method that sets the new values: code/built_in_components/app/ts/ng_style/ng_style.ts

98 apply(color: string, fontSize: number) { 99 this.color = color;

100 this.fontSize = fontSize;

101 }

And with that, both the color and the font size will be applied to the elements using theNgStyle directive.

NgClass

The NgClassdirective, represented by a ngClassattribute in your HTML template, allows you to dynamically set and change the CSS classes for a given DOM element.

If you’re coming from Angular 1, theNgClass directive will feel very similar to what ngClassused to do in Angular 1.

The first way to use this directive is by passing in an object literal. The object is expected to have the keys as the class names and the values should be a truthy/falsy value to indicate whether the class should be applied or not.

code/built_in_components/app/css/styles.scss

11 .bordered {

12 border: 1px dashed black;

13 background-color: #eee;

14 }

Let’s add twodivelements: one always having theborderedclass (and therefore always having the border) and another one never having it:

code/built_in_components/app/ts/ng_class/ng_class.ts

9 <div [ngClass]="{bordered: false}">This is never bordered</div>

10 <div [ngClass]="{bordered: true}">This is always bordered</div>

As expected, this is how those twodivs would be rendered :

Simple class directive usage

Of course, it’s a lot more useful to use theNgClassdirective to make class assignments dynamic. To make it dynamic we add a variable as the value for the object value, like this:

code/built_in_components/app/ts/ng_class/ng_class.ts

12 <div [ngClass]="{bordered: isBordered}">

13 Using object literal. Border {{ isBordered ? "ON" : "OFF" }} 14 </div>

Alternatively, we can define the object in our component: code/built_in_components/app/ts/ng_class/ng_class.ts

50 export class NgClassSampleApp { 51 isBordered: boolean;

52 classesObj: Object; 53 classList: string[];

code/built_in_components/app/ts/ng_class/ng_class.ts

16 <div [ngClass]="classesObj">

17 Using object var. Border {{ classesObj.bordered ? "ON" : "OFF" }} 18 </div>

Again, be careful when you have class names that contains dashes, likebordered-box.

JavaScript objects don’t allow literal keys to have dashes. If you need to use them, you must make the key a string like this:

1 <div [ngClass]="{'bordered-box': false}">...</div>

We can also use a list of class names to specify which class names should be added to the element. For that, we can either pass in an array literal:

code/built_in_components/app/ts/ng_class/ng_class.ts

37 <div class="base" [ngClass]="['blue', 'round']"> 38 This will always have a blue background and 39 round corners

40 </div>

Or declare an array variable in our component: 1 this.classList = ['blue', 'round'];

And passing it in:

code/built_in_components/app/ts/ng_class/ng_class.ts

42 <div class="base" [ngClass]="classList">

43 This is {{ classList.indexOf('blue') > -1 ? "" : "NOT" }} blue 44 and {{ classList.indexOf('round') > -1 ? "" : "NOT" }} round 45 </div>

In this last example, the[class]assignment works alongside existing values assigned by the HTML classattribute.

The resulting classes added to the element will always be the set of the classes provided by usual classHTML attribute and the result of the evaluation of the[class]directive.

code/built_in_components/app/ts/ng_class/ng_class.ts

37 <div class="base" [ngClass]="['blue', 'round']"> 38 This will always have a blue background and 39 round corners

40 </div>

The element will have all three classes: base from the classHTML attribute and also blue and roundfrom the[class]assigment:

Classes from both the attribute and directive

NgFor

The role of this directive is to repeat a given DOM element (or a collection of DOM elements), each time passing it a different value from an array.

This directive is the successor of ng1’sng-repeat.

The syntax is*ngFor="let item of items".

• Thelet itemsyntax specifies a (template) variable that’s receiving each element of theitems array;

• Theitemsis the collection of items from your controller.

To illustrate, we can take a look at the code example. We declare an array of cities on our component controller:

1 this.cities = ['Miami', 'Sao Paulo', 'New York'];

And then, in our template we can have the following HTML snippet: code/built_in_components/app/ts/ng_for/ng_for.ts

8 <h4 class="ui horizontal divider header"> 9 Simple list of strings

10 </h4>

11

12 <div class="ui list" *ngFor="let c of cities"> 13 <div class="item">{{ c }}</div>

14 </div>

And it will render each city inside thedivas you would expect:

Result of the ng_for directive usage We can also iterate through an array of objects like these:

code/built_in_components/app/ts/ng_for/ng_for.ts

72 this.people = [

73 { name: 'Anderson', age: 35, city: 'Sao Paulo' }, 74 { name: 'John', age: 12, city: 'Miami' },

75 { name: 'Peter', age: 22, city: 'New York' }

76 ];

code/built_in_components/app/ts/ng_for/ng_for.ts

16 <h4 class="ui horizontal divider header"> 17 List of objects

18 </h4>

19

20 <table class="ui celled table"> 21 <thead> 22 <tr> 23 <th>Name</th> 24 <th>Age</th> 25 <th>City</th> 26 </tr> 27 </thead>

28 <tr *ngFor="let p of people"> 29 <td>{{ p.name }}</td>

30 <td>{{ p.age }}</td>

31 <td>{{ p.city }}</td>

32 </tr>

33 </table>

Getting the following result:

Rendering array of objects

We can also work with nested arrays. If we wanted to have the same table as above, broken down by city, we could easily declare a new array of objects:

code/built_in_components/app/ts/ng_for/ng_for.ts

77 this.peopleByCity = [

78 {

79 city: 'Miami',

80 people: [

81 { name: 'John', age: 12 }, 82 { name: 'Angel', age: 22 }

83 ]

84 },

85 {

86 city: 'Sao Paulo',

87 people: [

88 { name: 'Anderson', age: 35 }, 89 { name: 'Felipe', age: 36 }

90 ]

91 }

92 ];

93 };

And then we could useNgForto render oneh2for each city : code/built_in_components/app/ts/ng_for/ng_for.ts

39 <div *ngFor="let item of peopleByCity"> 40 <h2 class="ui header">{{ item.city }}</h2>

And use a nested directive to iterate through the people for a given city : code/built_in_components/app/ts/ng_for/ng_for.ts

42 <table class="ui celled table"> 43 <thead> 44 <tr> 45 <th>Name</th> 46 <th>Age</th> 47 </tr> 48 </thead>

49 <tr *ngFor="let p of item.people"> 50 <td>{{ p.name }}</td>

51 <td>{{ p.age }}</td>

52 </tr>

53 </table>

code/built_in_components/app/ts/ng_for/ng_for.ts

35 <h4 class="ui horizontal divider header"> 36 Nested data

37 </h4>

38

39 <div *ngFor="let item of peopleByCity"> 40 <h2 class="ui header">{{ item.city }}</h2>

41

42 <table class="ui celled table"> 43 <thead> 44 <tr> 45 <th>Name</th> 46 <th>Age</th> 47 </tr> 48 </thead>

49 <tr *ngFor="let p of item.people"> 50 <td>{{ p.name }}</td>

51 <td>{{ p.age }}</td>

52 </tr>

53 </table>

54 </div>

Rendering nested arrays

Documento similar