web-dev-qa-db-fra.com

Comment remplacer un élément dans la fonction de liaison des directives AngularJS?

Je crée une directive <row> AngularJS qui doit se remplacer (la balise <row> Ne doit pas figurer dans le DOM après exécution) par un modèle dynamique pouvant contenir du code HTML.

Le problème de l’utilisation de replace: true Est qu’il ne fonctionne pas avec les balises <tr> De la table et que le modèle est choisi de manière dynamique.

J'essaie donc de trouver un moyen de remplacer l'élément dans la fonction de liaison, sans succès.

L'utilisation de .replaceWith() de jQuery interrompt ngRepeat pour une raison inconnue.

Des allusions?

Voici le violon

40
Antonio Madonna

Votre violon semble assez basique, mais vous devriez pouvoir utiliser simplement outerHTML

element[0].outerHTML ='<div>I should not be red</div>';

Violon mis à jour

Si vous devez traiter avec ng-repeat, Vous pouvez lier vos éléments à une propriété d’étendue et les référencer dans votre modèle que vous compilez. Une fois compilé, vous pouvez utiliser jQuery replaceWith()

html

<row items="items">***</row>

directif

.directive('row', function ($compile) {
    return {
        restrict: 'E',
        scope: {
            items: "="
        },
        link: function (scope, element, attrs) {
            var html ='<div ng-repeat="item in items">I should not be red</div>';
            var e =$compile(html)(scope);
            element.replaceWith(e);
        }
    };
});

exemple ng-repeat

52
Mark Coleman

La réponse de Mark fonctionnera, cependant, cet exemple est trop limité pour donner une image complète. Alors que la directive de Mark peut en effet suffire pour des composants d'interface utilisateur courants et simples, cette configuration doit être évitée pour des opérations plus complexes. Ci-dessous, j'explique en détail la raison derrière cela. En fait, Angular déjà fournit un moyen beaucoup plus simple de remplacer l'élément de directive par un modèle. Vous pouvez le trouver. au bas de cette réponse.

Voici comment une directive regarde en coulisse:

.directive('row', function ($compile) {
  return {
      restrict: 'E',
      scope: {
          items: "="
      },

      // Whether you define it this way or not, this is the order of
      // operation (execution) behind every AngularJS directive.
      // When you use the more simple syntax, Angular actually generates this
      // structure for you (this is done by the $compile service):

      compile: function CompilingFunction($templateElement, $templateAttributes, transcludeFn) {

        // The compile function hooks you up into the DOM before any scope is
        // applied onto the template. It allows you to read attributes from
        // the directive expression (i.e. tag name, attribute, class name or
        // comment) and manipulate the DOM (and only the DOM) as you wish.

        // When you let Angular generate this portion for you, it basically
        // appends your template into the DOM, and then some ("some" includes
        // the transclude operation, but that's out of the $scope of my answer ;) )

          return function LinkingFunction($scope, $element, $attrs) {

            // The link function is usually what we become familiar with when
            // starting to learn how to use directives. It gets fired after
            // the template has been compiled, providing you a space to
            // manipulate the directive's scope as well as DOM elements.

            var html ='<div ng-repeat="item in items">I should not be red</div>';
            var e = $compile(html)($scope);
            $element.replaceWith(e);
          };
      }
  };
});

Que pouvons-nous en tirer? Il est donc évident que l'appelant manuellement $compile pour la même présentation DOM deux fois est redondant, mauvais pour les performances et mauvais pour vos dents, aussi. Que devriez-vous faire à la place? Compilez simplement votre DOM où il devrait être compilé:

.directive('row', function ($compile) {
  return {
      restrict: 'E',
      template: '<div ng-repeat="item in items">I should not be red</div>',
      scope: {
          items: "="
      },

      compile: function CompilingFunction($templateElement, $templateAttributes) {
          $templateElement.replaceWith(this.template);

          return function LinkingFunction($scope, $element, $attrs) {
            // play with the $scope here, if you need too.
          };
      }
  };
});

Si vous voulez plonger plus loin sous le capot des directives, voici ce que j'aime appeler le non officiel référence de la directive AngularJS

Une fois que vous avez terminé avec cette tête ici: https://github.com/angular/angular.js/wiki/Understanding-Directives


Maintenant, comme promis, voici la solution pour laquelle vous êtes venu:

En utilisant replace: true:

.directive('row', function ($compile) {
    return {
        restrict: 'E',
        template: '<div ng-repeat="item in items">I should not be red</div>',
        replace: true,
        scope: {
            items: "="
        }
    };
});
99
pilau