I. Premier chapitre▲
Suite au précédent tutoriel, vous avez pu générer votre premier projet et lancer un serveur HTTP grâce à la commande ng serve. Je vous propose maintenant d'étudier de plus près notre premier component AppComponent présent dans src/app. En voici le code :
2.
3.
4.
5.
6.
7.
8.
9.
import
{
Component }
from
'@angular/core'
;
@Component
({
selector
:
'app-root'
,
templateUrl
:
'./app.component.html'
,
styleUrls
:
[
'./app.component.css'
]
}
)
export
class
AppComponent {
title =
'app works!'
;
}
Le selector est préfixé par app par défaut. Il est possible de changer ce prefix lors de la génération du projet en ajoutant -prefix <nom du préfixe> comme ceci :
II. Les propriétés templateUrl et styleUrls▲
Angular-CLI a pris le parti d'utiliser la propriété templateUrl pour gérer la partie template de @Component. Cela a pour avantage de dissocier le code du template, mais il est possible de choisir la propriété template à la place. Dans ce cas, le code HTML du component se trouvera dans le décorateur @Component. Si votre template a besoin de plusieurs lignes pour plus de lisibilité, vous pouvez encadrer votre template par les caractères ``. Nous allons donc en profiter pour modifier notre Component en supprimant le fichier app.component.html et en modifiant le code comme ceci :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
import
{
Component }
from
'@angular/core'
;
@Component
({
selector
:
'app-root'
,
template
:
`
<h1>Mon premier Component</h1>
<p>en action</p>
`
,
styleUrls
:
[
'./app.component.css'
]
}
)
export
class
AppComponent {
}
Cela nous donne le résultat suivant :
Pour rappel, le fichier HTML généré par Angular-CLI est celui-ci :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
<!
doctype html
>
<html>
<head>
<meta charset
=
"utf-8"
>
<title>MonPremierProjet</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>
De la même façon, nous pouvons supprimer le fichier app.component.css et remplacer stylesUrl par la propriété styles. Le fichier app.component.css ne contenait pas de styles, mais nous allons en profiter pour corriger cela avec un peu de rouge :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
import
{
Component }
from
'@angular/core'
;
@Component
({
selector
:
'app-root'
,
template
:
`
<h1>Mon premier Component</h1>
<p>en action</p>
`
,
styles
:
[
`
h1 {
color: red;
}
`
]
}
)
export
class
AppComponent {
}
Cela va nous donner :
II-A. Imbrication de Components▲
Lors de vos développements futurs, vous aurez souvent besoin d'imbriquer vos Components dans d'autres Components. Une application classique Angular peut ressembler à ceci :
Notre AppComponent intègre plusieurs Components tels que les menus, le body, qui à leur tour peuvent en intégrer d'autres. Pour illustrer cela, nous allons créer un nouveau Component child à l'aide d'Angular-CLI, et en se plaçant à la racine du projet, avec la commande suivante :
Le Component, ainsi généré, peut être modifié comme ceci :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
import
{
Component}
from
'@angular/core'
;
@Component
({
selector
:
'app-child'
,
template
:
`
<h1>Mon second Component</h1>
`
,
styles
:
[
`
h1 {
color : blue;
}
`
]
}
)
export
class
ChildComponent {
}
Nous allons maintenant inclure ce Component dans notre premier Component. Pour cela, il suffit d'ajouter notre balise <app-child> dans le template du Component appComponent. Plutôt simple, non ?
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
import
{
Component}
from
'@angular/core'
;
@Component
({
selector
:
'app-root'
,
template
:
`
<h1>Mon premier Component</h1>
<app-child></app-child>
`
,
styles
:
[
`
h1 {
color : red;
}
`
]
}
)
export
class
AppComponent {
title =
'app works!'
;
}
Le résultat est étonnant !
III. L'usage du Shadow DOM▲
Pourquoi étonnant ? Regardez les styles CSS de ces deux composants : ils indiquent tous les deux la couleur du même élément HTML h1. Pourtant, le premier h1 est bien rouge et le second bleu. Cela est dû à la portance d'un Component, pour réaliser ce tour de magie, Angular n'utilise pas le shadow DOM par défaut, mais un comportement bien à lui qui lui permet de rendre étanche entre eux les styles CSS de ses Components. Si l'on regarde de plus près le source généré, on peut voir qu'Angular va ajouter des attributs différents aux balises h1 des deux Components pour pouvoir attribuer des styles CSS différents.
Angular propose en fait trois modes d'encapsulation du DOM :
- ViewEncapsulation.None - Ni Shadow DOM, ni aucun mécanisme d'encapsulation de style CSS.
- ViewEncapsulation.Emulated - Pas de Shadow DOM, mais une émulation du Shadow DOM. C'est le comportement par défaut.
- ViewEncapsulation.Native - Utilisation du véritable Shadow DOM. Superbe sur Chrome, mais cela s'arrête là pour le moment. Ni Safari, ni Firefox ne supporte ce mécanisme.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
import
{
Component,
ViewEncapsulation}
from
'@angular/core'
;
@Component
({
selector
:
'app-root'
,
template
:
`
<h1>Mon premier Component</h1>
<app-child></app-child>
`
,
styles
:
[
`
h1 {
color : red;
}
`
],
encapsulation
:
ViewEncapsulation.
Native
}
)
export
class
AppComponent {
title =
'app works!'
;
}
Et si l'on regarde maintenant le source généré, on distingue l'apparition d'un mystérieux #shadow-root qui encapsule les Components entre eux :
IV. Insérer du contenu dans un Component▲
Pour illustrer ce mécanisme, nous allons créer un nouveau Component que nous allons appeler cadre. Pour cela nous allons nous placer dans le répertoire src/app/child :
J'ai utilisé l'option -flat pour indiquer que je désire voir ce nouveau Component dans le répertoire courant.
Maintenant, je vais me servir de ce nouveau component comme un cadre (au sens CSS). Dans ce cadre, je désire mettre le texte de mon choix. Ce texte ne fera donc pas partie du template du Component cadre. Si vous regardez votre fichier index.html, vous pouvez vous rendre compte que votre balise <app-root>contient Loading…, et pourtant, ce Loading… disparait lorsque votre Component est initialisé au profit du contenu du template.
Pour faire cela, Angular nous offre la balise <ng-content>. Cette dernière se place dans le Component cadre dans notre cas, à l'endroit où on accepte de recevoir un contenu externe. Voici notre component cadre modifié pour répondre à notre besoin :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
import
{
Component }
from
'@angular/core'
;
@Component
({
selector
:
'app-cadre'
,
template
:
`
<div class="bordure">
<h1>
<ng-content></ng-content>
</h1>
</div>
`
,
styles
:
[
`
h1 {
color : darkmagenta;
}
.bordure {
border: 1px solid darkmagenta;
}
`
]
}
)
export
class
CadreComponent {
}
et le code de notre AppComponent utilisant ce nouveau Component :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
import
{
Component }
from
'@angular/core'
;
@Component
({
selector
:
'app-root'
,
template
:
`
<h1>Mon premier Component</h1>
<app-child></app-child>
<app-cadre>un contenu dans mon cadre</app-cadre>
`
,
styles
:
[
`
h1 {
color: red;
}
`
]
}
)
export
class
AppComponent {
}
Le résultat est magnifique ! Nous pouvons envoyer du texte dans un Component :