web-dev-qa-db-fra.com

Directive AngularJS pour analyser et remplacer le contenu des éléments personnalisés

Je voudrais créer une directive de démarquage simple qui accepte du contenu dans l'élément, le analyse et le remplace par HTML.

Donc ça:

<markdown>#Heading</markdown>

ou ce ( où $ scope.heading = '#Heading'; )

<markdown>{{heading}}</markdown>

Devient ceci:

<h1>Heading</h1>

Ma directive à ce jour (évidemment pas complète!):

.directive('markdown', function () {
    return {
        restrict: 'E',
        replace: true,
        link: function ($scope, $element, $attrs) {
            // Grab contents
                var contents = /* How do I do this? */

                var newContents = Markdowner.transform(contents);

                // Replace <markdown> element with newContents
                /* How do I do this? */
        }
    }
})

Je ne suis pas sûr de savoir comment récupérer le contenu de la directive? Aurais-je besoin de le compiler?!

L'analyse syntaxique n'est qu'un exemple

10
Greg

Voici!

Démo de travail

app.directive('markdown', function() {
  return {
    restrict: 'E',
    transclude: true,
    compile: function(elem) {
      elem.replaceWith(Markdowner.transform(elem.html()));
    }
  }
});
7
jessegavin

ngTransclude est spécialement conçu pour cela.

myModule.directive('heading', function() {
    return {
        restrict: 'E',
        replace: true,
        transclude: true,
        scope: true,
        template: '<h1 ng-transclude></h1>'
    };
}

Ensuite, utilisez-le comme ceci:

<heading><span>{{foo}}</span></heading>

Voici un travail violon (angulaire 1.2.7).

En outre, je suppose que vous avez besoin d'une sorte d'intégration de démarque. Voici une version utilisant transclude pour vous retrouver avec un conteneur div.

Celui-ci passe tout le comportement de la transclude et je suppose que c'est plus proche de ce que vous recherchez.

6
Sergiu Paraschiv

Vous pouvez obtenir et définir le contenu compilé de l'élément dans la fonction de liaison à l'aide de:

element.html() //get
element.html("blah") //set

Voici un exemple basé sur l'exemple de Sergiu ci-dessous qui traite les liaisons contenues dans le code HTML à l'aide de scope.$eval(), avant d'appeler le convertisseur de démarque:

http://jsfiddle.net/edeustace/4rE85/1/

angular.module('transclude', [])
 .directive('markdown', function() {

  var regex = /\{\{(.*?)\}\}/;

  var converter = new Showdown.converter();

  return {
    restrict: 'E',
    replace: true,
    scope: true,
    link: function (scope, element) {

      var processTemplate = function(text){
        var results = text.match(regex);
        if(!results){
          return text;
        } else {
          var value = scope.$eval(results[1]);
          var replaceKey = new RegExp("{{" + results[1] + "}}","g");
            text = text.replace(replaceKey, value);
            return processTemplate(text);
        }
     };
     var text = element.text();
     var processed = processTemplate(text);
     var markdownText = converter.makeHtml(processed);
     element.html(markdownText);
    }

  };
});

qui travaillera avec:

<markdown>
# Bar {{foo}} {{foo}}
# {{bing}}
</markdown>

Ou vous pouvez le lier à un attribut que vous pouvez ensuite utiliser dans votre directive:

app.directive('markdownWithBinding', function () {

  var converter = new Showdown.converter();

  return {
    restrict: 'E',
    scope: {
      'md' : '@'
    },
    link: function  ($scope, $element, $attrs) {

      $scope.$watch('md', function(newMd){

        var markdownText = converter.makeHtml(newMd);
        element.html(markdownText);

      });
    }
  }
});

Utilisé comme tel:

<markdown-with-binding md="Hello {{name}}"></markdown-with-binding> 
<!-- outputs Hello World!!! -->

Ancienne réponse

Cela se produira dans link (), qui sert à relier la portée à l'élément. Pour les modifications structurelles pour lesquelles aucune étendue n'est requise, il peut être préférable d'effectuer vos modifications dans la fonction de compilation:

app.directive('markdown', function () {

var link = function ($scope, $element, $attrs) {};
return {
    restrict: 'E',
    replace: true,
  compile: function($element, $attrs, $transclude){

    if($element.html() == "#Hello"){
      $element.html("<h1>Hello</h1>");
    }
    return link;
  },
}

});

Voici un excellent tutoriel sur les composants: http://www.youtube.com/watch?v=A6wq16Ow5Ec

3
ed.

Sur votre fonction de liaison, AngularJS a déjà analysé votre code HTML et remplacé le contenu par votre modèle (qui, dans votre cas, est manquant, car vous avez "remplacer" défini sur true).

Vous pouvez récupérer le contenu HTML interne à partir de l'élément $, qui est un élément jQuery (jQLite).

var contents = $element.innerHTML;
0
Jonas