More on Components

In the last chapter, we created a basic Recipe Book app. In this chapter, we will add to the app by creating a feature that will allow users to rate each recipe.


What you will learn

Previously, you learned about how to create a basic Angular component. In this chapter, we will dive deeper into components and their features.


Running the sample app

The code for this chapter is in the Chapter_03 directory of the angular.dart.tutorial download. View it in Dart Editor by using File > Open Existing Folder... to open the Chapter_03 directory.

Now run the app. In Dart Editor’s Files view, select Chapter_03/web/index.html, right-click, and choose Run in Dartium.

You’ll notice that the rating, which used to be displayed as a boring number, has now become a not-so-boring cluster of stars. Play around with the star ratings by changing the rating on each recipe. Click any of the recipes to display its details, and notice there is also a star rating component in the recipe details section. Change the recipe rating in the details section; the rating in the recipe list section also changes.


Angular components

The rating feature is an Angular component, implemented using the Component annotation. Components are lightweight, reusable, self-contained UI components that have a single specific purpose. The rating component is a great example of a small, simple, re-usable component. It can be used anywhere in your app as many times as you want. Nothing about the rating component is intrinsically tied to our Recipe Book. We could use this component in any app to rate anything.


Using components from your app

Using a component from your app is simple. Just create an HTML element with the name of the component, and pass any required properties in as HTML attributes. Here is how our Recipe Book app uses the rating component.


Declaring components

As seen in the previous chapter, the @Component annotation is used to declare a component:

The selector, templateUrl and cssUrl options have been explained in the previous chapter. There are a few more that can be used.

useShadowDom

By default the component template is inserted into a shadow root node - the shadow host being the DOM node triggering the component directive. useShadowDom can be set to false to prevent the usage of shadow DOM for this component. In such a case the shadow DOM behavior is emulated so that the features stay the same.

map

You can be use the map option to describe the bindings for the component. Later in this chapter you'll see another option for describing bindings: field annotations.


Defining attributes

Recall how our Recipe Book app uses the rating component:

To specify which HTML attributes correspond to which properties of the component, the RatingComponent class uses annotations like the following:

The argument to the annotation specifies the HTML attribute name—for example, “rating” or “max-rating”. Following HTML rules, the attribute name is case insensitive, with dashes to separate words.

Which annotation you should use depends on how you want the attribute to be evaluated:

NgAttr

Sets the property to the value of the attribute, interpolating if it contains {{}}. Our example had this: max-rating="5". You could also get the value from the model by doing something like max-rating="{{someProperty}}".

NgAttr attributes are unidirectional. A copy of the attribute is passed to the component, and each instance of the component has its own copy. The component can change its local value of the property without changing the value outside the component.

NgOneWay

Evaluates the attribute's value as an expression and passes the result to the component. You can use any valid expression—for example, "foo + bar" would pass the result of foo + bar to the component.

NgOneWay attributes are unidirectional. The component's property changes if the expression's value changes, but changing the component's property has no effect outside the component.

NgTwoWay

Evaluates the expression, passes the result to the component, and keeps the expression and property value in sync. Our example set an NgTwoWay attribute using this code: rating="selectedRecipe.rating"

NgTwoWay is bidirectional. When a component changes the value of an NgTwoWay-annotated property, the value outside of the component changes, as well. In this way, components can change model objects in your app. In our example, the rating component changes the rating on your RecipeBook’s model objects.


How do components work?

Components inner structure of components are isolated from their surroundings and can be thought of as black boxes.

Components create their own scope hierarchy that is invisible from the outside world. They don’t have direct access to the app’s scope, nor does the app have direct access to a component’s scope.

Components isolate their views from their surroundings by creating a shadow DOM. Using a shadow DOM allows components to be used anywhere without suffering from things like CSS name collisions.


Angular features

This chapter introduced you to two more built-in Angular directives: ng-if and ng-class.

ng-if

The ng-if directive allows you to evaluate sections of the DOM conditionally. The ng-if directive takes an expression. If the expression is false, then the portion of the DOM underneath the if is removed. ng-if does not change the visibility of the DOM element. It removes it.

ng-class

The ng-class directive allows you to set CSS classes on an element dynamically using an expression that evaluates to the classes to be added.