BUILDING ANGULAR

April 2017, Denko Mancheski

workshop #7

AGENDA

Bootstrapping

Component tree (smart and dumb components)

NgModule

Zone

Feature modules

JIT / AOT

 

BOotstrapping

To bootstrap an Angular app, we need a module. Since its the entry point of the app (or the first module), it is called "root module"

The root module must have a bootstrap property in which will be defined the first component. This component is the root component in the component tree

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule);
// module.ts
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import AppComponent from './app';

@NgModule({
  imports: [BrowserModule],
  declarations: [AppComponent],
  bootstrap: [AppComponent]
})
export class AppModule {}

Root module

Bootstrap

Component Tree

NgModule

An NgModule is a class adorned with the @NgModule decorator function. @NgModule takes a metadata object that tells Angular how to compile and run module code. It identifies the module's own components, directives, and pipes, making some of them public so external components can use them.@NgModule may add service providers to the application dependency injectors.

NgModules consolidate components, directives, and pipes into cohesive blocks of functionality, each focused on a feature area, application business domain, workflow, or common collection of utilities.

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }  from './app.component';

@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

Every Angular app has a root module class. By convention, the root module class is called AppModule

NgModule is used for bootstrapping

You launch the application by bootstrapping the AppModule in the main.ts file.

Dynamic bootstrapping with the just-in-time (JIT) compiler

Static bootstrapping with the ahead-of-time (AOT) compiler

Consider the static alternative which can produce a much smaller application that launches faster, especially on mobile devices and high latency networks.

Because the entire application was pre-compiled, Angular doesn't ship the Angular compiler to the browser and doesn't compile in the browser.

COMPILATION

An Angular application consists largely of components and their HTML templates. Before the browser can render the application, the components and templates must be converted to executable JavaScript by the Angular compiler.

JIT compilation incurs a runtime performance penalty. Views take longer to render because of the in-browser compilation step. The application is bigger because it includes the Angular compiler and a lot of library code that the application won't actually need. Bigger apps take longer to transmit and are slower to load.

Compilation can uncover many component-template binding errors. JIT compilation discovers them at runtime, which is late in the process.

You can compile the app in the browser, at runtime, as the application loads, using the just-in-time (JIT) compiler. This is the standard development approach shown throughout the documentation. It's great but it has shortcomings.

JIT

AOT

The ahead-of-time (AOT) compiler can catch template errors early and improve performance by compiling at build time.

 

Faster rendering

With AOT, the browser downloads a pre-compiled version of the application. The browser loads executable code so it can render the application immediately, without waiting to compile the app first.

Fewer asynchronous requests

The compiler inlines external HTML templates and CSS style sheets within the application JavaScript, eliminating separate ajax requests for those source files.

 

 

 

Smaller Angular framework download size

There's no need to download the Angular compiler if the app is already compiled. The compiler is roughly half of Angular itself, so omitting it dramatically reduces the application payload.

Detect template errors earlier

The AOT compiler detects and reports template binding errors during the build step before users can see them.

Better security

AOT compiles HTML templates and components into JavaScript files long before they are served to the client. With no templates to read and no risky client-side HTML or JavaScript evaluation, there are fewer opportunities for injection attacks.

future modules

When our root module start growing, it starts to be evident that some elements (components, directives, etc.) are related in a way that almost feel like they belong to a library that can be "plugged in".

What if we extract these three elements to their own feature module and then we import it into our root module?

Warning: When it comes to components, pipes and directives, every module should import its own dependencies disregarding if the same dependencies were imported in the root module or in any other feature module. In short, even when having multiple feature modules, each one of them needs to import the CommonModule

Services and Lazy Loaded Modules

Not this time :)

SMART / DUMB components

how do we structure our application ?

  • what types of components are there?
  • how should components interact ?
  • should I inject services into any component ?
  • how do I make my components reusable across views ?

smart (container) components

Smart / Container components are application-specific, higher-level, container components with access to the application's domain model

DUMB (Presentational) components

Dumb / Presentational components are components responsible for UI rendering and/or behavior of specific entities passed in via components API (i.e. component properties and events). Those components are more in-line with the upcoming Web Component standard

@Component({
  selector: 'app-home',
  template: `
    <h2>All Lessons</h2>
    <h4>Total Lessons: {{lessons?.length}}</h4>
    <div class="lessons-list-container v-h-center-block-parent">
        <table class="table lessons-list card card-strong">
            <tbody>
            <tr *ngFor="let lesson of lessons" (click)="selectLesson(lesson)">
                <td class="lesson-title"> {{lesson.description}} </td>
                <td class="duration">
                    <i class="md-icon duration-icon">access_time</i>
                    <span>{{lesson.duration}}</span>
                </td>
            </tr>
            </tbody>
        </table>
    </div>
`,
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  lessons: Lesson[];

  constructor(private lessonsService: LessonsService) {
  }

  ngOnInit() {
      this.lessonsService.findAllLessons()
          .do(console.log)
          .subscribe(
              lessons => this.allLessons = lessons
          );
  }
  ...
}

Significant size already

No re-usability

Lack of generics

Lack of separation

Lack of maintainability

The problem:

Scenarios:

What if we want to display specific lessons for some course ?

What if we want to use the list of lessons somwehere else ?

import {Component, OnInit, Input, EventEmitter, Output} from '@angular/core';
import {Lesson} from "../shared/model/lesson";

@Component({
  selector: 'lessons-list',
  template: `
      <table class="table lessons-list card card-strong">
          <tbody>
          <tr *ngFor="let lesson of lessons" (click)="selectLesson(lesson)">
              <td class="lesson-title"> {{lesson.description}} </td>
              <td class="duration">
                  <i class="md-icon duration-icon">access_time</i>
                  <span>{{lesson.duration}}</span>
              </td>
          </tr>
          </tbody>
      </table>  
  `,
  styleUrls: ['./lessons-list.component.css']
})
export class LessonsListComponent {

  @Input()
  lessons: Lesson[];

  @Output('lesson')
  lessonEmitter = new EventEmitter<Lesson>();

    selectLesson(lesson:Lesson) {
        this.lessonEmitter.emit(lesson);
    }

}
  

Pros:

  • The component doesnt know where the lessons come from
  • the lessons might be a list of all lessons available
  • or the lessons might be a list of all the lessons of a given course
  • or even the lessons might be a page in any given list of a search

We could reuse this component in all of these scenarios, because the lessons list component does not know where the data comes from. The responsibility of the component is purely to present the data to the user and not to fetch it from a particular location.

Conclusion:

= Dumb (presentational) component

import { Component, OnInit } from '@angular/core';
import {LessonsService} from "../shared/model/lessons.service";
import {Lesson} from "../shared/model/lesson";

@Component({
  selector: 'app-home',
  template: `
      <h2>All Lessons</h2>
      <h4>Total Lessons: {{lessons?.length}}</h4>
      <div class="lessons-list-container v-h-center-block-parent">
          <lessons-list [lessons]="lessons" (lesson)="selectLesson($event)"></lessons-list>
      </div>
`,
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

    lessons: Lesson[];

  constructor(private lessonsService: LessonsService) {
  }

  ngOnInit() {
     ...
  }

  selectLesson(lesson) {
    ...
  }

}
  • The home component still knows how to retrieve the lessons list from a service, and what type of list this is (if these lessons are the lessons of a course, etc.).
  • But the Home component does not know how to present the lessons to the user.

Pros

Text

Conclusion

This type of component is inherently tied to the application itself, so as we can see it receives in the constructor some dependencies that are application-specific, like the LessonsService. It would be very hard to use this component in another application.

The top level component of our view will likely always be a smart component.

Interaction between smart and dumb components

@Input() and @Output()

BUT, the thing is, its sometimes not that simple because custom events like lesson don't bubble up. So if for example you have a deep tree of components and you want a component multiple levels above to know about the event, the event will not bubble. What if we nest components deeper than 1 level ?

Hello Services 


@Injectable()
export class LessonSelectedService {

    private _selected: BehaviorSubject<Lesson> = new BehaviorSubject(null);

    public selected$ = this._selected.asObservable().filter(lesson => !!lesson);
    
    
    select(lesson:Lesson) {
         this._selected.next(lesson);
    }

}

http://blog.angular-university.io/angular-2-smart-components-vs-presentation-components-whats-the-difference-when-to-use-each-and-why/

ZONE.js

Definition: an execution context for asynchronous operations. They turn out to be really useful for things like error handling and profiling. But what exactly does that mean?

Zone.js helps Angular to be aware of the things which are executed in the app, in order to update the view automatically. The main usage of zone.js in Angular is for the Change Detection mechanism

A Zone is an execution context that persists across async tasks. You can think of it as thread-local storage for JavaScript VMs.

Conclusion: So, without zones, we don’t get any change detection, so we don’t get any of the nice UI updates that we’d expect!

THANK YOU

denkomanceski@gmail.com

Made with Slides.com