La version 2.0 d’Angular a maintenant été annoncée depuis un moment comme une refonte complète. Cette version étant en développement actif, elle change donc beaucoup, nous vous proposons de découvrir ce nouveau framework.

Angular 2.0 et TypeScript

Première chose à noter, Google et Microsoft collaborent pour écrire cette version Angular 2.0 avec le langage TypeScript.

TypeScript est un langage typé créé par Microsoft qui est un sur-ensemble de ES6. Il apporte entre-autres les annotations, l’introspection et le typage au JavaScript. Les annotations vont permettre de définir la configuration, les options des composants, tandis que l’introspection ajoute une vérification des types à l’exécution.

Voici un exemple “Hello World”:

class Greeter {
  constructor(public greeting: string) { }

  greet() {
    return '<h1>' + this.greeting + '</h1>';
  }
};

var greeter = new Greeter('Hello, world!');
var str = greeter.greet();

document.body.innerHTML = str;

Ce code défini une classe JavaScript, avec un constructeur qui attend un attribut de type string. Le mot clef public défini devant l’argument permet de définir la portée de l’attribut, qui peuvent aussi être définis comme private. Utiliser un de ces mots clés devant un paramètre, comme dans cet exemple, permet de définir et d’initialier automatiquement une propriété du même nom. Cette classe comprend aussi une méthode greet qui retourne une balise h1 avec la valeur de la propriété greeting. La suite du code instancie donc la classe avec le fameux “Hello, world!” et appelle la méthode greet, avant de placer le résultat dans le document HTML.

Il est aussi possible de faire des héritages de classes avec le mot clé extends, des mixins avec le mot clef implements, et de définir des interfaces:

class Animal {
  name: string;
}

interface Caracteristic {
  height: number;
}

class Dog extends Animal implements Caracteristic { }

$scope

Le super $scope qui sert dans la version 1 de liant entre les vues et les contrôleurs est retiré, les propriétés sont définies dans les classes:

class Dog {
  name: string;

  constructor() {
    this.name = 'Snoopy';
  }
}

La variable name sera accessible dans la vue du composant comme suit:

<p>{{ name }}</p>

le data-binding bi-directionnel

La directive ng-model qui permet d’avoir une mise à jour des données par l’utilisateur dans la vue, et dans le même temps coté contrôleur est retirée. La mise à jour du modèle par la vue devra passer par des évènements, et pour définir une variable locale au template, il faudra faire précéder un attribut du même nom de #:

<input #name (keyup) />
<input #email (keyup)="typing($event)" />
<p>{{ name.value }}</p>
<p>{{ email.value }}</p>

Vous pouvez voir qu’un évènement se défini avec son mot clé entre () et peut appeler une méthode du composant, dans ce cas typing, qui pourrait ajouter du traitement en plus de modifier la valeur de email. D’autre part la valeur d’une variable locale au template est accessible par un attribut value sur celle-ci.

jqLite

angular.element et son mini jQuery embarqué par la première version d’Angular est retiré, vous souhaitez utiliser jQuery ? Alors il faudra le charger.

les components

Le MVW pattern est remplacé par le concept des components, pour lesquels les contrôleurs seront maintenant réservés.

Un composant comprend donc une classe JavaScript qui est le contrôleur, il se concentre sur la logique propre au composant, et des annotations qui définissent sa configuration. On retrouve par exemple la définition du sélecteur, du template et des dépendances.

Un exemple d’annotations:

@Component({
  selector: 'greeting'
})
@View({
  template: `
    <h2>
      Hello {{ name }}
      <span *if="!name">World</span>
      !
    </h2>
  `,
  directives: [If]
})

Ces annotations définissent un sélecteur qui va chercher à s’accrocher sur une balise <greeting></greeting>, une dépendance à la directive If, et un template qui utilise une variable name et la directive If. Au passage vous remarquez que les directives fournies par le framework sont préfixées par *. On aurait d’ailleurs aussi pu l’utiliser avec la forme *ng-if.

Dans cet exemple name serait une valeur définie dans le contrôleur, et non une valeur saisie par l’utilisateur, auquel cas il faudrait la définir dans le template comme suit: {{ name.value }}.

Les formulaires

Un nouveau module Forms fait son apparition pour améliorer la gestion des formulaires, et pour compenser la perte de ng-model. Il contient une classe FormBuilder qui permet de définir programmatiquement les options d’un formulaire. Parmi les options disponibles pour la construction du formulaire, nous allons par exemple pouvoir définir des contraintes de validations.

Disons que nous avons une classe User comme suit:

class User {
  name: string;
  email: string;
  age: number;
}

Construction un composant de type formulaire pour cette classe:

@Component({
  selector: 'user-form',
  injectables: [FormBuilder]
})
@View({
  templateUrl: 'user_form.html',
  directives: [formDirectives]
})

class UserForm {
  user: User;
  form: ControlGroup;

  constructor(builder: FormBuilder) {
    this.user = new User();

    this.form = builder.group({
      name: [(this.user.name || ''), Validators.required],
      email: [(this.user.email || ''), Validators.required],
      age: [(this.user.age || null)]
    });
  }

  submit() {
    for(var key in this.form.controls) {
      this.user[key] = this.form.controls[key].value;
    }

    console.log(this.user);
    return false;
  }
}

bootstrap(UserForm);

user_form.html:

<form [control-group]="form">
  Nom : <input control="name">
  <div *if="!form.controls.name.valid">Champ requis</div>
  Mail : <input control="email">
  <div *if="!form.controls.email.valid">Champ requis</div>
  Age : <input control="age" size="3">
  <button (click)=submit()>Valider</button>
</form>

FormBuilder sert donc à construire/définir les options du formulaire au sein de la classe du composant. On le passe à la classe UserForm à l’instanciation avec l’option injectables dans l’annotation Component. formDirectives est passé à l’annotation View avec l’option directives, et semble être un set de toutes les directives du module Forms nécéssaire à la construction d’un formulaire. ControlGroup sert à contenir un ensemble de Control, ici c’est la variable form, et on retrouve sa directive associée dans le template définie avec [control-group]="attribut". Les directives suivantes sont donc des Control définies avec control="attribut" dans le template. C’est ici un raccourci de syntaxe, la syntaxe complète est la suivante:

<input [control]="form.controls.name">

Un attribut défini entre [] signifie “binding”. Enfin nous avons la classe Validators qui nous sert à définir les contraintes de validation comme son nom l’indique.

Il est vrai que ce “nouveau” framework demande un effort de mise à niveau, peut être qu’AngularJs 2 vaudra la peine de le faire, voyons voir ce qu’il nous réserve prochainement.