Les propriétés personnalisées CSS, ou variables CSS, permettent de rendre les styles d'un site web plus dynamiques et flexibles. Dans l'exemple suivant, on observe comment ces propriétés peuvent être utilisées pour modifier l’apparence de plusieurs éléments d’une page sans avoir à dupliquer les règles de style. Le panneau affiché initialement en violet dans un scope global devient rose dans un autre, lorsque la classe CSS contrast est appliquée, affectant ainsi les éléments descendants. Cela démontre le pouvoir des propriétés personnalisées pour ajuster les couleurs, les polices, les dimensions, mais aussi des aspects plus complexes comme les animations ou les transitions.

La portée des propriétés personnalisées est définie à partir du DOM où la classe est utilisée et se propage à tous ses descendants. Ce concept rend l'utilisation de ces propriétés particulièrement utile dans des applications complexes où il est nécessaire de gérer différentes parties d'une interface sans réécrire de nombreuses lignes de code CSS. Par exemple, dans le cadre de la personnalisation d'un site en fonction de la langue de l'utilisateur, on peut associer des propriétés comme --welcome-text à une classe donnée. Cela permet d'afficher du texte traduit sans avoir à changer chaque élément de la page.

Une mise en œuvre typique pourrait ressembler à cela dans un composant Angular. Le code ci-dessous montre comment associer un texte de bienvenue en fonction de la langue active dans l’application. Lorsque l'utilisateur choisit une langue, le texte du composant se met à jour grâce aux propriétés personnalisées CSS.

css
:lang(en) { --welcome-text: 'Welcome to my website!'; } :lang(fr) { --welcome-text: 'Bienvenue sur mon site web!'; }

En associant cette propriété à un élément HTML via un pseudo-élément ::before, on affiche un texte qui se change dynamiquement lorsque la langue est modifiée.

Angular Ivy, dans sa version la plus récente, permet d’aller encore plus loin en facilitant la liaison des valeurs des propriétés CSS personnalisées. Un exemple typique consiste à lier la taille du texte de manière dynamique grâce à une propriété d'hôte dans le composant. En utilisant HostBinding dans Angular, on peut lier directement une valeur CSS personnalisée à l’élément racine du composant. Cela permet de modifier la taille du texte en temps réel, par exemple, en utilisant un sélecteur de taille de police, et ce, de manière très performante grâce à l'utilisation d'un binding directement dans les composants.

typescript
import { Component, HostBinding } from '@angular/core';
@Component({ selector: 'app-root', template: ` Text size <p>Lorem ipsum dolor sit amet...</p> `, }) export class AppComponent { @HostBinding('style.--text-size.px') textSize = 16; }

Cette capacité à manipuler dynamiquement les valeurs des propriétés CSS sans avoir à manipuler directement le DOM ouvre de nouvelles possibilités pour la création d'interfaces utilisateurs modernes, où les styles peuvent être ajustés en fonction des préférences de l'utilisateur ou d'autres paramètres.

Dans le même ordre d'idées, les propriétés CSS personnalisées peuvent être utilisées pour des cas plus avancés comme la gestion de la taille du texte dans des applications complexes ou même la gestion des couleurs en fonction des conditions de l'utilisateur. Par exemple, imaginez que vous permettez à vos utilisateurs de modifier la taille du texte ou de basculer entre des thèmes de couleurs sombres et clairs – tout cela peut être accompli de manière fluide avec des propriétés CSS personnalisées.

Les propriétés CSS ne sont pas limitées aux simples ajustements visuels. En effet, elles peuvent avoir des applications plus avancées, notamment pour la localisation ou l'internationalisation des contenus. En fonction de la langue active sur la page, vous pouvez ainsi modifier non seulement le texte, mais aussi des aspects comme les mises en page, les tailles de police, et d'autres éléments de style, de manière totalement dynamique.

Il est également essentiel de comprendre la manière dont Angular Ivy facilite l'utilisation des fournisseurs de portées (provider scopes) dans la gestion des dépendances, ce qui est d'une importance capitale pour la construction d’applications modulaires et maintenables. Par exemple, le scope any est particulièrement intéressant pour définir une portée de fournisseur qui peut être partagée à travers différentes parties d’une application, tout en étant optimisée grâce au tree-shaking. Ce concept est particulièrement utile pour les bibliothèques Angular ainsi que pour les applications à grande échelle où la gestion des ressources doit être fine et efficace.

Les développeurs Angular peuvent exploiter ces nouvelles fonctionnalités pour créer des interfaces dynamiques où les préférences utilisateur, les paramètres régionaux, et d'autres facteurs influent sur l'apparence et la fonctionnalité de l’application en temps réel. Un tel niveau de personnalisation n'était pas aussi facilement accessible dans les versions précédentes, mais aujourd'hui, la combinaison des propriétés CSS personnalisées et des nouveaux fournisseurs de portées Angular rend cela possible avec un minimum d'effort et un maximum d’efficacité.

Comment inspecter et comprendre les contextes de vues intégrées dans Angular

Dans le cadre du développement d’applications Angular, la gestion des vues et des changements dans le DOM peut devenir complexe, notamment lorsque l'on travaille avec des directives structurelles telles que NgIf ou NgFor. Ces directives sont responsables de l'ajout ou de la suppression dynamique d'éléments dans le DOM, et elles sont étroitement liées à des contextes de vues spécifiques, qui définissent l'état et les propriétés de chaque élément de la vue. L’un des outils essentiels pour comprendre et déboguer ces contextes est l'API de débogage à l'exécution d'Angular Ivy.

Lorsqu’un cycle de détection des changements est terminé, l'état de l'application — comme la génération de nombres aléatoires dans un exemple simulé — est reflété dans le DOM. Cette gestion dynamique est rendue possible grâce aux mécanismes internes d'Angular qui permettent d’inspecter et de manipuler les composants en temps réel. Dans cet article, nous allons explorer comment inspecter un contexte de vue intégré en utilisant l'API de débogage Angular Ivy, et comprendre son rôle dans le rendu dynamique des éléments du DOM.

Une directive structurelle, comme NgIf ou NgFor, crée une vue intégrée associée à un contexte de vue particulier. Par exemple, lorsque la directive NgIf est utilisée, elle génère une vue dynamique dont l'état est lié à une structure de données spécifique. Ce contexte de vue, appelé NgIfContext, a une forme bien définie : une propriété $implicit, qui représente l’état implicite de la directive (en l’occurrence un booléen), et une autre propriété, ngIf, qui indique si l'élément doit ou non être affiché. Cette structure est simple mais cruciale pour la gestion de l’affichage conditionnel.

De même, la directive NgFor, qui est utilisée pour afficher des listes, crée un autre type de contexte, le NgForOfContext. Ce dernier offre une représentation plus riche, incluant des informations telles que l'élément actuellement itéré ($implicit), le nombre total d'éléments (count), l’indice de l’élément dans la liste (index), ainsi que des informations utiles comme si l'élément est pair, premier, dernier, ou impair. Grâce à cette organisation, chaque vue intégrée générée par NgFor est liée à des propriétés spécifiques à cet élément, mais elle conserve également l’accès à des métadonnées générales sur l’ensemble de la liste.

Lorsqu’on interroge un élément avec une directive structurelle attachée, l’API Angular Ivy permet de récupérer ce contexte de vue spécifique via la méthode ng.getContext(). Par exemple, en passant un élément contenant une directive NgIf, la méthode retournera un objet NgIfContext avec les valeurs correspondantes à la directive. Si l'élément appartient à une itération NgFor, le contexte retourné sera un objet NgForOfContext détaillant l'état de l'élément dans la liste.

L’interrogation d’un élément du DOM avec une directive structurelle permet d'accéder à des informations essentielles, telles que l’indice de l’élément dans la liste ou si c'est le premier ou le dernier de la séquence. Ces informations peuvent ensuite être utilisées pour ajuster dynamiquement le comportement de l’application ou pour des actions de débogage. Prenons l'exemple suivant : en interrogeant un élément d'une liste d'utilisateurs avec la méthode ng.getContext(), nous obtenons un contexte précis sur l'élément concerné, comme l'indice ou la position dans la liste. Cela permet non seulement de mieux comprendre le comportement de l'application, mais aussi de manipuler de manière fine l’affichage des éléments de manière dynamique.

Il est crucial de comprendre que lors de l’utilisation de directives structurelles, un seul contexte de vue est attaché à chaque élément du DOM. Par conséquent, lorsque vous avez besoin d’appliquer plusieurs directives structurelles à un même élément, la pratique recommandée est d’envelopper cet élément dans un conteneur spécial et de l’appliquer ensuite à ce conteneur. Cette méthode garantit la bonne gestion des contextes, tout en permettant l’usage multiple de directives dans un même espace DOM.

Le débogage avec l’API de débogage Angular Ivy permet d’inspecter de manière approfondie l’état interne de l’application. En accédant à ces contextes de vue et en modifiant directement l’état du composant, les développeurs peuvent simuler des changements, déclencher une détection des modifications, et observer instantanément l'impact sur le DOM. Cela ouvre une nouvelle ère dans le débogage des applications Angular, où chaque élément de la vue peut être analysé et manipulé à la volée. De plus, cette approche simplifie grandement le processus de développement en permettant une meilleure compréhension des mécanismes internes d'Angular.

L'un des aspects les plus importants à comprendre lors de l'inspection des contextes de vues est la gestion dynamique des états au sein des directives structurelles. Chaque élément du DOM qui est géré par une directive comme NgIf ou NgFor n'est pas simplement un élément statique, mais plutôt une vue dynamique liée à un état particulier du composant ou de l’application. La capacité à interroger ces états à tout moment permet de mieux contrôler le rendu et le comportement des vues, et d’optimiser la gestion des performances.

Comment optimiser le support régional avec des API de mondialisation améliorées

Les applications multilingues utilisent la mondialisation pour offrir aux utilisateurs de différents pays et origines une expérience régionale adaptée. Angular dispose d'API intégrées pour gérer à la fois l'internationalisation et la localisation. Dans cette section, nous allons examiner les configurations et les exemples de mise en œuvre pour illustrer certaines des nouvelles possibilités de mondialisation offertes par Ivy.

Angular utilise des données locales pour gérer les variations régionales telles que le formatage des dates, des devises, des nombres décimaux et des pourcentages. Avec Ivy, il est désormais possible de regrouper une seule locale dans le cadre de la compilation en utilisant l'option de build localize. Supposons que nous souhaitions que notre application utilise la locale française. Nous pourrions configurer la compilation du projet de la manière suivante, ce qui remplace implicitement la valeur fournie pour le jeton d'injection de dépendance LOCALE_ID dans le paquet @angular/core :

json
{
"projects": { "my-app": { "projectType": "application", "i18n": { "locales": { "fr": "src/locales/translations.fr.xlf" } }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "localize": ["fr"] } } } } } }

L'option localize indique que la locale française (fr) est intégrée et chargée avec l'application, tandis que l'option locales.fr spécifie le chemin du fichier de traduction en français. Lors de la migration vers Ivy, il est également nécessaire d'exécuter la commande ng add @angular/localize pour activer les API de mondialisation intégrées d'Angular. Si ces API ne sont pas utilisées, nous pouvons omettre ce paquet afin d'éviter d'augmenter la taille du bundle. Il est également possible de créer une configuration de build par locale, mais cela sera laissé comme un exercice pour le lecteur. En utilisant les API de mondialisation d'Angular, la vitesse de build pour la localisation a considérablement augmenté dans Ivy.

Avant Angular Ivy, il était nécessaire de charger et d'enregistrer les données de toutes les locales à supporter dans l'application, à l'exception de la locale "en-US" qui était toujours intégrée. Cela se faisait à l'aide de la fonction registerLocaleData. Lorsqu'une application utilise un build contenant une locale et des traductions intégrées, registerLocaleData reste nécessaire. Cependant, si nous n'utilisons pas les API d'internationalisation intégrées d'Angular, il est possible de charger paresseusement les données locales, ce qui s'intègre bien avec les bibliothèques de traduction dynamique telles que ngx-translate ou Transloco.

Pour charger paresseusement les données locales, nous pouvons importer dynamiquement le sous-paquet @angular/common/locales/global/fr pour la locale française. Voici un exemple de service basé sur une classe que l'on peut utiliser avec un sélecteur de locale :

typescript
import { Injectable } from '@angular/core';
import { EMPTY, from, Observable } from 'rxjs'; import { catchError, mapTo } from 'rxjs/operators';
import { LanguageTag } from '../../shared/ui/language-tag';
@Injectable({ providedIn: 'root', }) export class LocaleLoader { load(locale: LanguageTag): Observable<void> {
return from(import(`@angular/common/locales/global/${locale}`)).pipe(
catchError(() => { console.error(`Error when loading locale "${locale}"`); return EMPTY; }), mapTo(undefined) ); } }

Le type LanguageTag représente une chaîne de texte suivant le format BCP47. Le service LocaleLoader utilise la syntaxe d'importation dynamique pour charger paresseusement les données locales et signaler toute erreur dans la console du navigateur. Cela est encapsulé dans un observable.

Le composant LocalePickerComponent sert à afficher un sélecteur de locale. Il ne déclenche pas directement des effets secondaires lorsqu'un utilisateur sélectionne une locale, mais émet la locale sélectionnée via sa propriété de sortie localeChange :

typescript
import { Component, Input, Output, ChangeDetectionStrategy } from '@angular/core';
import { FormControl, Validators } from '@angular/forms'; import { Observable } from 'rxjs';
import { LanguageTag } from '../../shared/ui/language-tag';
@Component({ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'app-locale-picker', styles: [':host { display: block; }'], templateUrl: './locale-picker.component.html', }) export class LocalePickerComponent { @Input() set locale(value: LanguageTag) { this.selectedLocale.setValue(value, { emitEvent: false, emitViewToModelChange: false, }); }
@Input() locales: ReadonlyArray<LanguageTag> = [];
@Output() localeChange: Observable<LanguageTag> = validValueChanges(this.selectedLocale); selectedLocale = new FormControl('', [Validators.required, localeValidator]); }

Le validateur localeValidator vérifie que la chaîne de texte saisie correspond au format de tag de langue spécifié par BCP47. Il utilise une expression régulière pour valider le tag de langue :

typescript
export const languageTagPattern = /^[a-z]{2,3}(-[A-Z]{1}[a-z]{3})?(-[A-Z]{2}|\d{3})?$/;

Enfin, localeValidator recherche le tag de langue dans une liste de locales connues. Ce composant ne déclenche pas de changements d'état internes mais émet simplement la locale sélectionnée via son mécanisme de sortie.

Une autre avancée apportée par Ivy est la gestion dynamique de l'attribut dir, qui est maintenant possible grâce à la fonction getLocaleDirection dans le paquet @angular/common. Cela permet d'ajuster la direction du texte en fonction de la locale sélectionnée, offrant ainsi une flexibilité supplémentaire pour les applications multilingues.

Dans ce contexte, il devient essentiel de comprendre que le choix de la méthode de chargement des données locales peut affecter de manière significative les performances de l'application, surtout si celle-ci doit supporter plusieurs locales. La gestion de la charge des traductions et des données locales doit être optimisée pour éviter d'alourdir inutilement les fichiers de build. Par ailleurs, l'utilisation d'une approche de chargement paresseux des locales s'avère plus efficace lorsque des bibliothèques de traduction dynamique sont intégrées dans l'application.