Author Archives: admin

Angular 2 – Handling forms

  • Regarding forms, what Angular does for us is giving us a object representation of the form in order to handle fetching data and form validation.
  • And also we will be able to handle form submit without reloading the page (as it is a SPA).

Captura de pantalla 2017-05-10 a las 9.30.46

Two approaches

  • There are two ways of handling forms with Angular. With Template -driven we will resolve most of the cases, but with the Reactive approach you will have full control of the form and it is useful for advanced cases.
  • In Template-driven approch we code all the logic in the template.

Captura de pantalla 2017-05-10 a las 9.35.14

TD: Creating the form and registering controls

  • We need to import FormModule in the app.module.ts

app.module.ts

import { FormsModule } from '@angular/forms';
...

imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  • Angular will detect form tags in your html to create the javascript representation, but we still need to indicate what controls of the form we want to manage. We get that with ngModel directive and giving a “name” attribute to the control. That name we will use it to fetch the value of that control,
            <input
              type="email"
              id="email"
              class="form-control"
              ngModel
              name="email">
  • Submit of the form managed by Angular is done by adding ngSubmit directive to the form tag and specifying the handler method. Otherwise the default behaviour will take place.
<form (ngSubmit)="onSubmit()">
  • With the ngForm directive we finally get the desired javascript representation of our form
<form (ngSubmit)="onSubmit(f)" #f="ngForm">
import { NgForm } from '@angular/forms';

 ...
 onSubmit(form: NgForm) {
    console.log('submitted!', form);
  }

Captura de pantalla 2017-05-10 a las 10.31.05

  • There are useful properties in NgForm object:
    • controls: what control we registered
    • dirty: flag to indicate of something changed
    • disabled
    • enabled
    • valid
    • invalid
    • touched
  • We also can use ViewChild annotation to get reference of a template reference and get form reference:
<form (ngSubmit)="onSubmit()" #f="ngForm">
@ViewChild('f') signupForm: NgForm;
...
onSubmit() {
 console.log('submitted!', this.signupForm);
 }

TD: Adding validation to check user input

  • In template driven forms we can add some validation in the tags. For example, we will add required to username input and required and email validation to email input:
               <input
              type="text"
              id="username"
              class="form-control"
              ngModel
              name="username"
              required>
...
             <input
              type="email"
              id="email"
              class="form-control"
              ngModel
              name="email"
              required
              email>
  • in the NgForm object submitted we will get the valid flag of the form and of the individuals controls set to true/false as a result of validation. What Angular does behind the scenes is adding some control classes to the DOM inputs, such as ‘ng-valid’ , ‘ng-touched’, etc

Built-in Validators & Using HTML5 Validation

Which Validators do ship with Angular?

Check out the Validators classhttps://angular.io/docs/ts/latest/api/forms/index/Validators-class.html – these are all built-in validators, though that are the methods which actually get executed (and which you later can add when using the reactive approach).

For the template-driven approach, you need the directives. You can find out their names, by searching for “validator” in the official docshttps://angular.io/docs/ts/latest/api/#!?query=validator – everything marked with “D” is a directive and can be added to your template.

Additionally, you might also want to enable HTML5 validation (by default, Angular disables it). You can do so by adding the ngNativeValidate  to a control in your template.

 

TD: Using the Form State

  • Lets disable the submit button on false validation (using the form local reference ‘f’):
<button 
        class="btn btn-primary"
        type="submit"
        [disabled]="!f.valid">Submit</button>
  • Also we would like to render in red invalid inputs on validation checks. We will use Angular classes:

app.component.css

input.ng-invalid.ng-touched {
  border: 1px solid red;
}

TD: Outputting validation error messages

  • Lets add a validation message for the email input using a local reference for the email input:
<input
              type="email"
              id="email"
              class="form-control"
              ngModel
              name="email"
              required
              email
              #email="ngModel">
            <span class="help-block" *ngIf="!email.valid && email.touched">Please select a valid email!</span>

TD: Setting default values with ngModel property binding

  • We want in the elect input set “pet” ad the default value. We use property binding in the ngModel directive.

app.component.ts

  defaultQuestion = "pet";

app.component.html

<select
            id="secret"
            class="form-control"
            [ngModel]="defaultQuestion"
            name="secret">
            <option value="pet">Your first Pet?</option>
            <option value="teacher">Your first teacher?</option>
          </select>

TD: Using ngModel with Two-Way Binding

  • Sometimes you want to react to changes in the input , so you need 2-way binding.
  • It is the case when some element in the template depends on other element. In this example we will print what user input in a textarea:

app.component.html

        <div class="form-group">
          <textarea name="questionAnswer" rows="10"
            class="form-control"
            [(ngModel)] = "answer">
          </textarea>
          <p>Yout reply is {{answer}}</p>
        </div>

app.component.ts

  answer='';
  • We get the value in the NgForm in the typescript and also in the template

TD: Grouping form controls

  • We can group some form controls under a same javascript object and be as another form control for checking engine. For example let group user data :
<form (ngSubmit)="onSubmit()" #f="ngForm">
        <div id="user-data"
        ngModelGroup="userData"
        #userData="ngModelGroup">
...
        <p *ngIf="!userData.valid && userData.touched">User data is not valid!</p>

TD: Handling Radio Buttons

          <div class="radio" *ngFor="let gender of genders">
            <label for="">
              <input type="radio"
                name="gender"
                id="gender_{{gender}}"
                ngModel
                [value]="gender"
                required>
                {{gender}}
            </label>
          </div>

app.component.ts

  genders= ['male', 'female'];

TD: Setting and patching form values

  • We can set the whole form to some value with two methods: setValue and patchValue
  • With setValue we overwrite the whole form. For example let set the form on clicking in the suggested user button:

app.component.html

          <button class="btn btn-default" type="button" (click)="suggestUserName()">Suggest an Username</button>

app.component.ts

  suggestUserName() {
    const suggestedName = 'Superuser';
    this.signupForm.setValue({
        userData: {
          username: suggestedName,
          email:''
        },
        secret:'pet',
        questionAnswer:'',
        gender:'male'
    });
  }
  • With patchValue on the form property of the NgForm object we don’t touch other values in the form , only the specified ones:
    this.signupForm.form.patchValue({
        userData: {
          username: suggestedName,
        },
        gender:'male'
    });

TD: Using form data

  • We will print out the information user input on submission:

app.component.html

  <div class="row" *ngIf="submitted">
    <div class="col-xs-12">
      <h2>Your submitted data is:</h2>
      <ul>
        <li>Username: {{user.username}}</li>
        <li>Email: {{user.email}}</li>
        <li>Gender: {{user.gender}}</li>
        <li>Secret question: {{user.secret}}</li>
      </ul>
    </div>
  </div>

app.component.ts

  user = {
    name: '',
    email: '',
    gender: '',
    secret: '',
  };

...

  onSubmit() {
    console.log('submitted!', this.signupForm);
    this.submitted = true;
    this.user.name = this.signupForm.value.userData.username;
    this.user.email = this.signupForm.value.userData.email;
    this.user.gender = this.signupForm.value.gender;
    this.user.secret = this.signupForm.value.secret;
  }

TD: Resetting forms

this.signupForm.reset();
  • You can also pass values to reset method to reset to specific values.

 

Angular 2 – Observables

  • Observables are another way of handling async tasks. Angular2 use them a lot.
  • Usually are objects wrapping some data source which emits events, such as button clicks , https requests, etc.

Captura de pantalla 2017-05-09 a las 17.51.10

Analyzing a Built in observable

  • We already used observables when subscribing to changes int the route params:
    this.route.params.subscribe(
      (params: Params)=> {
        this.id = +params['id'];
        this.editMode = !isNaN(this.id);
      }
    );

Building and using a first simple Observable

  • We will make a observable which print a number in the console every second.
  • This is a built-in utility in rxjs package
...
import { Observable } from 'rxjs/Observable';
import 'rxjs/Rx';
  ...
ngOnInit() {
    const myNumbers = Observable.interval(1000);
    myNumbers.subscribe(
      (number: number) => {
        console.log(number);
      }
    );
  }

Building and using a custom observable from scratch

  • Let make a custom observable which prints to console after 2 seconds , 4 seconds and complete on five seconds.
    const myObservable = Observable.create((observer: Observer<string>) => {
      setTimeout(()=> {
        observer.next('first package');
      },2000);
      setTimeout(()=> {
        observer.next('second package');
      },4000);
      // setTimeout(()=> {
      //   observer.error('error ocurred!');
      // },5000);
      setTimeout(()=> {
        observer.complete();
      },5000);
      setTimeout(()=> {
        observer.next('third package');
      },6000);
    });

    myObservable.subscribe(
      (data:string)=> { console.log(data); },
      (error:string)=> { console.log(error); },
      ()=> { console.log('completed'); },
    );

NOTE: third package is not printed because it is emitted after observable is completed (dead).

Unsubscribe!

  • We must not forget clean up our subscriptions on leaving the component. Otherwise we could lead to a memory leak. We will do it in the destroy lifecycle method.
...
  subscription1: Subscription;
  subscription2: Subscription;
...
    this.subscription1 = myNumbers.subscribe(
      (number: number) => {
        console.log(number);
      }
    );

    this.subscription2 = myObservable.subscribe(
      (data:string)=> { console.log(data); },
      (error:string)=> { console.log(error); },
      ()=> { console.log('completed'); },
    );
...
  ngOnDestroy() {
    this.subscription1.unsubscribe();
    this.subscription2.unsubscribe();
  }
...

Where to learn more

Using Subject to pass and listen to data

  • Subject is a object from Rxjs package that is Observable and Observer at the same instance.
  • It is very useful in cross component communication instead of emit events

user.service.ts

import {Subject} from 'rxjs/Subject';
...
export class UsersService {
  userActivated = new Subject();
...

app.component.html

      <hr>
      <h4>Using Subjects (from RxJs)</h4>
      <p>
        User is {{userActivated? '(activated)':''}}
        <button (click)="onActivate()">Activate user</button>
      </p>

app.component.ts

...
  userActivated = false;

  constructor(
     private usersService: UsersService ,
...
  ngOnInit() {

    this.subscription3 = this.usersService.userActivated.subscribe(
      (text: string)=> {
        if(text) {
          this.userActivated = true;
        }
    });
...
  onActivate() {
    this.usersService.userActivated.next('dfdfdfd');
  }

Understanding observable operators

  • Observable operators return observables , so you can chain them.
  • In http://reactivex.io/rxjs/ , in the Observable object you can check all operators available.
  • Lets make an example using map operator to print double numbers in the console
    const myNumbers = Observable.interval(1000).map(
      (data:number)=>{
        return data*2;
      }
    );

ds

ds

ds

d

sd

Angular 2 – Routing

Setting up and loading routes

  • We set up two routes:
    • http://localhost:4200/page1
    • http://localhost:4200/page2

app.module.ts

import { Routes, RouterModule } from '@angular/Router';
import { Page1Component } from './page1/page1.component';
import { Page2Component } from './page2/page2.component';

const appRoutes: Routes = [
  // { path: '', Page1Component},
  { path: 'page1', component: Page1Component},
  { path: 'page2', component: Page2Component}
];

...
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    RouterModule.forRoot(appRoutes)
  ],

...

app.component.html

      <router-outlet></router-outlet>

Navigating with Router links

  • Using routerLink directive we avid reloading of the page

app.component.html

<h5>Routing</h5>
 <ul class="nav nav-tabs">
 <li role="presentation" class="active"> <a routerLink="/">Home</a></li>
 <li role="presentation"> <a routerLink="/page1">Page 1</a></li>
 <li role="presentation"> <a [routerLink]="['/page2']">Page 2</a></li>
 </ul>
 ...
 
 <router-outlet></router-outlet>

Understanding navigation paths

  • In routerLinks we can define relative paths to current path:
    <a routerLink="page1">Page 1</a>
  • or absolute paths: 
    <a routerLink="/page1">Page 1</a>
  • or navigate as a folder structure:
    <a routerLink="../page1">Page 1</a>

Styling Active Router Links

      <ul class="nav nav-tabs">
        <li role="presentation" routerLinkActive="active" [routerLinkActiveOptions]="{exact: true}"> <a routerLink="/">Home</a></li>
        <li role="presentation" routerLinkActive="active"> <a routerLink="/page1">Page 1</a></li>
        <li role="presentation" routerLinkActive="active"> <a [routerLink]="['/page2']">Page 2</a></li>
      </ul>

Loading routes programmatically

import { Router } from '@angular/Router';
...
goto(target) {
   this.router.navigate([target]);
 }

using relative paths with navigation method:

constructor(private route: ActivatedRoute , private router: Router){}
...
this.router.navigate([target], {relativeTo: this.route});

Passing parameters to routes

app.module.ts

const appRoutes: Routes = [
 // { path: '', Page1Component},
 { path: 'page1', component: Page1Component},
 { path: 'page2', component: Page2Component},
 { path: 'page2/:id/:name', component: Page2Component}
];

page2.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/Router';
@Component({
 selector: 'app-page2',
 templateUrl: './page2.component.html',
 styleUrls: ['./page2.component.css']
})
export class Page2Component implements OnInit {

user: {id: number , name: string};

constructor(private route: ActivatedRoute) { }

ngOnInit() {
 this.user = {
 id: this.route.snapshot.params['id'],
 name: this.route.snapshot.params['name']
 };
 }
}

Subscribing to changes in the route params

this.route.params.subscribe(
 (params: Params) => {
 this.user.id = params.id;
 this.user.name = params.name;
 }
 );

NOTE: The subscription on the params will remain while we are in teh page2 component; Angular2 will automatically remove the subscription on destroy of the component. Just in case you need to unsubscribe for observables we show yo what angular does:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute, Params } from '@angular/Router';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'app-page2',
  templateUrl: './page2.component.html',
  styleUrls: ['./page2.component.css']
})
export class Page2Component implements OnInit, OnDestroy{

  user: {id: number , name: string};
  paramsSubscription: Subscription;

  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    this.user = {
      id: this.route.snapshot.params['id'],
      name: this.route.snapshot.params['name']
    };

    this.paramsSubscription = this.route.params.subscribe(
      (params: Params) => {
        this.user.id = params['id'];
        this.user.name = params['name'];
      }
    );
  }

  ngOnDestroy() {
    this.paramsSubscription.unsubscribe();
  }

}

Passing Query Parameters and Fragments

  • From the html, this code
<a
  [routerLink]="['/page2']"
  [queryParams]="{allowEdit: '1', otro: 'jaja'}"
  fragments="myfragment">
    Navigate to Page2 with query params and fragments
</a>

will go to http://localhost:4200/page2?allowEdit=1&otro=jaja

  • From the typescript code:
  gotoWithQueryParamsAndFragments(target) {
    this.router.navigate([target], {relativeTo: this.route, queryParams: {allowEdit:'1'}, fragment: 'myfragment'});
  }

it will go to http://localhost:4200/page2?allowEdit=1#myfragment

  • For retrieving them:
console.log('Init page 2 queryParams and fragments', this.route.snapshot.queryParams, this.route.snapshot.fragment);

and also , as  they are observables we can subscribe to their changes.

NOTE: To convert a string into a number there is a sneaky way: to prepend a ‘+’ operator:

> +'42'
42

Setting up nested routes

  • We set up ‘/page2/nested’ route. This route will be child of /page2 and in the page 2 html we insert “router-outlet” to nest this child views.

app.module.ts

const appRoutes: Routes = [
  // { path: '', Page1Component},
  { path: 'page1', component: Page1Component},
  { path: 'page2', component: Page2Component, children: [
    { path: 'nested', component: NestedComponent}
  ]},
  { path: 'page2/:id/:name', component: Page2Component}

];

page2.component.html

<p>
  page2 works!
</p>
<p>
  User Id: {{user.id}}
</p>
<p>
  User name: {{user.name}}
</p>

<p>
  <a [routerLink]="['/page2', '23', 'INDIRA']">Navigate to Page2/23/INDIRA</a>
</p>

<p>
<a
  [routerLink]="['/page2']"
  [queryParams]="{allowEdit: '1', otro: 'jaja'}"
  fragments="myfragment">
    Navigate to Page2 with query params and fragments
</a>
</p>

<hr>
Nested routes under page2
<router-outlet></router-outlet>

Preserve query parameters on navigation to other route

    this.router.navigate([target], {relativeTo: this.route, queryParamsHandling: 'preserve'});

Redirecting and wildcard routes

We want redirect /page3 to /not-found

and we want to get all unknown routes to /not-found

app.module.ts

const appRoutes: Routes = [
  // { path: '', Page1Component},
  { path: 'page1', component: Page1Component},
  { path: 'page2', component: Page2Component, children: [
    { path: 'nested', component: NestedComponent}
  ]},
  { path: 'page2/:id/:name', component: Page2Component},
  { path: 'not-found', component: PageNotFoundComponent},
  { path: 'page3', redirectTo: '/not-found'},
  { path: '**', redirectTo: '/not-found'}

];

NOTE: the wildcard rule is evaluated at the end because it is in the bottom of the rules. If we put it at the top , all routes will go to not-found.

NOTE 2: Important: Redirection Path Matching
 

In our example, we didn’t encounter any issues when we tried to redirect the user. But that’s not always the case when adding redirections.

By default, Angular matches paths by prefix. That means, that the following route will match both /recipes  and just /

{ path: '', redirectTo: '/somewhere-else' }

Actually, Angular will give you an error here, because that’s a common gotcha: This route will now ALWAYS redirect you! Why?

Since the default matching strategy is "prefix" , Angular checks if the path you entered in the URL does start with the path specified in the route. Of course every path starts with ''  (Important: That’s no whitespace, it’s simply “nothing”).

To fix this behavior, you need to change the matching strategy to"full" :

{ path: '', redirectTo: '/somewhere-else', pathMatch: 'full' }

Now, you only get redirected, if the full path is ''  (so only if you got NO other content in your path in this example).

Outsourcing the router configuration

  • We will get out route configuration from app.module.ts to a proper module:

app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/Router';

import { Page1Component } from './page1/page1.component';
import { Page2Component } from './page2/page2.component';
import { PageNotFoundComponent } from './page-not-found/page-not-found.component';
import { NestedComponent } from './nested/nested.component';

const appRoutes: Routes = [
  // { path: '', Page1Component},
  { path: 'page1', component: Page1Component},
  { path: 'page2', component: Page2Component, children: [
    { path: 'nested', component: NestedComponent}
  ]},
  { path: 'page2/:id/:name', component: Page2Component},
  { path: 'not-found', component: PageNotFoundComponent},
  { path: 'page3', redirectTo: '/not-found'},
  { path: '**', redirectTo: '/not-found'}

];

@NgModule({
  imports: [
    RouterModule.forRoot(appRoutes)
  ],
  exports: [RouterModule]

})
export class AppRoutingModule {
}

app.module.ts

...
import { AppRoutingModule } from './app-routing.module';
...

  imports: [
    BrowserModule,
    FormsModule,
    HttpModule,
    AppRoutingModule
  ],

...

Protecting Routes with canActivate

  • We want to protect some routes to only logged in users. We will use what Angular calls guards. 
  • They are some services which are called before some routes we set up to.
  • We will simulate an AuthService to loggin in /out

app-routing.module.ts

const appRoutes: Routes = [
  { path: '', component: Page1Component},
  { path: 'page1', component: Page1Component},
  { path: 'page2', canActivate: [AuthGuard], component: Page2Component, children: [
    { path: 'nested', component: NestedComponent}
  ]},
  { path: 'page2/:id/:name', canActivate: [AuthGuard], component: Page2Component},
  { path: 'not-found', component: PageNotFoundComponent},
  { path: 'page3', redirectTo: '/not-found'},
  { path: '**', redirectTo: '/not-found'}

];

auth-guard.service.ts

import {Injectable} from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot,Router } from '@angular/Router';
import {Observable} from 'rxjs/Observable';

import { AuthService } from './auth.service';

@Injectable()
export class AuthGuard implements CanActivate {

  constructor(private authService: AuthService, private router: Router) {}

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return this.authService.isAuthenticated().
    then((authenticated: boolean)=> {
      if(authenticated) {
        return true;
      } else {
        this.router.navigate(['/']);
      }
    });
  }

}

auth.service.ts

export class AuthService {
  loggedIn = false;

  isAuthenticated() {
    const promise = new Promise((resolve,reject)=> {
      setTimeout(()=> {
        resolve(this.loggedIn);
      },800);

    });

    return promise;
  }

  login() {
    this.loggedIn = true;
  }

  logout() {
    this.loggedIn = false;
  }
}

With canActivateChild interface we can protect only the children of a route

Controlling navigation with canDeactivate

  • We will control when leaving /page route with some change to get confirmation from user with a javascript confirm

/page1/can-deactivate-guard.service.ts

import { Observable } from 'rxjs/Observable';
import { CanDeactivate, ActivatedRouteSnapshot , RouterStateSnapshot } from '@angular/router';

export interface CanComponentDeactivate {
  canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}

export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
  canDeactivate(component: CanComponentDeactivate,
                currentRoute: ActivatedRouteSnapshot,
                currentState: RouterStateSnapshot,
                nextState?: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    return component.canDeactivate();
  }
}

app.routing.module.ts

  ...
{ path: 'page1', component: Page1Component, canDeactivate: [CanDeactivateGuard]},
...

/page1/page1.component.ts

...
export class Page1Component implements OnInit, CanComponentDeactivate {
...
  canDeactivate(): Observable<boolean> | Promise<boolean> | boolean {
    console.log('JESSSS confirmLeavingValue', this.confirmLeavingValue);
    if(!this.confirmLeavingValue){
      return true;
    } else {
      return confirm('Do u want to discard the changes?');
    }
  }

app.module.ts

...
  providers: [AccountsService, LoggingService, CounterService , UsersService, AuthService, AuthGuard, CanDeactivateGuard],
...

Passing static data to a Route

  • We want to have a error page generic for any type of error.
  • And we pass the message to show by static data in the route.

app-routing.module.ts

...
{ path: 'not-found', component: ErrorPageComponent, data: {errorMessage: 'Page not found'}},
 // { path: 'not-found', component: PageNotFoundComponent},
...

error-page.component.ts

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Data } from '@angular/Router';

@Component({
  selector: 'app-error-page',
  templateUrl: './error-page.component.html',
  styleUrls: ['./error-page.component.css']
})
export class ErrorPageComponent implements OnInit {

  errorMessage: string;
  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    this.errorMessage = this.route.snapshot.data['errorMessage'];
    this.route.data.subscribe(
      (data: Data)=> {
        this.errorMessage = data['errorMessage'];
      }
    );
  }

}

error-page.component.html

<h3> {{ errorMessage }}</h3>

Resolving dynamic data with the resolve guard

  • On page2/nested route we will simulate resolve data (a Server data) from a promise before nested component is loaded

example-resolver.service.ts

import {Resolve} from '@angular/Router';
import {Injectable} from '@angular/core';
import {Observable} from 'rxjs/Observable';

interface Server {
  id: number;
  name: string;
  status: string;
}

@Injectable()
export class ExampleResolver implements Resolve<Server> {

  constructor() {}

  resolve(): Observable<Server> | Promise<Server> | Server {

    return new Promise((resolve, reject) => {
      setTimeout(function(){
        resolve({
          id:1,
          name:'Señor potato',
          status:'single'
        });
      }, 250);
    });

  }

}

app-routing.module.ts

{ path: 'nested', component: NestedComponent, resolve: {server: ExampleResolver}}

nested.component.ts

import { Component, OnInit } from '@angular/core';

import {ActivatedRoute, Data} from '@angular/Router';

@Component({
  selector: 'app-nested',
  templateUrl: './nested.component.html',
  styleUrls: ['./nested.component.css']
})
export class NestedComponent implements OnInit {

  server: {id:number , name:string, status:string};

  constructor(private route:ActivatedRoute) { }

  ngOnInit() {
    this.route.data.subscribe(
      (data: Data) => {
        this.server = data['server'];
      }
    );
  }

}

nested.component.html

  <h4>Server</h4>
  <ul>
    <li>Id: {{ server.id }}</li>
    <li>Name: {{ server.name }}</li>
    <li>Status: {{ server.status }}</li>
  </ul>

Understanding Location strategies

  • Routes like ‘/page1’ or ‘/page2’ wont work on real web servers , they will get not found error because the server will look for page 1 or page 2 folder.
  • There is a chance to use hash mode (http://localhost:4200/#/page2) in the routes of our app:

app-routing.module.ts

@NgModule({
  imports: [
    RouterModule.forRoot(appRoutes, {useHash: true})
  ],
  exports: [RouterModule]

})

dfd

fd

fd

fd
gfgfd

 

fdf

df

df

df

df

d

Angular 2 – Using services and dependency injection

Injecting a custom service into components

  • A Service is created when we need a centralized component which serves some functionality to multiple components. Also we would expect to be a singleton instance.

app.component.html

      <button type="button" (click)="testLoggingService('one')" name="button">Test Logging Service One</button>
      <button type="button" (click)="testLoggingService('two')" name="button">Test Logging Service Two</button>

app.component.ts

import { Component } from '@angular/core';
import { LoggingService } from './logging.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [LoggingService]
})
export class AppComponent {
  myCondition = true;
  value=10;

  constructor(private LoggingService: LoggingService){}
  testLoggingService(msg) {
    this.LoggingService.logStatusChange(msg);
  }
}

logging.service.ts

export class LoggingService {
  logStatusChange(status: string) {
    console.log('A server JAJAJA JIJIJIJ JOJOJOJ' + status);
  }
}

Angular has a Hierarchical Injector for dependencies:

Captura de pantalla 2017-04-28 a las 11.41.31

WARNING: If we declare in [providers] a service in a child component which is declared in the parent component, we are overwritting the parent one , so they are two different instances.

For using a service declared in the parent component we still need to define it as a parameter in the constructor but we don’t need to declare it in the [providers] decorator.

The highest level to declare a dependency is in the AppModule.

Injecting Services into Services

  • We inject both services into AppModule.

app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { BasicHighlightDirective } from './basic-highlight.directive';
import { BetterHighlightDirective } from './better-highlight.directive';
import { UnlessDirective } from './unless.directive';
import { AccountsService } from './accounts.service';
import { LoggingService } from './logging.service';

@NgModule({
  declarations: [
    AppComponent,
    BasicHighlightDirective,
    BetterHighlightDirective,
    UnlessDirective
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [AccountsService, LoggingService],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.html

      <button type="button" (click)="addAccount()" name="button">Add Account</button>
      <button type="button" (click)="removeAccount()" name="button">Remove Account</button>
      <ul>
       <li *ngFor="let account of accounts">Account #{{account.id}}</li>
      </ul>

app.component.ts

import { Component } from '@angular/core';
import { AccountsService } from './accounts.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  myCondition = true;
  value=10;
  accounts = this.AccountsService.accounts;

  constructor(private AccountsService: AccountsService){}
  addAccount() {
    this.AccountsService.addAccount();
  }
  removeAccount() {
    this.AccountsService.removeAccount();
  }
}

accounts.service.ts

import { Injectable } from '@angular/core';
import { LoggingService } from './logging.service';

@Injectable()
export class AccountsService {
  accounts = [];

  constructor(private logginService: LoggingService){}

  addAccount() {
    const newId = this.accounts.length;
    this.accounts.push({
      date: new Date().getTime(),
      id: newId
    });
    this.logginService.log('Account #' + newId + ' added!');
  }

  removeAccount() {
    this.accounts.splice(this.accounts.length-1,1);
    this.logginService.log('Account removed!');
  }
}

Cross Components Communication using services

accounts.service.ts

...
  sendMessage = new EventEmitter<string>();
...

component-one.component.ts

...
  constructor(private accountsService: AccountsService) { }
...

  emitEvent() {
    this.accountsService.sendMessage.emit('Hola caracola!!');
  }

component-one.component.html

<p>
  <button type="button" (click)="emitEvent()" name="button">Component One emits event to Component Two</button>
</p>

component-two.component.ts

import { Component, OnInit } from '@angular/core';
import { AccountsService } from '../accounts.service';

@Component({
  selector: 'app-component-two',
  templateUrl: './component-two.component.html',
  styleUrls: ['./component-two.component.css']
})
export class ComponentTwoComponent implements OnInit {

  receivedMsg:string = 'No message received yet';

  constructor(private accountsService: AccountsService) {
    this.accountsService.sendMessage.subscribe(
      (message: string) => {
        this.receivedMsg = message;
      }
    );
  }

  ngOnInit() {
  }

}

component-two.component.html

<p>
  Component Two receives event --> Message:{{receivedMsg}}
</p>

ds

dsd

sd

sd

sd

sd

sds

f

Angular 2 – Directives Deep dive

Attribute vs Structural Directives

  • In attribute directives you never modify the DOM structure , just change some behaviour in the element where it is added to. I looks like a normal HTML attribute (with databinding or property binding).
  • In Structural directives the DOM is modified. It also looks like a normal HTML attribute but it has a leading *. Affects the whole area in the DOM (elements get added / removed)

Creating a custom directive

app.component.html

<p appBasicHighlight>this is a basic highlight test</p>

basic-highlight.directive.js

import { Directive, ElementRef, OnInit } from '@angular/core';

@Directive({
  selector: '[appBasicHighlight]'
})
export class BasicHighlightDirective implements OnInit {

  constructor(private elementRef: ElementRef) { }

  ngOnInit() {
    this.elementRef.nativeElement.style.backgroundColor = 'green';
  }

}

Shortcut on ng cli to create a directive:

ng g d basic-highlight

Using the Renderer to build a better attribute directive

The problem with the former approach is that when we access the native element directly we are giving up on Angular’s DOM abstraction and miss out on the opportunity to be able to execute also in none-DOM environments such as: native mobile, native desktop, web worker or server side rendering.

Remember that Angular is a platform, and the browser is just one option for where we can render our app.

So what you do is to give this responsibility to the Renderer class.

better-highlight.directive.ts

import { Directive, Renderer2, OnInit, ElementRef } from '@angular/core';

@Directive({
  selector: '[appBetterHighlight]'
})
export class BetterHighlightDirective implements OnInit {

  constructor(private elRef: ElementRef, private renderer: Renderer2) { }

  ngOnInit() {
    this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
  }
}

Using HostListener to listen directive events

better-highlight.directive.ts

import { Directive, Renderer2, OnInit, ElementRef, HostListener } from '@angular/core';

@Directive({
  selector: '[appBetterHighlight]'
})
export class BetterHighlightDirective implements OnInit {

  constructor(private elRef: ElementRef, private renderer: Renderer2) { }

  ngOnInit() {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
  }

  @HostListener('mouseenter') mouseenter() {
    this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
  }
  @HostListener('mouseleave') mouseleave() {
    this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'transparent');
  }
}

Using HostBinding to Bind to element properties

better-highlight.directive.ts

import { Directive, Renderer2, OnInit, ElementRef, HostListener, HostBinding } from '@angular/core';

@Directive({
  selector: '[appBetterHighlight]'
})
export class BetterHighlightDirective implements OnInit {

  @HostBinding('style.backgroundColor') backgroundColor: string = 'transparent';

  constructor(private elRef: ElementRef, private renderer: Renderer2) { }

  ngOnInit() {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
  }

  @HostListener('mouseenter') mouseenter() {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
    this.backgroundColor = 'blue';
  }
  @HostListener('mouseleave') mouseleave() {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'transparent');
    this.backgroundColor = 'transparent';
  }
}

Binding to directive properties

better-highlight.directive.ts

import { Directive,
  Renderer2,
  OnInit,
  Input,
  ElementRef,
  HostListener,
  HostBinding } from '@angular/core';

@Directive({
  selector: '[appBetterHighlight]'
})
export class BetterHighlightDirective implements OnInit {

  @Input() defaultColor: string = 'transparent';
  @Input() highlightColor: string = 'blue';

  @HostBinding('style.backgroundColor') backgroundColor: string = 'transparent';

  constructor(private elRef: ElementRef, private renderer: Renderer2) { }

  ngOnInit() {
    this.renderer.setStyle(this.elRef.nativeElement, 'background-color', this.defaultColor);
  }

  @HostListener('mouseenter') mouseenter() {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'blue');
    this.backgroundColor = this.highlightColor;
  }
  @HostListener('mouseleave') mouseleave() {
    // this.renderer.setStyle(this.elRef.nativeElement, 'background-color', 'transparent');
    this.backgroundColor = this.defaultColor;
  }
}

app-component.html

      <p appBetterHighlight [defaultColor]="'yellow'" [highlightColor]="'red'" >this is a Better highlight test</p>

Structural directives: What happens behind the scenes

  • For example *ngIf directive it is translated in a ng-template with ngIf attribute behind the scenes:
<div *ngIf="condition"> ... </div>
<ng-template [ngIf]="condition"></ng-template>

Building a custom structural directive

unless.directive.ts

import { Directive, Input, TemplateRef, ViewContainerRef} from '@angular/core';

@Directive({
  selector: '[appUnless]'
})
export class UnlessDirective {

  @Input() set appUnless(condition: boolean) {
    if(condition) {
      this.vcRef.createEmbeddedView(this.templateRef);
    } else {
      this.vcRef.clear();
    }

  }
  constructor(private templateRef: TemplateRef<any>, private vcRef: ViewContainerRef) { }

}

app.component.html

      <p *appUnless="myCondition">Hola caracola (custom structural directive)</p>

Undestanding ngSwitch

      <div [ngSwitch]="value">
        <p *ngSwitchCase="5">Value is 5</p>
        <p *ngSwitchCase="10">Value is 10</p>
        <p *ngSwitchCase="15">Value is 15</p>
      </div>

gg

fg

fg

fg

fg

fg

gf

gf

gf

gf

g

gf

Angular2 – Introduction Notes

Angular CLI

  • Before install check latest nodejs version (>=v7.7.1)
  • npm install -g @angular/cli
  • Angular Command Line Interface for workflow commons tasks.
  • More info in https://github.com/angular/angular-cli/wiki
  • Create a new app skeleton:
  • ng new my-first-app
  • Init local development server:
  • ng serve

Integrating Bootstrap

  • Install bootstrap npm package
  • npm install --save bootstrap
  • Edit .angular-cli.json:
  •       "styles": [
            "../node_modules/bootstrap/dist/css/bootstrap.min.css",
            "styles.css"
          ],

How AngularJs is loaded and started

  • index.html
  • <!doctype html>
    <html>
    <head>
      <meta charset="utf-8">
      <title>MyFirstApp</title>
      <base href="/">
    
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
      <app-root>Loading...</app-root>
    </body>
    </html>
  • main.ts
  • import { enableProdMode } from '@angular/core';
    import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
    
    import { AppModule } from './app/app.module';
    import { environment } from './environments/environment';
    
    if (environment.production) {
      enableProdMode();
    }
    
    platformBrowserDynamic().bootstrapModule(AppModule);
  • app/app.module.ts
  • import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    import { HttpModule } from '@angular/http';
    
    import { AppComponent } from './app.component';
    
    @NgModule({
      declarations: [
        AppComponent
      ],
      imports: [
        BrowserModule,
        FormsModule,
        HttpModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
  • app/app.component.ts
  • import { Component } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent {
      title = 'Dicen que dicen los que dicen que dicen!';
      name = 'El nuevo marketing de Podemos es la trama';
    }

     

Creating a custom component

  • Will create a new ‘app-server’ component to be place into main ‘app-root’ component
  • app/server/server.component.ts
  • import { Component } from '@angular/core';
    
    @Component ({
      selector: 'app-server',
      templateUrl: './server.component.html'
    })
    export class ServerComponent {}
  • app/server/server.component.html
  • <h3>Server Component</h3>
  • app/app.module.ts
  • import { BrowserModule } from '@angular/platform-browser';
    import { NgModule } from '@angular/core';
    import { FormsModule } from '@angular/forms';
    import { HttpModule } from '@angular/http';
    
    import { AppComponent } from './app.component';
    import { ServerComponent } from './server/server.component';
    
    @NgModule({
      declarations: [
        AppComponent,
        ServerComponent
      ],
      imports: [
        BrowserModule,
        FormsModule,
        HttpModule
      ],
      providers: [],
      bootstrap: [AppComponent]
    })
    export class AppModule { }
  •  app/app.component.html
  • <input type="text" [(ngModel)]="name">
    <p>{{ name }}</p>
    <button type="button" class="btn btn-primary" name="button">Kaka de la vaca</button>
    <hr>
    <app-server></app-server>

Create a component with CLI

  • We can generate a new component from the terminal:
ng generate component servers
ng g c servers
  • it creates servers/servers.component.ts and related files

Databinding / String interpolation / Property binding

  • servers/servers.component.ts
  • import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-servers',
      templateUrl: './servers.component.html',
      styleUrls: ['./servers.component.css']
    })
    export class ServersComponent implements OnInit {
      allowNewServer = false;
      constructor() {
        setTimeout(() => {
          this.allowNewServer = true;
        },2000)
    
      }
    
      ngOnInit() {
      }
    
    }
  • servers/servers.component.html
  • <app-server></app-server>
    <app-server></app-server>
    <button type="button" class="btn btn-primary" [disabled]='!allowNewServer'>Add Server</button>
  • server.component.ts
  • import { Component } from '@angular/core';
    
    @Component ({
      selector: 'app-server',
      templateUrl: './server.component.html'
    })
    export class ServerComponent {
      serverId:number = 77;
      serverStatus:string = 'offline';
    
      getServerStatus() {
        return this.serverStatus;
      }
    }
  • server.component.html
  • <h3>Server {{serverId}} is {{getServerStatus()}}</h3>

Event Binding

  • servers/servers.component.html
  • <app-server></app-server>
    <app-server></app-server>
    <button
      type="button"
      class="btn btn-primary"
      [disabled]='!allowNewServer'
      (click)='onCreateServer()'>Add Server</button>
    {{createButtonClickedMessage}}
  • servers/servers.component.ts
  • import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-servers',
      templateUrl: './servers.component.html',
      styleUrls: ['./servers.component.css']
    })
    export class ServersComponent implements OnInit {
    
      allowNewServer = false;
      createButtonClickedMessage:string = 'No he pulsado el botón';
    
      constructor() {
        setTimeout(() => {
          this.allowNewServer = true;
        },2000)
    
      }
    
      onCreateServer() {
        this.createButtonClickedMessage = 'Ey , he pulsado el botón!'
      }
    
    
      ngOnInit() {
      }
    
    }

Built-in directives: ngIf, ngFor, ngStyle, ngClass

  • ngIf and ngFor are structural directives because changes the DOM, so will write them with asterisk: *:
  • app.component.html
  <button type="button" (click)="togglePassword()">Display Details</button>
  <p *ngIf="showPassword">Secret password: de danone</p>

  <div *ngFor="let log of logs">
    <p [ngStyle]="{backgroundColor: getColor(log.id)}" [ngClass]="{blanco: log.id > 4}">{{log.text}}</p>
  </div>
  • app.component.ts
import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  // styleUrls: ['./app.component.css']
  styles: [`
    .blanco {
      color:#fff;
    }
  `]
})
export class AppComponent {
  logs=[];
  username='';
  usernameIsEmpty = true;
  resetUsername() {
    this.username = '';
  }
  showPassword=false;

  togglePassword() {
    this.showPassword=!this.showPassword;
    this.logs.push({
      text: 'clicked on ' + new Date().getTime(),
      id: this.logs.length
    });
  }

  getColor(id) {
    return (id < 5)? 'white':'blue';
  }

}
NOTE: All components , not depending of the nesting , are being referenced in the app.module.ts

Two ways of assigning a model value to a html property

  • Normal string interpolation
<img src="{{recipe.imagePath}}">
  • Property binding
<img [src]="recipe.imagePath"

A shorcut for defining models

export class Ingredient {
  constructor(public name:string, public amount:number) {}
}

this is equivalent to assign the parameters to the “this” attributes of the object.

Debugging

  • Typescript are not executed by the browser , it is compiled to regular javascript. But we can make debugging in the browser console:

Captura de pantalla 2017-04-15 a las 19.47.07

in the ‘Source’ tab we can inspect all the webpack items, including ts files. That is because of using sourcemaps.

  • There is a Chrome Extension called Augury ti inspect the angular app more in deep:

Captura de pantalla 2017-04-15 a las 19.56.06

Binding to custom properties: communication from parent component to child component / Input decorator

Child: Odd component

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-odd',
  templateUrl: './odd.component.html',
  styleUrls: ['./odd.component.css']
})
export class OddComponent implements OnInit {

  @Input() count: number;
  constructor() { }

  ngOnInit() {
  }

}

Parent : app.component

      <app-odd *ngFor="let odd of oddArray" [count]="odd"></app-odd>

Binding to custom events: communication from child component to parent component / Output decorator

Child component: game-control.component.ts

import { Component, OnInit,EventEmitter,Output } from '@angular/core';

@Component({
  selector: 'app-game-control',
  templateUrl: './game-control.component.html',
  styleUrls: ['./game-control.component.css']
})
export class GameControlComponent implements OnInit {
  intervalRef;
  count:number = 0;
  @Output() startGameEvent = new EventEmitter<{count: number}>();

  constructor() { }

  ngOnInit() {
  }

  onStartGame() {
    this.intervalRef = setInterval(() => {
      this.startGameEvent.emit({
        count: this.count++
      });
    },1000);
  }

  onStopGame() {
    clearInterval(this.intervalRef);
  }

}

Parent component: app.component

  <app-game-control (startGameEvent)="onStartGameClicked($event)"></app-game-control>

Understanding View Encapsulation

  • All components have their own css file and all the classes defined in that file only applies to that component and NOT are spread to their children.

Using local references in templates / ViewChild decorator

  • You can create local references in the templates to be only accesible for the component

https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ref-vars

Projecting content into components with ng-content

  • With <ng-content></ng-content> you can reference the html snippet included between the start tag and the end tag of the component declaration.

Lifecycle hooks

ngIf example with else to show ng-template

<div class="row">
  <div class="col-md-5">
    <app-recipe-list (selectRecipeEvent2)="onRecipeSelected($event)"></app-recipe-list>
  </div>
  <div class="col-md-7">
    <app-recipe-detail
    *ngIf="recipeSelected; else infoText"
    [recipe]="recipeSelected"></app-recipe-detail>
    <ng-template #infoText>
      <p>Please select a recipe:</p>
    </ng-template>
  </div>
</div>

Ecmascript 6: Modules

[Fuente: http://exploringjs.com/es6/ch_modules.html]

16.1 Overview

JavaScript has had modules for a long time. However, they were implemented via libraries, not built into the language. ES6 is the first time that JavaScript has built-in modules.

ES6 modules are stored in files. There is exactly one module per file and one file per module. You have two ways of exporting things from a module. These two ways can be mixed, but it is usually better to use them separately.

16.1.1 Multiple named exports

There can be multiple named exports:

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

You can also import the complete module:

//------ main.js ------
import * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5

16.1.2 Single default export

There can be a single default export. For example, a function:

//------ myFunc.js ------
export default function () { ··· } // no semicolon!

//------ main1.js ------
import myFunc from 'myFunc';
myFunc();

Or a class:

//------ MyClass.js ------
export default class { ··· } // no semicolon!

//------ main2.js ------
import MyClass from 'MyClass';
const inst = new MyClass();

Note that there is no semicolon at the end if you default-export a function or a class (which are anonymous declarations).

16.1.3 Browsers: scripts versus modules

Scripts Modules
HTML element <script> <script type="module">
Default mode non-strict strict
Top-level variables are global local to module
Value of thisat top level window undefined
Executed synchronously asynchronously
Declarative imports (importstatement) no yes
Programmatic imports (Promise-based API) yes yes
File extension .js .js

 

16.2 Modules in JavaScript

Even though JavaScript never had built-in modules, the community has converged on a simple style of modules, which is supported by libraries in ES5 and earlier. This style has also been adopted by ES6:

  • Each module is a piece of code that is executed once it is loaded.
  • In that code, there may be declarations (variable declarations, function declarations, etc.).
    • By default, these declarations stay local to the module.
    • You can mark some of them as exports, then other modules can import them.
  • A module can import things from other modules. It refers to those modules via module specifiers, strings that are either:
    • Relative paths ('../model/user'): these paths are interpreted relatively to the location of the importing module. The file extension .js can usually be omitted.
    • Absolute paths ('/lib/js/helpers'): point directly to the file of the module to be imported.
    • Names ('util'): What modules names refer to has to be configured.
  • Modules are singletons. Even if a module is imported multiple times, only a single “instance” of it exists.

This approach to modules avoids global variables, the only things that are global are module specifiers.

16.2.1 ECMAScript 5 module systems

It is impressive how well ES5 module systems work without explicit support from the language. The two most important (and unfortunately incompatible) standards are:

  • CommonJS Modules: The dominant implementation of this standard is in Node.js (Node.js modules have a few features that go beyond CommonJS). Characteristics:
    • Compact syntax
    • Designed for synchronous loading and servers
  • Asynchronous Module Definition (AMD): The most popular implementation of this standard is RequireJS. Characteristics:
    • Slightly more complicated syntax, enabling AMD to work without eval() (or a compilation step)
    • Designed for asynchronous loading and browsers

The above is but a simplified explanation of ES5 modules. If you want more in-depth material, take a look at “Writing Modular JavaScript With AMD, CommonJS & ES Harmony” by Addy Osmani.

16.2.2 ECMAScript 6 modules

The goal for ECMAScript 6 modules was to create a format that both users of CommonJS and of AMD are happy with:

  • Similarly to CommonJS, they have a compact syntax, a preference for single exports and support for cyclic dependencies.
  • Similarly to AMD, they have direct support for asynchronous loading and configurable module loading.

Being built into the language allows ES6 modules to go beyond CommonJS and AMD (details are explained later):

  • Their syntax is even more compact than CommonJS’s.
  • Their structure can be statically analyzed (for static checking, optimization, etc.).
  • Their support for cyclic dependencies is better than CommonJS’s.

The ES6 module standard has two parts:

  • Declarative syntax (for importing and exporting)
  • Programmatic loader API: to configure how modules are loaded and to conditionally load modules

16.3 The basics of ES6 modules

There are two kinds of exports: named exports (several per module) and default exports (one per module). As explained later, it is possible use both at the same time, but usually best to keep them separate.

16.3.1 Named exports (several per module)

A module can export multiple things by prefixing its declarations with the keyword export. These exports are distinguished by their names and are called named exports.

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

There are other ways to specify named exports (which are explained later), but I find this one quite convenient: simply write your code as if there were no outside world, then label everything that you want to export with a keyword.

If you want to, you can also import the whole module and refer to its named exports via property notation:

//------ main.js ------
import * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5

The same code in CommonJS syntax: For a while, I tried several clever strategies to be less redundant with my module exports in Node.js. Now I prefer the following simple but slightly verbose style that is reminiscent of the revealing module pattern:

//------ lib.js ------
var sqrt = Math.sqrt;
function square(x) {
    return x * x;
}
function diag(x, y) {
    return sqrt(square(x) + square(y));
}
module.exports = {
    sqrt: sqrt,
    square: square,
    diag: diag,
};

//------ main.js ------
var square = require('lib').square;
var diag = require('lib').diag;
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5

16.3.2 Default exports (one per module)

Modules that only export single values are very popular in the Node.js community. But they are also common in frontend development where you often have classes for models and components, with one class per module. An ES6 module can pick a default export, the main exported value. Default exports are especially easy to import.

The following ECMAScript 6 module “is” a single function:

//------ myFunc.js ------
export default function () {} // no semicolon!

//------ main1.js ------
import myFunc from 'myFunc';
myFunc();

An ECMAScript 6 module whose default export is a class looks as follows:

//------ MyClass.js ------
export default class {} // no semicolon!

//------ main2.js ------
import MyClass from 'MyClass';
const inst = new MyClass();

There are two styles of default exports:

  1. Labeling declarations
  2. Default-exporting values directly
16.3.2.1 Default export style 1: labeling declarations

You can prefix any function declaration (or generator function declaration) or class declaration with the keywords export default to make it the default export:

export default function foo() {} // no semicolon!
export default class Bar {} // no semicolon!

You can also omit the name in this case. That makes default exports the only place where JavaScript has anonymous function declarations and anonymous class declarations:

export default function () {} // no semicolon!
export default class {} // no semicolon!
16.3.2.1.1 Why anonymous function declarations and not anonymous function expressions?

When you look at the previous two lines of code, you’d expect the operands of export default to be expressions. They are only declarations for reasons of consistency: operands can be named declarations, interpreting their anonymous versions as expressions would be confusing (even more so than introducing new kinds of declarations).

If you want the operands to be interpreted as expressions, you need to use parentheses:

export default (function () {});
export default (class {});
16.3.2.2 Default export style 2: default-exporting values directly

The values are produced via expressions:

export default 'abc';
export default foo();
export default /^xyz$/;
export default 5 * 7;
export default { no: false, yes: true };

Each of these default exports has the following structure.

export default «expression»;

That is equivalent to:

const __default__ = «expression»;
export { __default__ as default }; // (A)

The statement in line A is an export clause (which is explained in a later section).

16.3.2.2.1 Why two default export styles?

The second default export style was introduced because variable declarations can’t be meaningfully turned into default exports if they declare multiple variables:

export default const foo = 1, bar = 2, baz = 3; // not legal JavaScript!

Which one of the three variables foo, bar and baz would be the default export?

16.3.3 Imports and exports must be at the top level

As explained in more detail later, the structure of ES6 modules is static, you can’t conditionally import or export things. That brings a variety of benefits.

This restriction is enforced syntactically by only allowing imports and exports at the top level of a module:

if (Math.random()) {
    import 'foo'; // SyntaxError
}

// You can’t even nest `import` and `export`
// inside a simple block:
{
    import 'foo'; // SyntaxError
}

16.3.4 Imports are hoisted

Module imports are hoisted (internally moved to the beginning of the current scope). Therefore, it doesn’t matter where you mention them in a module and the following code works without any problems:

foo();

import { foo } from 'my_module';

16.3.5 Imports are read-only views on exports

The imports of an ES6 module are read-only views on the exported entities. That means that the connections to variables declared inside module bodies remain live, as demonstrated in the following code.

//------ lib.js ------
export let counter = 3;
export function incCounter() {
    counter++;
}

//------ main.js ------
import { counter, incCounter } from './lib';

// The imported value `counter` is live
console.log(counter); // 3
incCounter();
console.log(counter); // 4

How that works under the hood is explained in a later section.

Imports as views have the following advantages:

  • They enable cyclic dependencies, even for unqualified imports (as explained in the next section).
  • Qualified and unqualified imports work the same way (they are both indirections).
  • You can split code into multiple modules and it will continue to work (as long as you don’t try to change the values of imports).

16.3.6 Support for cyclic dependencies

Two modules A and B are cyclically dependent on each other if both A (possibly indirectly/transitively) imports B and B imports A. If possible, cyclic dependencies should be avoided, they lead to A and B being tightly coupled – they can only be used and evolved together.

Why support cyclic dependencies, then? Occasionally, you can’t get around them, which is why support for them is an important feature. A later section has more information.

Let’s see how CommonJS and ECMAScript 6 handle cyclic dependencies.

16.3.6.1 Cyclic dependencies in CommonJS

The following CommonJS code correctly handles two modules a and b cyclically depending on each other.

//------ a.js ------
var b = require('b');
function foo() {
    b.bar();
}
exports.foo = foo;

//------ b.js ------
var a = require('a'); // (i)
function bar() {
    if (Math.random()) {
        a.foo(); // (ii)
    }
}
exports.bar = bar;

If module a is imported first then, in line i, module b gets a’s exports object before the exports are added to it. Therefore, b cannot access a.foo in its top level, but that property exists once the execution of a is finished. If bar() is called afterwards then the method call in line ii works.

As a general rule, keep in mind that with cyclic dependencies, you can’t access imports in the body of the module. That is inherent to the phenomenon and doesn’t change with ECMAScript 6 modules.

The limitations of the CommonJS approach are:

  • Node.js-style single-value exports don’t work. There, you export single values instead of objects:
      module.exports = function () { ··· };
    

    If module a did that then module b’s variable a would not be updated once the assignment is made. It would continue to refer to the original exports object.

  • You can’t use named exports directly. That is, module b can’t import foo like this:
      var foo = require('a').foo;
    

    foo would simply be undefined. In other words, you have no choice but to refer to foo via a.foo.

These limitations mean that both exporter and importers must be aware of cyclic dependencies and support them explicitly.

16.3.6.2 Cyclic dependencies in ECMAScript 6

ES6 modules support cyclic dependencies automatically. That is, they do not have the two limitations of CommonJS modules that were mentioned in the previous section: default exports work, as do unqualified named imports (lines i and iii in the following example). Therefore, you can implement modules that cyclically depend on each other as follows.

//------ a.js ------
import {bar} from 'b'; // (i)
export function foo() {
    bar(); // (ii)
}

//------ b.js ------
import {foo} from 'a'; // (iii)
export function bar() {
    if (Math.random()) {
        foo(); // (iv)
    }
}

This code works, because, as explained in the previous section, imports are views on exports. That means that even unqualified imports (such as bar in line ii and fooin line iv) are indirections that refer to the original data. Thus, in the face of cyclic dependencies, it doesn’t matter whether you access a named export via an unqualified import or via its module: There is an indirection involved in either case and it always works.

React-LeafletJS

[Fuente: https://github.com/PaulLeCam/react-leaflet/blob/master/docs/Getting%20started.md]

Sobre React-Leaflet

Esta librería proporciona una abstracción de Leaflet en forma de React components.

No reemplaza a Leaflet, sólo se basa en los React’s lifecycle methods para invocar los handlers relevantes de Leaflet. Puedes leer más información sobre el proceso del ciclo de vida en How it works. Por favor asegúrate que entiendes todos los core concepts y limitations para evaluar si esta librería es apropiada para tus necesidades.

React-Leaflet permite convertir este ejemplo de código de la documentación de Leaflet:

 

import L from 'leaflet';

const position = [51.505, -0.09];
const map = L.map('map').setView(position, 13);

L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
  attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

L.marker(position).addTo(map)
  .bindPopup('A pretty CSS3 popup. <br> Easily customizable.');

a componentes React:

import React from 'react';
import { render } from 'react-dom';
import { Map, Marker, Popup, TileLayer } from 'react-leaflet';

const position = [51.505, -0.09];
const map = (
  <Map center={position} zoom={13}>
    <TileLayer
      url='http://{s}.tile.osm.org/{z}/{x}/{y}.png'
      attribution='© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    />
    <Marker position={position}>
      <Popup>
        <span>A pretty CSS3 popup.<br/>Easily customizable.</span>
      </Popup>
    </Marker>
  </Map>
);

render(map, document.getElementById('map-container'));

Notar que el  <Map> component crea su propio <div> container para el mapa, no está linkado a un nodo existente.

Se puede ver este ejemplo en this jsfiddle.

Leaflet setup

If you are not familiar with Leaflet, make sure you read its quick start guide before using this library.
You will notably need to add its CSS to your page to render the map properly, and set the height of the <Map>container.

All components are React wrappers for Leaflet elements and layers, they need a map instance and therefore must be included in a top-level <Map> component.

Installation

Using npm

npm install react-leaflet@next

React, ReactDOM and Leaflet are peer dependencies, if you haven’t already installed them you can use:

npm install leaflet@1.0.0-rc.2 react react-dom react-leaflet@next

Cómo funciona

Conceptos claves

React-Leaflet usa los métodos del ciclo de vida de React (React’s lifecycle methods) para invocar a los handlers relevantes de Leaflet, lo cual tiene unas cuentas consecuencias:

DOM rendering

React no renderiza layers de Leaflet en el DOM, este renderizado es hecho por Leaflet por si mismo. React sólo renderiza el map container dentro del Map component y potenciales elementos <div> vacíos en componentes que tengán varios hijos.

Component properties

Las properties que se pasan a los componentes son utilizados para crear la intancia Leaflet correspondiente cuando el componente sea montado. Cuando se añada un componente, todas estas propiedades deben ser soportadas si la versión de Leaflet la soporta, pero no serán actualizadas en el UI cuando cambian a menos que sean referenciados en la documentación como dynamic.

Component context

React-Leaflet utiliza el API context de React (context API) para fabricar los elementos Leaflet disponibles a otros elementos que lo necesiten.

Si creas custom components, necesitas acceder a las siguientes instancias desde el contexto:

  • map: The Leaflet.Map instance created by the <Map> component.
  • layerContainer: The containing layer, for example a LayerGroup instance. Defaults to the map value if no other container is set.
  • popupContainer: The layer that could contain a popup.

Lifecycle process

  1. El Map de nivel más alto renderiza un <div> vacío para contener el mapa.
  2. El método componentDidMount() de Map instancia un Leaflet.Map() para el <div> creado con las component properties y setea la instancia en ese estado. Esta instancia es hecha disponible en el contexto.
  3. El método render() de Map es ejecutado otra vez, esta vez renderinzando sus componentes hijos.
  4. Para cada componente hijo, se invocará el método componentWillMount() e instanciará la instancia Leaflet correspondiente para este elemento utilizando las propiedades del componente y su contexto.
  5. El método render() es invocado par cada hijo, que retornará o null o renderizará sus propios hijos.
  6. Cuando el método componentDidUpdate de un componente es invocado , actualiza su intancia Leaflet de acuerdo a sus propiedades dinámicas soportadas.
  7. Cuando el método componentWillMount de un componente es llamado, elimina su layer del map.

Limitations

  • Leaflet hace llamadas directas al DOM cuando es cargado, por lo tanto esta librería no es compatible con server-side rendering.
  • Los componentes expuestos son abstracciones para los Leaflet layers, y no de elementos DOM. Algunos de ellos tienen propiedades que pueden ser actualizadas directamente invocando los métodos setters expuestos por Leaflet mientras otros deben ser completamente reemplazados , configurando un valor único en su propiedad key de forma que pueda ser manejado apropiadamente por el algoritmo de React.

dsd
f
df
df
df
df
df
df
df
dfd
fd
fd
fd
fd
fd
fd
fd
fd
fdf
df
df
df
df
df

AngularJS: Form validation built in support

[Fuente: https://scotch.io/tutorials/angularjs-form-validation]

We’ll focus on client side validation and using the built in Angular form properties.

Demo

See the Pen AngularJS Form Validation by Chris Sevilleja (@sevilayha) on CodePen.

Requirements

  • Name is required
  • Username is not required, minimum length 3, maximum length 8
  • Email is not required, but has to be a valid email
  • Form submit is disabled if the form isn’t valid
  • Show a required or invalid email error
  • Alert awesome if submitted correctly

Angular Form Properties $valid, $invalid, $pristine, $dirty

Property Class Description
$valid ng-valid Boolean Tells whether an item is currently valid based on the rules you placed.
$invalid ng-invalid Boolean Tells whether an item is currently invalid based on the rules you placed.
$pristine ng-pristine Boolean True if the form/input has not been used yet.
$dirty ng-dirty Boolean True if the form/input has been used.
$touched ng-touched Boolean True if the input has been blurred.

Angular also provides classes on the form and its inputs so that you can style each state accordingly.

ACCESSING ANGULAR FORM PROPERTIES

  • To access the form: <form name>.<angular property>
  • To access an input: <form name>.<input name>.<angular property>

 Setting up our form

<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <!-- CSS ===================== -->
    <!-- load bootstrap -->
    <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css"> 
    <style>
        body    { padding-top:30px; }
    </style>
    
    <!-- JS ===================== -->
    <!-- load angular -->
    <script src="http://code.angularjs.org/1.2.6/angular.js"></script> 
    <script src="app.js"></script>
</head>

<!-- apply angular app and controller to our body -->
<body ng-app="validationApp" ng-controller="mainController">
<div class="container">
<div class="col-sm-8 col-sm-offset-2">
    
    <!-- PAGE HEADER -->
    <div class="page-header"><h1>AngularJS Form Validation</h1></div>
   
    <!-- FORM -->
    <!-- pass in the variable if our form is valid or invalid -->
    <form name="userForm" ng-submit="submitForm(userForm.$valid)" novalidate> 
<!-- novalidate prevents HTML5 validation since we will be validating ourselves -->

        <!-- NAME -->
        <div class="form-group">
            <label>Name</label>
            <input type="text" name="name" class="form-control" ng-model="name" required>
        </div>

        <!-- USERNAME -->
        <div class="form-group">
            <label>Username</label>
            <input type="text" name="username" class="form-control" ng-model="user.username" ng-minlength="3" ng-maxlength="8">
        </div>
        
        <!-- EMAIL -->
        <div class="form-group">
            <label>Email</label>
            <input type="email" name="email" class="form-control" ng-model="email">
        </div>
        
        <!-- SUBMIT BUTTON -->
        <button type="submit" class="btn btn-primary">Submit</button>
        
    </form>

</div><!-- col-sm-8 -->
</div><!-- /container -->
</body>
</html>

A few key points to note here:

  • novalidate: This will prevent the default HTML5 validations since we’ll be doing that ourselves (ours will be much prettier)
  • We have applied ng-model to our inputs so that we have data from our forms bound to Angular variables
  • ng-minlength and ng-maxlength on username will create those rules
  • The name input is required
  • The email input is type=”email”

Validation Rules

Angular provides many validation rules that we can use in addition to ng-minlength and ng-maxlength.

These are the available parameters for an Angular input to create validation rules. Read the Angular input directive for more information.

  <input
       ng-model="{ string }"
       name="{ string }"
       required
       ng-required="{ boolean }"
       ng-minlength="{ number }"
       ng-maxlength="{ number }"
       ng-pattern="{ string }"
       ng-change="{ string }">
    </input>

Now that we have our simple form, let’s create our Angular app and controller that we have already applied to it using ng-app and ng-controller.

OUR ANGULAR APP CODE APP.JS

// app.js
// create angular app
var validationApp = angular.module('validationApp', []);

// create angular controller
validationApp.controller('mainController', function($scope) {

  // function to submit the form after all validation has occurred            
  $scope.submitForm = function(isValid) {

    // check to make sure the form is completely valid
    if (isValid) {
      alert('our form is amazing');
    }

  };

});

Disabling the Submit Button ng-disabled

<!-- index.html -->
...

<!-- SUBMIT BUTTON -->
<button type="submit" class="btn btn-primary" ng-disabled="userForm.$invalid">Submit</button>

...

Showing an Error Message ng-show

ng-valid and ng-invalid will automatically determine if an input is good based on the rules placed on it in your form.

Let’s go through and add an error message for each of our inputs if they are not $valid and have already been used (since we don’t want to show an error before they’ve been used).

<!-- index.html -->
...

<!-- NAME -->
<div class="form-group">
  <label>Name</label>
  <input type="text" name="name" class="form-control" ng-model="name" required>
  <p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">You name is required.</p>
</div>

<!-- USERNAME -->
<div class="form-group">
  <label>Username</label>
  <input type="text" name="username" class="form-control" ng-model="user.username" ng-minlength="3" ng-maxlength="8">
  <p ng-show="userForm.username.$error.minlength" class="help-block">Username is too short.</p>
  <p ng-show="userForm.username.$error.maxlength" class="help-block">Username is too long.</p>
</div>

<!-- EMAIL -->
<div class="form-group">
  <label>Email</label>
  <input type="email" name="email" class="form-control" ng-model="email">
  <p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">Enter a valid email.</p>
</div>

...

Styling Classes

Angular already provides classes on our inputs and our forms based on if they are valid or not. Look at the table at the beginning of this article for those classes (ng-valid, ng-invalid, ng-pristine and ng-dirty).

You can style those in CSS if you like. You can do anything you like with those classes. There will even be classes based on the certain rules applied if you wanted to get really specific.

.ng-valid       {  }
.ng-invalid     {  }
.ng-pristine    {  }
.ng-dirty       {  }
.ng-touched     {  }

/* really specific css rules applied by angular */
.ng-invalid-required        {  }
.ng-invalid-minlength       {  }
.ng-valid-max-length        {  }

Adding Conditional Classes ng-class

Since we are using Bootstrap, we will use the classes they provide (has-error). This will get us that nice error and color around our form-group.

ng-class allows us to add classes based on an expression. In this case, we want to add a has-error class to our form-group if an input is $invalid and not pristine.

The way it works is ng-class="{ <class-you-want> : <expression to be evaluated > }". For more information, read the Angular ngClass docs.

<!-- index.html -->
...

<!-- NAME -->
<div class="form-group" ng-class="{ 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }">
    <label>Name</label>
    <input type="text" name="name" class="form-control" ng-model="user.name" required>
    <p ng-show="userForm.name.$invalid && !userForm.name.$pristine" class="help-block">You name is required.</p>
</div>

<!-- USERNAME -->
<div class="form-group" ng-class="{ 'has-error' : userForm.username.$invalid && !userForm.username.$pristine }">
    <label>Username</label>
    <input type="text" name="username" class="form-control" ng-model="user.username" ng-minlength="3" ng-maxlength="8">
    <p ng-show="userForm.username.$error.minlength" class="help-block">Username is too short.</p>
    <p ng-show="userForm.username.$error.maxlength" class="help-block">Username is too long.</p>
</div>
    
<!-- EMAIL -->
<div class="form-group" ng-class="{ 'has-error' : userForm.email.$invalid && !userForm.email.$pristine }">
    <label>Email</label>
    <input type="email" name="email" class="form-control" ng-model="user.email">
    <p ng-show="userForm.email.$invalid && !userForm.email.$pristine" class="help-block">Enter a valid email.</p>
</div>

...

Only showing errors after submitting the form

Sometimes it is not desirable to show errors while a user is typing. The errors currently show immediately as a user is typing into the form. This happens because of Angular’s great data-binding feature. Since everything changes immediately, it can be a downside when talking about form validation.

For the scenario where you only want to show errors after a form is submitted, you would adjust the above code a little bit.

  1. You would need to take away the ng-disabled on the submit button since we want a user to be able to submit a form even if it is not fully valid.
  2. You would add a variable after the form has been submitted. Inside of your submitForm() function, just add $scope.submitted = true;. This stores the submitted variable as true as soon as the form is submitted.
  3. Adjust the error rules from ng-class="&#123; 'has-error' : userForm.name.$invalid && !userForm.name.$pristine }" to ng-class="&#123; 'has-error' : userForm.name.$invalid && !userForm.name.$pristine && submitted }". This ensures that the error will only show after the form is submitted. You would need to adjust all the other ng-class and ng-show to account for this variable.

Now the form only shows errors if the submitted variable is set to true.

Only showing errors after clicking out of an input

Picturefill 2.0: Responsive Images And The Perfect Polyfill

[Fuente: https://www.smashingmagazine.com/2014/05/picturefill-2-0-responsive-images-and-the-perfect-polyfill/]

Over the last four years (yeah, it’s been about four years), we’ve seen many permutations of images in responsive design. From the lazier days of setting max-width: 100% (the absolute minimum you should be doing) to more full-featured JavaScript implementations, such as Picturefill and Zurb’sdata-interchange method, we’ve spent a lot of time spinning our wheels, banging our heads and screaming at the wall. I’m happy to say that our tireless journey is coming to a close. The W3C and browser makers got the hint.

The State Of Responsive Images

In our search for the holy grail of serving the right image to the user, our attitude towards browser makers until now has largely been, “Forget you — we’ll do it ourselves.” I’m certainly no exception. We were so attentive to responsive images and were exposed to all of the guesswork and trials that are not typically released to the public that we got impatient (rightfully so) and did it with JavaScript.

The difference between a CSS transition and a responsive image is, of course, how they degrade. If a CSS transition doesn’t work, who really cares? Your interface might be a little jumpy, but the experience as a whole won’t really suffer because your users will still be able to accomplish their goal and consume the content they need.

That really isn’t the case with images. How does a new image tag degrade? The img tag is so widely accepted that I couldn’t even find when the W3C recommended it as a standard, other than a small reference in the HTML 4.01 specification. Replacing or even expanding on the img tag would be like telling Frank Sinatra to wear a baseball cap instead of a fedora — you’ll get some pushback.

RESOURCE PROBLEMS

As responsive design grew in popularity and as the media through which users consume information became uncontrollable, we slowly realized that img by itself wasn’t going to cut the mustard. We started asking questions like, “What screen size is the user on?” and “What’s the pixel density of the screen?” These questions fuelled our image techniques until we realized that screen size and pixel density have absolutely no relationship to the amount of bandwidth available to serve up a huge high-definition image.

The RICG began working on the picture element, sharing its work with the W3C along the way.
The RICG began working on the picture element, sharing its work with the W3C along the way.

The solutions got pretty complex. Talk of the picture element started, and a group called the Responsive Images Community Group (RICG) appeared. The RICG began working on the picture element, sharing its work with the W3C along the way. The result has led us to today and this discussion about all of the progress that’s been made.

THE INTRODUCTION OF SRCSET

Because most of the responsive-image community was on board with the picture element and looking forward to it because of the great polyfills, such as Picturefill, it went ahead and released a well thought-out and fleshed-out document outlining something called srcset, which is an extension of the standard img tag. Yeah, I know — it feels like it came out of nowhere. It was also super-complicated and overly limiting by restricting you to (implied) pixel values and using a microsyntax that didn’t allow for scalability with media queries in the future. Luckily, the syntax has matured into what we have today, which is a fairly robust recommendation.

Most recently, Andrew Clark said it best when he tweeted, “Looked at the responsive images srcset & sizes attributes for the first time. Blimey it’s complicated.”

I couldn’t have said it better myself. Let’s look at what we’re dealing with:

<img alt="dog" src="dog.jpg" srcset="dog-HD.jpg 2x, dog-narrow.jpg 300w, dog-narrow-HD.jpg 600w 2x">  

Three major attributes are in the snippet above: alt, src and srcset. The alt attribute is the same as it’s always been; src is the fallback if srcset isn’t supported; and srcset is obviously the meat and potatoes here.

We can see three arguments in srcset. The first is the image path. The second gives the browser information about the natural widths of the sources, so that it knows which resource to serve to the user (based on the user’s preferences and cross-referencing with the sizes attribute – I told you it was complicated). The last piece sets the optional pixel ratio (2x in this example specifies the high-definition image).

One thing I really love about srcset is that the specification states that the browser should contain image-allocation preferences for certain bandwidth situations. This means you don’t have to worry about serving a 2x image to a high-definition screen if that device is on a cruddy 3G connection. The user’s preferences should take over, and the browser would choose the appropriate image to serve.

PREPARING FOR THE PICTURE ELEMENT

After much complaining about our new weird friend, srcset, the RICG continued working on the picture element, which is finally getting some serious traction with browser makers… well, that is, with Chrome. The proposed syntax for the picture element might look familiar because we saw it largely in the first version of Picturefill, and it’s not unlike how <audio> and <video> are marked up.

<picture>
  <source media="(min-width: 600px)" srcset="large-1.jpg, large-2.jpg 2x">
  <img alt="A fat dog" src="small-1.jpg">
</picture>  

As you can see, a source tag is in the picture element, along with a normal img tag. Just as we saw with src in srcset, the img is a fallback. In the source tag, we have what looks like a media query, alongside a srcset attribute that contains the same image-source and pixel-density arguments as before. This seems like a nice clean way to popularize responsive images; we’re generally familiar with the syntax, so it should be easily adopted.

BROWSER SUPPORT

The srcset attribute has been supported in Chrome since version 34. At the time of writing, it is not supported anywhere else. Mozilla appears to be working on an implementation (fingers crossed). Internet Explorer is nowhere in sight.

The picture element has even worse support; it isn’t even in Chrome yet. But like Mozilla with srcset, Google is currently working on implementing it. If you can stomach reading through a specification, I highly recommend it. Even though there isn’t much of a plot and the character development is pretty weak, it’s still a pretty good read.

Picturefill 2.0 was created because native support is reasonably close. You know we’ll need a rock-solid polyfill to use when the time officially comes, so let’s take a look at it!

Introducing Picturefill 2.0

Picturefill 2.0 was recently released as beta, and it’s quite a large jump from version 1. The RICG really aimed to create a one-stop solution for responsive images. The challenge was to create a script that allows you, the developer, to use any combination of the solutions currently being standardized, without bloating it to the point that not using it at all would be more lightweight.

Imagine polyfilling an image that would normally take 2 seconds to load using a JavaScript file that takes 10 seconds to load — it wouldn’t make much sense. Picturefill 2.0 avoids this by following the specification very closely (with some intentional omissions, which we’ll go over in a bit) and letting you use either srcset or picture or a combination of the two.

Picturefill is an responsive image approach that mimics the proposed picture element using divs.
Picturefill is an responsive image approach that mimics the proposed picture element using divs. (Larger version)

While we can’t reliably achieve everything in the specification using JavaScript (such as reasonably detecting bandwidth, which would be a user setting anyway), we can certainly take care of all of the pieces that are meant to be in HTML (i.e. elements and attributes). This version of Picturefill gets us one step closer to not needing Picturefill, which is the ultimate goal of anyone who has ever written a polyfill.

If you’re currently using version 1.0, I highly recommend upgrading to 2.0. It’s a big step towards a better solution to serving the correct image to the user. Some big changes have been made to the syntax and functionality. Let’s look at what’s new.

WHAT’S NEW IN 2.0

One thing that makes this polyfill different from others that I’ve seen is that it polyfills a concept, not just an unsupported block of HTML. Picturefill 1.0 used spans and custom attributes to mimic how we thought responsive images should work. For the record, it is a great solution, and I currently use it for many of my projects that haven’t been converted to 2.0.

In the last year or so, the specification for srcset and picture have matured so much, so we can now actually get to use something close to the real syntax. Picturefill is starting to look like a true polyfill, one we can strip away when real support shows up.

INSTALLING AND USING THE POLYFILL

If you’ve read this far, then you’ve probably dealt with some form of polyfill in the past. This one isn’t much different. Polyfills are supposed to be set-it-and-forget-it (to steal a line from Ronco), but because this is an HTML polyfill, you’ll need either to create the picture element manually or use some form of HTML shiv to do it for you. Luckily, HTML shivs are pretty common and ship with toolkits such as Modernizr; just verify that picture is supported in whatever shiv you choose.

<!-- Create the actual picture element if you haven’t already. -->
<script>
  document.createElement( "picture" );
</script>

<!-- Asynchronously load the polyfill. -->
<script src="picturefill.js" async></script>  

Other than creating the picture element, you simply have to link to the script. Using the async attribute is also recommended, so that Picturefill doesn’t block your page from loading.

USING PICTUREFILL 2.0 WITH SRCSET

Let’s look at the syntax that provides the best support and that uses srcset. It should look familiar because it has the same attributes that we saw when discussing the specification.

<img sizes="100vw, (min-width: 40em) 80vw"
srcset="pic-small.png 400w, pic-medium.png 800w, pic-large.png 1200w" alt="Obama">  

The most glaring difference between this snippet and the specification is the absence of a fallback src attribute, which was intentionally removed to prevent images from being downloaded twice in unsupported browsers. And, really, what would be the point of this if images were downloaded twice? Other than that, it’s pretty faithful to the specification, but it will probably evolve over time as the specification fleshes out and the polyfill matures.

The sizes attribute tells the browser of the image’s size relative to the viewport. This often gets overlooked because srcset is the buzzword now, but this attribute is equally important. If you’d like to learn more,Eric Portis makes a lot of sense of this “blimey complicated mess.”

USING PICTUREFILL 2.0 WITH THE PICTURE ELEMENT

The RICG did such a good job with this second version of Picturefill that the syntax of the picture element should come as no surprise. It matches the specification very closely:

<picture>
  <source srcset="extralarge.jpg, extralarge.jpg 2x" media="(min-width: 1000px)">
  <source srcset="large.jpg, large.jpg 2x" media="(min-width: 800px)">
  <source srcset="medium.jpg">
  <img srcset="medium.jpg" alt="Cambodia Map">
</picture>  

The biggest change between versions 1.0 and 2.0 is the removal of some traditional HTML (divs and spans) and the addition of newer elements (picture and source). Also, srcset support is built in (heck, why not, right? It’s in the spec!). This is great step forward for this polyfill.

Use as many or as few of these options as you’d like. In line with the specification, if you don’t want to use the 2x option, you don’t have to (and so on). The difference between this and the official picture element is the img fallback. You’ll notice here that the img fallback also has a srcset attribute, instead of a normal src (which is widely supported). Again, this is to prevent double-downloading (it’s a real problem). The srcset in the img tag would also cause double-downloading if the browser supports srcset but not picture. This bug should get worked out in the beta version.

Like many good polyfills, Picturefill 2.0 can be executed programmatically by exposing a global function, picturefill(). This allows you to use it in any ultra-hip JavaScript framework that you’d like. You can read about a few options for targeting specific images in the API documentation.

DEGRADING GRACEFULLY

Earlier in the article, I alluded to the challenge of degrading the img tag gracefully in unsupported browsers. This was another problem in creating Picturefill 2.0. Because it is a polyfill, the concept of unsupported browsers doesn’t really exist (kind of) — we’re using JavaScript to force it to work.

The edge case is this: If a browser doesn’t natively support picture orsrcset and has JavaScript turned off, then you’ll get a frowny face. I can already feel your eyes rolling, but knowing the limitations of a system is important before you rely on it on a large scale. If a user were to come across a Picturefill’ed image in an unsupported browser with JavaScript turned off, they would see the image’s alt text — a nice little way to reinforce the importance of descriptive and meaningful alt text, isn’t it?

Alternative text is the fallback because the previous <noscript>solution caused problems with browsers that support picture orsrcset but have JavaScript disabled (two images would render). The group also explored adding a src attribute to img (as in the specification), but that results in double-downloading, which defeats the purpose of allocating the appropriate image assets to the user.

We’ve come a long way with responsive images. We can see the light at the end of the tunnel, but a lot of work still has to be done. And we’d love your help!

How To Get Involved

If you’d like to get involved and help out with the responsive-images movement, join the RICG via the W3C. If that’s too much, we’re always looking for people to try out Picturefill’s beta version and submit bugs through the issue tracker on GitHub.

You can also spread the word about great tools like Sizer Soze, which calculates the performance cost of not using responsive images.

RESOURCES AND FURTHER READING LINK