web-dev-qa-db-fra.com

Générique Angular Composants - Liaisons facultatives

Je veux créer un tas de composants génériques (angulaire 1.5) avec plusieurs liaisons optionnelles qui seraient utilisées dans plusieurs applications. 

Je crains que cela ne crée beaucoup d'observateurs inutiles pour une application qui n'utilise pas le maximum de liaisons facultatives.

Exemple:

Déclaration du composant:  

let dateRangeComponent = {
    bindings: {
        label: '@',
        name1: '@',
        name2: '@',
        model1: '>?',
        model2: '>?',
        extra1: '>?'
    },
    template: `<div ng-if="$ctrl.model1>stuff</div>
               <div ng-if="$ctrl.model2>stuff</div>
               <div ng-if="$ctrl.extra1>stuff</div>`
};

Exemple d'utilisation du composant:  

<date-rage-component label="Pretty Date" name1="Start" name2="end"/>

Ma question est de savoir s'il est possible de décompresser automatiquement tous les éléments liés aux liaisons facultatives non utilisées, sachant qu'elles ne sont pas définies au moment de la compilation.

Par exemple, imaginons que je souhaite utiliser un composant dans mon application qui ne nécessite aucun élément de la liaison facultative Binding, angular créerait un grand nombre d'observateurs inutiles pour conserver le ng-si mis à jour, lorsque nous savons qu'il sera toujours faux.

Suis-je en train d’optimiser les performances dès que je n’en ai pas besoin ou si je comprends mal un concept?

Je pensais qu'en créant une directive costum wrapper pour tirer parti de la compilation paresseuse de la transclude dans angular 1.5

Quelque chose comme ça (pseudo-code, non testé):

<optional-binding-once ng-if="::attrs.model1">
  <div ng-if="attrs.model1">
      stuff
  </div>
</optional-binding-once>

De cette façon, je pense que le code contenu dans optional-binding-once ne serait compilé que si ng-if est vrai, ce qui réduirait l'observateur si une liaison n'est pas définie.

(EDIT) Quelques conclusions après quelques tests et recherches

Eh bien, je suppose qu’il n’ya pas de solution triviale pour réduire le nombre d’observateurs dans un composant lorsque des liaisons facultatives ne sont pas renseignées.

J'ai effectué quelques tests à travers la phase $ digest de angular, afin de vérifier si le nombre accru d'observateurs de ce type est vraiment problématique.

Voici mes résultats:

Les tests ont été effectués dans le pire des scénarios avec 888 composants avec 4 liaisons facultatives.

Chrome - Sans fixations facultatives (composant 888, total des observateurs 889)

  • Nombre total d'observateurs: 889
  • Temps de cycle du dernier condensé: 0.9950000000026193
  • Durée moyenne des 1004 derniers cycles de résumé: 1,0544920318724353 ms
  • démarrage du chargement de dom (400ms)

Chrome - Avec liaisons en option (composant 888, 4 liaisons en option, total watchers 4441)

  • Observateurs totaux: 4441
  • Temps de cycle du dernier condensé: 1.1549999999988358
  • Durée moyenne des 1001 derniers cycles de résumé: 1,6851748251747816 ms
  • démarrage du chargement de dom (600ms)

Safari - Sans liaisons optionnelles (composant 888, observateurs totaux 889)

  • Nombre total d'observateurs: 889
  • Durée du dernier cycle de digestion: 1.0849999999991269
  • Durée moyenne des 530 derniers cycles de résumé: 1,211632075471664 ms

Safari - Avec liaisons optionnelles (composant 888, 4 liaisons optionnelles, total watchers 4441)

  • Observateurs totaux: 4441
  • Temps de cycle du dernier condensé: 1.7450000000026193
  • Durée moyenne des 588 derniers cycles de résumé: 2.1167176870748237 ms

Conclusions:

Dans le pire des cas, le temps de digestion $ sera augmenté de 1 ms. Je ne pense pas que cette augmentation constituera un goulot d'étranglement pour les performances de mes applications. Ce type d'observateurs échouera dans la première condition $ digest (valeur = get (actuel))! == (dernier = watch.last) && etc ...), ce qui aura un impact mineur sur le temps de traitement, car ils ne changer ou salir le contexte angulaire!

20
Luis Neves

J'utiliserais le fait que la propriété template peut être une function (tElem, tAttrs) { ... } ( docs ) qui renvoie une chaîne pour modifier le modèle en fonction des attributs présents.

Pour ce faire, jQuery et certains éléments personnalisés sont utilisés pour indiquer les parties du modèle conditionnelles.

Voici une fonction exemple de modèle rapide:

function template($element, $attrs) {
  var fullTemplate = $('<div><if-attr name="a"><div ng-if="$ctrl.a"></div></if-attr></div>');
  fullTemplate.find('if-attr').each(function() {
    if (attrs.hasOwnProperty($(this).attr('name'))) {
      $(this).replaceWith(this.innerHTML);
    } else {
      $(this).remove();
    }
  });
  return fullTemplate[0].outerHTML;
}

Échantillon de sortie

template(null, {a: '1'}) => "<div><div ng-if="$ctrl.a"></div></div>"
template(null, {b: '1'}) => "<div></div>"

Limites connues

Cela tombe en panne si vous voulez récupérer le modèle à partir d'une URL (et il n'est pas pré-rempli dans le $templateCache), mais cela ne semble pas être votre cas.

Si minifiant

La documentation indique que si template est une fonction, elle est injectée avec $element et $attrs. Cela signifie que si vous réduisez votre code, veillez à utiliser une méthode de spécification sans danger pour la minification, qui spécifie les noms des paramètres de la fonction. P. Ex. 

template: ['$element', '$attrs', function ($elem, $attrs) { 
    // ...
}],

ou 

function templateFn($elem, $attrs) { 
    // ...
}
templateFn['$inject'] = ['$element', '$attrs'];

template: templateFn,
1
GregL

Il vous suffit de garder une liaison unique avec {{:: variable}} pour être empêché par plusieurs observateurs. Dans ce cas, vous ne rencontrerez aucun problème de performances.

1
Mr. Raj Kale

Vous devez détruire la liaison de composant après un appel de composant.

S'il vous plaît vérifier et laissez-moi savoir si vous avez besoin de plus de détails.

https://toddmotto.com/angular-1-5-lifecycle-hooks#using-ondestroy

0
Akash Gadhiya

Une autre suggestion serait de ne PAS créer de composant générique. Reportez plutôt la logique métier aux services et créez des composants spécifiques. Laissez le code du consommateur décider du composant à utiliser en fonction de ses besoins. Si vous avez beaucoup de comportements communs partagés entre plusieurs composants, vous pouvez injecter le service dans les composants pour les réutiliser. Envisagez de scinder la logique métier en plusieurs services et utilisez une conception hiérarchique pour réutiliser le code, tout en permettant une spécification en fonction du cas. Poussez partagé en code vers un service abstrait et étendez-le en services concrets. Injectez les services concrets dans vos composants. Soyez heureux :).

0
Juliano

Un bon moyen est la réponse de @GregL, utilisez un modèle différent avec des attributs différents, mais vous pouvez aussi utiliser un ng-attr- [nomCustomAttr] = "valeur", pour les liaisons facultatives, voir ma réponse associée , et de cette façon, angular utilise un type de bindingOnce et vérifie si le attr a une valeur et ajoute ou non l'attribut dépendant de la valeur.

Pour cela, les attributs doivent rester sur le modèle de la directive/composante.

Remarque: angularjs crée une surveillance uniquement pour les variables qui apparaissent dans l'interface utilisateur.

Eh bien, bonne chance, j'espère que cela vous aide dans quelque chose.

0
Sieg