We took a detailed look at the Component decorator, talking about attributes like template versus templateUrl, styles, and also covered at a high level how Angulars change detection works and how we can override it. The EventEmitter can be typed for additional type safety. Initialize an array of products there, instead of initializing a single product in the ProductComponent. To some extent, you can consider an Angular application to be nothing but a tree of components.
In case it is not a component that you wrote, make sure that you have imported the module that provides/exports the component.
In these cases, we can use the exportAs attribute of the Component decorator.
For now, it is good to understand the difference between the two change detection strategies that Angular provides.
Your carousel component might also have other features like lazy loading, etc. We then covered the lifecycle of a component, as well as the hooks that Angular provides for us to hook on to and react to some of these lifecycle events. Angular will not check the components bindings automatically.
If the parent component B changes any attribute on the compositeObj directly (as a response to a user action outside component B), then these changes would not be updated in component C (major change from the default behavior). When you run it, open the JavaScript console in the browser.
I basically want to extend a component and inherit it's styles, but the AnotherComponent is not inheriting the base-component.css. Similarly, we can do the same for the StockItemComponent: We have done exactly the same thing we did on the AppComponent with the StockItemComponent. This template can then continue to use other components, thus forming a tree of components, which is the Angular application that gets rendered in the browser. Both of these take an array as an input.
You can check out the finished solution in chapter4/exercise/ecommerce. (This is why we added the counter!). Next, lets quickly modify stock-item.component.html to allow us to trigger the new function. First, lets add the following snippet of code to the app.component.css file. This lifecycle executes in preorder tree traversal order, from top to bottom. Move the increment/decrement logic from the ProductItem to the ProductListComponent. Finally, lets tie it all together by subscribing to the new output from our StockComponent in the app-component.html file: We just added an event binding using Angulars event-binding syntax to the output declared in the stock-item component. The last thing we will cover in this chapter is the concept of view projection. Projection is an important idea in Angular as it gives us more flexibility when we develop our components and again gives us another tool to make them truly reusable under different contexts.
The best way to see how this impacts our application is to make a slight change and see how our application behaves under different circumstances. It would be nice for templates too! Now when you run this application, you should expect to see the following behavior: Clicking Add to Favorite within the StockItemComponent still works as expected. The selector takes a string value, which is the CSS selector Angular will use to identify the element. This is because the styles applied on the AppComponent are not restricted to just the component but are now taking the global namespace. You can do so by using the interpolation attribute, which takes an array of two strings, the opening and closing markers for the interpolation. Move the ProductItemComponent to be optimal and move from the default ChangeDetectionStrategy to an OnPush ChangeDetectionStrategy.
Clicking Change Price outside the StockItemComponent will have no impact (even though the actual value of the stock will jump if you click Change Price inside after this). to your account. Take OReilly with you and learn anywhere, anytime on your phone and tablet.
You should see, in order of execution: First, the AppComponent gets created.
There are times when the default Angular interpolation markers (the double-curlies {{ and }}) interfere with integrating with other frameworks or technologies. These hooks become very useful for certain trickier initialization logic, and are definitely essential for cleanup once your component is done and dusted, to avoid memory leaks.
What this tells Angular is that the bindings for this particular component will need to be checked only based on the Input to this component. In the previous chapter, we did a deep dive into the built-in directives that Angular offers that allow us to perform common functionality like hiding and showing elements, repeating templates, and so on. Similarly, lets quickly change the main app.component.html file to add another button to trigger the change of the price from the parent component (similar to component B in the earlier hypothetical example): We have added two new buttons to this template: one that will change the reference of the stock object directly, and another that will modify the existing reference of the stock object to change the price from the parent AppComponent. That way I could reference the template content using the type at least. Angular will first call the constructor for any component, and then the various steps mentioned earlier in order. The OnDestroy hook is called when a component is about to be destroyed and removed from the UI. If you create a new component, and do not add it to a module, Angular will complain that you have components that are not part of any modules. It is called before the ngOnInit method. This is one of the ways we can use to notify Angular of a change in the component, when we override the default ChangeDetectionStrategy for a component from Default to OnPush. It is a good place to do all cleanup, like unsubscribing any listeners you may have initialized and the like. It would be cool to be able to add it in the AnotherComponent style array but since it's bundled I guess this won't work.
ViewChildren is any child component whose tags/selectors (mostly elements, as that is the recommendation for components) appear within the template of the component. It also feels like a more organic way of extending components. Thus, any element that adds the name class to itself will get this font-size applied to it.
This makes sense as well because the parent component is responsible for the data and should be the single source of truth. One of the ways we can make a component reusable (rather than having default, hardcoded values inside it) is by passing in different inputs depending on the use case.
In the preceding section, we talked about how Angular encapsulates the styles to ensure that it doesnt contaminate any of your other components. The HTML markup remains pretty much the same otherwise: Next, we add a method to the AppComponent that should be triggered whenever the onToggleFavorite method is triggered, which we will add event binding on: The only thing new is the onToggleFavorite method we have added, which takes a stock as an argument. The Angular CLI will automatically add your component or directive to the module when you create a component through it. Thanks.
Sign in By default, they are ['{{', '}}'], but you override it by, say, providing interpolation: ['<<', '>>'] to replace the interpolation symbols for just that component to << and >>.
We use data binding to pass data in, and we use event binding syntax to register for events. The imports attribute allows you to specify modules that you want imported and accessible within your module.
Clicking Change Stock outside the StockItemComponent will change the name of the stock with each click. Without it, the function would still get triggered, but you would not get any arguments with it. I want to be able to extend a component and add on encapsulated styles with the same template, or provide a different template but keep the same styles. There is no other change required in the component. Now if we refresh our application, you will see that the name of the stock has been blown up to 50px. The way I worked around this was to add a static field in the inherited class and add the template to that. Now that we have seen how Input and Output decorators work, lets deep dive a little bit into how Angular performs its change detection at a component level.
Also, to get access to the value emitted by the component, we use the keyword $event as a parameter to the function. All we have done is taken the template and moved it into the template attribute of the Component decorator. We will use these functions to demonstrate the behavior of the change detection in the context of our application. As mentioned, the AfterContentInit hook is triggered during component projection cases, and only once during initialization of the component. Next, lets take a look at the AppComponent and how we can change that to now pass in the data to the StockItemComponent: We just moved the initialization of the stock object from the StockItemComponent to the AppComponent. The onToggleFavorite now just calls a method on the EventEmitter to emit the entire stock object. View providers allow you to define providers that inject classes/services into a component or any of its children.
We will cover these in Change Detection.
I have a angular library (ng generate library shared) with a BaseComponent in, I want to be able to extend that component in another project and keep the styles of both the BaseComponent and the new component (AnotherComponent). There is no impact on the final generated application as Angular compiles the code into a single bundle. I have the same problem and same request! So in our case, app-stock-item would be a ViewChild of the AppComponent. Note that as a result of moving it to template, we have removed the previous templateUrl attribute.
Finally, we covered projection in components and how we can make some truly powerful components that allow the user of the component to decide parts of the UI.
Get Mark Richardss Software Architecture Patterns ebook to better understand how to design componentsand how they should interact.
When you first start out building Angular applications, you might easily forget to add your newly created components to the declarations attribute, so keep track of that (if you are not using the Angular CLI, that is!) Now finally, we can see how all of this is hooked up in the app.component.ts file: The app.component.ts file has seen the most changes. Again, a good way to think about both this and AfterContentChecked is like a depth-first tree traversal, in that it will execute only after all the children components AfterViewChecked hooks have finished executing. We have been working so far by using the component classs functions within the context of the template. In one, we have a button that triggers the testMethod we added in the AppComponent, and the other simply has text content. We will cover this in more detail in Chapter8.
Angular will end up picking one or the other and will lead to unexpected behavior. The selector attribute, as we touched upon briefly in Chapter2, allows us to define how Angular identifies when the component is used in HTML.
First, we can modify the src/app/app.component.ts file and add the hooks as follows: You can see that we have implemented the interfaces for OnInit, OnChanges, OnDestroy, DoCheck, AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit on the AppComponent class, and then went ahead and implemented the respective functions. In the preceding example, we have defined that the StockItemComponent is to be rendered whenever Angular encounters the app-stock-item selector, and to render the stock-item.component.html file when it encounters the element.
By default, Angular checks every binding in the UI to see if it needs to update any UI element whenever any value changes in our component.
We worked with directives like ngIf and ngForOf and got a feel for how and when to use them. This can help reduce the build size by compressing your HTML. There is also one more concept to learn, which we will briefly touch upon in this chapter, and come back to later in more detailthe concept of ViewChildren and ContentChildren. HTML, CSS, and JavaScript have a default tendency to be global in the context of the current page.
For example, here are a few ways you could specify the selector attribute and how you would use it in the HTML: selector: 'app-stock-item' would result in the component being used as
We will first modify the stock-item component to mark the stock as an input to the component, but instead of initializing the stock object, we will mark it as an Input to the component. 2022, OReilly Media, Inc. All trademarks and registered trademarks appearing on oreilly.com are the property of their respective owners. Notice again that it is case sensitive and it has to exactly match what member variable we decorated with the Output decorator. Lets consider a few examples to see how this might play out.
The exports attribute is relevant if you either have multiple modules or you need to create a library that will be used by other developers.
Lets take a look again at the stock-item component we created to see what a simple component would look like, and we will build up from there: The very basic component only needs a selector (to tell Angular how to find instances of the component being used) and a template (that Angular has to render when it finds the element).
First, modify the stock-item.component.ts file to change the ChangeDetectionStrategy in the child component: In addition to changing the ChangeDetectionStrategy, we also added another function to changeStockPrice(). We leverage this usually when we define inline templates.
We have also added a counter just to keep track of how many times we create a new stock object, but that is not strictly necessary.
A use case might be that we provide a carousel component, but want to provide functionality to allow the user of the component to control the next/previous functionality.
Each of these lifecycle steps comes with an interface that should be implemented when a component cares about that particular lifecycle, and each interface provides a function starting with ng that needs to be implemented.
Shadow DOM fixes this by scoping HTML DOM and CSS. This shows that the model is getting updated, but Angular is not updating the view. So basically inheritance of styles and templates.
Similarly, there might be cases where we want hooks from a component when a certain activity happens within its context.
In the previous case, we can either specify the templateUrl as: and it would work. selector: '.app-stock-item' would result in the component being used as a CSS class like
in the HTML.Then the following hooks are triggered on the AppComponent: The preceding two immediately execute because we dont have any content projection in our application so far. How do I get my Angular 6 components to inherit it's extended component's styles? If you want to use a component from other modules, make sure you import the relevant modules into the module you have declared and where the component exists. In this chapter, we will go a bit deeper into components, those elements we have been creating to render the UI and let users interact with the applications we build. Usually, you wont need it, but if there are certain components where you want to override, or restrict the availability of a class or a service, you can specify an array of providers to a component using the viewProviders attribute. We will cover this in more depth later in this chapter. One interesting thing to note is that unlike AngularJS (1.x), the application Angular builds does not load the template by URL at runtime. We will cover some of the more useful attributes you can specify when creating components, how to think about the lifecycle of the component and the various hooks that Angular gives you, and finally, cover how to pass data into and out of your custom components. The finished example is available in the GitHub repository in the chapter4/component-input folder.