98 votes

AngularJs : Personnalisation du modèle au sein d’une Directive

J'ai un formulaire qui est à l'aide de balisage de Bootstrap, comme suit:

<form class="form-horizontal">
  <fieldset>
    <legend>Legend text</legend>
    <div class="control-group">
      <label class="control-label" for="nameInput">Name</label>
      <div class="controls">
        <input type="text" class="input-xlarge" id="nameInput">
        <p class="help-block">Supporting help text</p>
      </div>
    </div>
  </fieldset>
</form>

Il y a beaucoup de code réutilisable, que j'aimerais réduire à une nouvelle directive - formulaire d'entrée, comme suit:

<form-input label="Name" form-id="nameInput"></form-input>

génère:

   <div class="control-group">
      <label class="control-label" for="nameInput">Name</label>
      <div class="controls">
        <input type="text" class="input-xlarge" id="nameInput">
      </div>
    </div>

J'ai à présent beaucoup de travail via un simple modèle.

angular.module('formComponents', [])
    .directive('formInput', function() {
        return {
            restrict: 'E',
            scope: {
                label: 'bind',
                formId: 'bind'
            },
            template:   '<div class="control-group">' +
                            '<label class="control-label" for="{{formId}}">{{label}}</label>' +
                            '<div class="controls">' +
                                '<input type="text" class="input-xlarge" id="{{formId}}" name="{{formId}}">' +
                            '</div>' +
                        '</div>'

        }
    })

Cependant, c'est quand je viens d'ajouter des fonctionnalités plus avancées que je suis coincé.

Comment puis-je soutenir les valeurs par défaut dans le modèle?

J'aimerais exposer le "paramètre" type d'un attribut facultatif sur mon directive, par exemple:

<form-input label="Password" form-id="password" type="password"/></form-input>
<form-input label="Email address" form-id="emailAddress" type="email" /></form-input>

Toutefois, si rien n'est spécifié, je tiens à défaut d' "text". Comment puis-je supporter cela?

Comment puis-je personnaliser le modèle en fonction de la présence / absence d'attributs?

Je tiens également à être en mesure de soutenir l'attribut required, si elle est présente. Par exemple:

<form-input label="Email address" form-id="emailAddress" type="email" required/></form-input>

Si required est présent dans la directive, je voudrais ajouter à la générées <input /> à la sortie, et l'ignorer sinon. Je ne suis pas sûr de savoir comment y parvenir.

Je soupçonne ces exigences sont peut-être passés au-delà d'un modèle simple, et commencer à utiliser le pré-compiler les phases, mais je suis à une perte par où commencer.

211voto

Misko Hevery Points 25631
angular.module('formComponents', [])
  .directive('formInput', function() {
    return {
        restrict: 'E',
        compile: function(element, attrs)
        {
            var type = attrs.type || 'text';
            var required = attrs.hasOwnProperty('required') ? "required='required'" : "";
            var htmlText = '<div class="control-group">' +
                '<label class="control-label" for="' + attrs.formId + '">' + attrs.label + '</label>' +
                    '<div class="controls">' +
                    '<input type="' + type + '" class="input-xlarge" id="' + attrs.formId + '" name="' + attrs.formId + '" ' + required + '>' +
                    '</div>' +
                '</div>';
            element.replaceWith(htmlText);
        }
    }
})

38voto

Janusz Gryszko Points 71

Essayé d'utiliser la solution proposée par Misko, mais dans ma situation, certains attributs, qui a besoin d'être fusionnés dans mon template html, étaient eux-mêmes directives.

Malheureusement, pas toutes les directives référencé par la modèle ne fonctionne pas correctement. Je n'ai pas assez de temps pour plonger dans angulaire de code et de trouver la cause du problème, mais a trouvé une solution de contournement, qui pourrait éventuellement être utile.

La solution a été de passer le code, ce qui crée le modèle html, de les compiler en une fonction de modèle. Exemple basé sur le code ci-dessus:

    angular.module('formComponents', [])
  .directive('formInput', function() {
    return {
        restrict: 'E',
        template: function(element, attrs) {
           var type = attrs.type || 'text';
            var required = attrs.hasOwnProperty('required') ? "required='required'" : "";
            var htmlText = '<div class="control-group">' +
                '<label class="control-label" for="' + attrs.formId + '">' + attrs.label + '</label>' +
                    '<div class="controls">' +
                    '<input type="' + type + '" class="input-xlarge" id="' + attrs.formId + '" name="' + attrs.formId + '" ' + required + '>' +
                    '</div>' +
                '</div>';
             return htmlText;
        }
        compile: function(element, attrs)
        {
           //do whatever else is necessary
        }
    }
})

5voto

JoeS Points 88

Les réponses ci-dessus, malheureusement, n'a pas assez de travail. En particulier, l'étape de la compilation n'a pas accès à l'étendue, de sorte que vous ne pouvez pas personnaliser le champ basé sur les attributs dynamiques. À l'aide de l'étape de lien semble offrir le plus de flexibilité (en termes de manière asynchrone de la création de dom, etc.) Ci-dessous l'approche adresses:

<!-- Usage: -->
<form>
  <form-field ng-model="formModel[field.attr]" field="field" ng-repeat="field in fields">
</form>

// directive
angular.module('app')
.directive('formField', function($compile, $parse) {
  return { 
    restrict: 'E', 
    compile: function(element, attrs) {
      var fieldGetter = $parse(attrs.field);

      return function (scope, element, attrs) {
        var template, field, id;
        field = fieldGetter(scope);
        template = '..your dom structure here...'
        element.replaceWith($compile(template)(scope));
      }
    }
  }
})

J'ai créé un gist avec code plus complet et à un writeup de l'approche.

4voto

Marty Pitt Points 8239

Voici ce que j’ai fini par utiliser.

Je suis très nouveau à AngularJS, alors j’adorerais voir des solutions mieux / alternatives.

Exemple d’utilisation :

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X