297 votes

AngularJS - créer une directive qui utilise ng-modèle

Je suis en train de créer une directive qui permettrait de créer un champ de saisie avec la même ng-model comme l'élément qui crée la directive.

Voici ce que j'ai trouvé jusqu'à présent:

HTML

<!doctype html>
<html ng-app="plunker" >
<head>
  <meta charset="utf-8">
  <title>AngularJS Plunker</title>
  <link rel="stylesheet" href="style.css">
  <script>document.write("<base href=\"" + document.location + "\" />");</script>
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
  <script src="app.js"></script>
</head>
<body ng-controller="MainCtrl">
  This scope value <input ng-model="name">
  <my-directive ng-model="name"></my-directive>
</body>
</html>

JavaScript

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.name = "Felipe";
});

app.directive('myDirective', function($compile) {
  return {
    restrict: 'E',
    scope: {
      ngModel: '='
    },
    template: '<div class="some"><label for="{{id}}">{{label}}</label>' +
      '<input id="{{id}}" ng-model="value"></div>',
    replace: true,
    require: 'ngModel',
    link: function($scope, elem, attr, ctrl) {
      $scope.label = attr.ngModel;
      $scope.id = attr.ngModel;
      console.debug(attr.ngModel);
      console.debug($scope.$parent.$eval(attr.ngModel));
      var textField = $('input', elem).
        attr('ng-model', attr.ngModel).
        val($scope.$parent.$eval(attr.ngModel));

      $compile(textField)($scope.$parent);
    }
  };
});

Cependant, je ne suis pas sûr que ce est la bonne façon de gérer ce scénario, et il y a un bug que ma commande n'est pas prise en initialisé avec la valeur de la ng-modèle de champ cible.

Voici un Plunker du code ci-dessus: http://plnkr.co/edit/IvrDbJ

Quelle est la façon correcte de ce traitement?

EDIT: Après la suppression de l' ng-model="value" à partir du modèle, cela semble fonctionner correctement. Cependant, je vais garder cette question parce que je veux vérifier que c'est la bonne façon de le faire.

211voto

Roy Truelove Points 6532

C'est en fait assez bonne logique, mais vous pouvez simplifier un peu les choses.

La Directive

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {
  $scope.model = { name: 'World' };
  $scope.name = "Felipe";
});

app.directive('myDirective', function($compile) {
  return {
    restrict: 'AE', //attribute or element
    scope: {
      myDirectiveVar: '=',
     //bindAttr: '='
    },
    template: '<div class="some">' +
      '<input ng-model="myDirectiveVar"></div>',
    replace: true,
    //require: 'ngModel',
    link: function($scope, elem, attr, ctrl) {
      console.debug($scope);
      //var textField = $('input', elem).attr('ng-model', 'myDirectiveVar');
      // $compile(textField)($scope.$parent);
    }
  };
});

Html avec la directive

<body ng-controller="MainCtrl">
  This scope value <input ng-model="name">
  <my-directive my-directive-var="name"></my-directive>
</body>

CSS

.some {
  border: 1px solid #cacaca;
  padding: 10px;
}

Vous pouvez le voir en action avec cette Plunker.

Voici ce que je vois:

  • Je comprends pas pourquoi vous voulez utiliser "ng-model", mais dans votre cas, il n'est pas nécessaire. ng-modèle de lien existant éléments html avec une valeur dans le champ d'application. Puisque vous êtes la création d'une directive-vous que vous êtes en train de créer un "nouveau" de l'élément html, de sorte que vous n'avez pas besoin de ng-model.

MODIFIER Comme indiqué par la Marque dans son commentaire, il n'y a aucune raison que vous ne pouvez pas utiliser ng-model, juste pour garder de la convention.

  • Explicitement la création d'un champ dans votre directive ("isolé" champ d'application), du champ de la directive ne peut pas accéder le nom de la variable sur la portée parent (c'est pourquoi, je pense que vous avez voulu utiliser ng-model).
  • J'ai enlevé ngModel de votre directive et l'a remplacé avec un nom personnalisé que vous pouvez modifier en quoi que ce soit.
  • La chose qui rend tout cela encore du travail, c'est que '=' signe dans le champ d'application. La caisse de l'docs docs en vertu de la "portée" de l'en-tête.

En général, vos directives devraient utiliser les isolés portée (que vous n'avez correctement) et d'utiliser le '=' type de portée si vous voulez une valeur dans votre directive toujours une carte à une valeur de la portée parent.

69voto

w00t Points 1253

J'ai pris un combo de toutes les réponses, et ont maintenant deux façons de le faire avec la ng-attribut du modèle:

  • Avec un nouveau champ d'application de copie de ngModel
  • Avec la même portée qui fait une compilation sur le lien

Je ne suis pas sûr que j'aime la compilation au moment de la liaison. Toutefois, si vous êtes juste de remplacement de l'élément avec l'autre, vous n'avez pas besoin de le faire.

Plunker est ici: http://plnkr.co/edit/D2keMc?p=preview

Dans l'ensemble je préfère la première. Suffit de définir la portée d' {ngModel:"="} et définissez ng-model="ngModel" où vous le souhaitez dans votre modèle.

54voto

AiShiguang Points 261

ce n'est pas si compliqué: dans votre dirctive, utilisez un alias: scope:{alias:'=ngModel'}

 .directive('dateselect', function () {
return {
    restrict: 'E',
    transclude: true,
    scope:{
        bindModel:'=ngModel'
    },
    template:'<input ng-model="bindModel"/>'
}
 

dans votre code HTML, utilisez comme d'habitude

 <dateselect ng-model="birthday"></dateselect>
 

31voto

asgoth Points 14599

Vous avez seulement besoin de ng-model quand vous avez besoin d'accéder au $ viewValue ou au modelValue du modèle. Voir NgModelController . Et dans ce cas, vous utiliserez require: '^ngModel' .

Pour le reste, voyez Roys répondre .

2voto

Mathew Berg Points 7247

Je ne définirais pas le ngmodel via un attribut, vous pouvez le spécifier directement dans le template:

 template: '<div class="some"><label>{{label}}</label><input data-ng-model="ngModel"></div>',
 

plunker : http://plnkr.co/edit/9vtmnw?p=preview

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