web-dev-qa-db-fra.com

Liaison de données bidirectionnelle dans les directives AngularJS

J'ai essayé de définir des directives afin de pouvoir afficher différents "widgets" dans un formulaire, selon le type de champ et ses paramètres, qui sont stockés dans une base de données. Je dois réagir à différents types de scénarios, d'où la nécessité de directives pour gérer la mise en page.

En jouant avec quelques exemples, j'ai trouvé un code qui * fonctionne * un peu:

HTML

<input type="text" ng-model="myModel" style="width: 90%"/>  
<div class="zippy" zippy-title="myModel"></div>

Directif

myApp.directive('zippy', function(){
    return {
      restrict: 'C',
      // This HTML will replace the zippy directive.
      transclude: true,
      scope: { title:'=zippyTitle' },
      template: '<input type="text" value="{{title}}"style="width: 90%"/>',
      // The linking function will add behavior to the template
      link: function(scope, element, attrs) {
            // Title element
            element.bind('blur keyup change', function() {
                scope.$apply(read);
            });

            var input = element.children();


            function read() {
                scope.title = input.val();
            }
        }
    }
});

Cela semble fonctionner (bien que sensiblement plus lent qu'une liaison de variable angularJS * appropriée *), mais je pense qu'il doit y avoir une meilleure façon de le faire. Quelqu'un peut-il faire la lumière sur la question?

29
Tiago Roldão

Je ne sais pas pourquoi vous déclenchez le $apply méthode manuellement car vous n'en avez réellement pas besoin.

J'ai édité l'exemple que vous avez utilisé à partir de la page Angular et inclus l'entrée. Cela fonctionne pour moi: http://jsfiddle.net/6HcGS/2/

[~ # ~] html [~ # ~]

<div ng-app="zippyModule">
  <div ng-controller="Ctrl3">
    Title: <input ng-model="title">
    <hr>
    <div class="zippy" zippy-title="title"></div>
  </div>
</div>​

[~ # ~] js [~ # ~]

function Ctrl3($scope) {
  $scope.title = 'Lorem Ipsum';
}

angular.module('zippyModule', [])
  .directive('zippy', function(){
    return {
      restrict: 'C',
      replace: true,
      transclude: true,
      scope: { title:'=zippyTitle' },
      template: '<input type="text" value="{{title}}"style="width: 90%"/>',
      link: function(scope, element, attrs) {
        // Your controller
      }
    }
  });

[~ # ~] mise à jour [~ # ~] maxisam a raison, vous devez utiliser ng-model au lieu de lier la variable à la valeur comme ceci:

<input type="text" ng-model="title" style="width: 90%"/>

Voici la version de travail: http://jsfiddle.net/6HcGS/3/

27
F Lekschas

Vous voulez dire quelque chose comme this?

J'utilise essentiellement l'exemple de @ Flek.
La seule différence étant ng-model='title'

L'astuce pour effectuer une liaison bidirectionnelle est ng-model, et elle indique dans le document :

ngModel est une directive qui indique à Angular de faire une liaison de données bidirectionnelle. Il fonctionne avec l'entrée, la sélection, la zone de texte Vous pouvez facilement écrire vos propres directives pour utiliser également ngModel.

<input type="text" ng-model="title" style="width: 90%"/>
11
maxisam

Voici un moyen de passer à un paramètre de rappel dans une directive. Le modèle de contrôleur:

    <component-paging-select-directive
            page-item-limit="{{pageItemLimit}}"
            page-change-handler="pageChangeHandler(paramPulledOutOffThinAir)"
            ></component-paging-select-directive>

La directive:

angular.module('component')
    .directive('componentPagingSelectDirective', [
        function( ) {
            return {
                restrict: 'E',
                scope: { 
                    // using the '=' for two way doesn't work
                    pageItemLimit:  '@', // the '@' is one way from controller
                    pageChangeHandler: '&'
                },
                controller: function($scope) {   
                    // pass value from this scope to controller method. 
                    // controller method will update the var in controller scope
                    $scope.pageChangeHandler({
                        paramPulledOutOffThinAir: $scope.pageItemLimit
                    })

                }, ...

Dans le contrôleur:

angular.module('...').controller(...
        $scope.pageItemLimit = 0; // initial value for controller scoped var

        // complete the data update by setting the var in controller scope 
        // to the one from the directive
        $scope.pageChangeHandler = function(paramPulledOutOffThinAir) {
            $scope.pageItemLimit = paramPulledOutOffThinAir;
        }

Notez la différence dans les paramètres de fonction pour la directive (un objet avec paramètre comme clés), le modèle (clés "non enveloppées" de l'objet paramètre dans la directive) et la définition du contrôleur.

3
Henry