web-dev-qa-db-fra.com

AngularJS - ng-model échoue sur contenteditable <span>

J'apprends AngularJS. J'ai rencontré quelque chose que je ne peux pas expliquer, et je ne peux trouver aucune explication (ou solution).

J'ai une simple application AngularJS et j'essaie de lier un <span contenteditable="true"> à une valeur, mais cela ne fonctionne pas. PAR EXEMPLE:

<!-- Works as expected -->
<input data-ng-model="chunk.value"></input>

<!-- Shows value, but doesn't bind - changes not reflected in model -->
<span contenteditable="true">{{chunk.value}}</span>

<!-- This is empty -->
<span contenteditable="true" data-ng-model="chunk.value"></span>

Comment puis-je faire en sorte que la dernière plage utilise la liaison bidirectionnelle, de sorte que la modification de sa valeur mette à jour chunk.value et vice versa?

16
Alex McMillan

ng-bind ! Utilisez ng-bind pour une liaison unidirectionnelle dans "span".

Veuillez vous référer ici pour un exemple: https://docs.angularjs.org/api/ng/directive/ngBind

Votre ligne serait donc: <span contenteditable="true" ng-bind="chunk.value"></span>

J'espère que cette aide

21
Siti Farah

Faire ng-model travailler avec contenteditable <span> éléments, utilisez une directive personnalisée:

app.directive('contenteditable', ['$sce', function($sce) {
    return {
      restrict: 'A', // only activate on element attribute
      require: '?ngModel', // get a hold of NgModelController
      link: function(scope, element, attrs, ngModel) {
        if (!ngModel) return; // do nothing if no ng-model

        // Specify how UI should be updated
        ngModel.$render = function() {
          element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
        };

        // Listen for change events to enable binding
        element.on('blur keyup change', function() {
          scope.$evalAsync(read);
        });
        read(); // initialize

        // Write data to the model
        function read() {
          var html = element.html();
          // When we clear the content editable the browser leaves a <br> behind
          // If strip-br attribute is provided then we strip this out
          if (attrs.stripBr && html === '<br>') {
            html = '';
          }
          ngModel.$setViewValue(html);
        }
      }
    };
}]);

Usage:

<span contenteditable ng-model="userContent">Change me!</span>
<p>{{userContent}}</p>

Pour plus d'informations, voir


La DÉMO

angular.module('customControl', ['ngSanitize'])
.directive('contenteditable', ['$sce', function($sce) {
    return {
      restrict: 'A', // only activate on element attribute
      require: '?ngModel', // get a hold of NgModelController
      link: function(scope, element, attrs, ngModel) {
        if (!ngModel) return; // do nothing if no ng-model

        // Specify how UI should be updated
        ngModel.$render = function() {
          element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
        };

        // Listen for change events to enable binding
        element.on('blur keyup change', function() {
          scope.$evalAsync(read);
        });
        read(); // initialize

        // Write data to the model
        function read() {
          var html = element.html();
          // When we clear the content editable the browser leaves a <br> behind
          // If strip-br attribute is provided then we strip this out
          if (attrs.stripBr && html === '<br>') {
            html = '';
          }
          ngModel.$setViewValue(html);
        }
      }
    };
  }]);
[contenteditable] {
  border: 1px solid black;
  background-color: white;
  min-height: 20px;
}
<script src="//unpkg.com/angular/angular.js"></script>
<script src="//unpkg.com/angular-sanitize/angular-sanitize.js"></script>
<body ng-app="customControl">
 <span contenteditable ng-model="userContent">Change me!</span>
 <hr>
 Content={{userContent}}
</body>
1
georgeawg

ng-model N'est pas destiné à être utilisé avec span. Si vous en avez absolument besoin, vous pouvez écrire une directive personnalisée pour cela. Cette directive créera un écouteur keydown,keyup Sur contentEditablespan et mettra à jour le modèle de portée (dans $apply()). Cela liera le contenu de l'étendue au modèle.

J'ai rapidement créé un plunker pour vous. Vérifiez-le. Il synchronise le contenu <span> Avec le modèle de portée. Ouvrez la console du navigateur pour voir la mise à jour du modèle de portée chaque fois que vous tapez quelque chose.

0
Sandeep Panda

En ajoutant ng-model-options="{ getterSetter: true }" comportement à un élément qui a ng-model y est attaché. Vous pouvez également ajouter ng-model-options="{ getterSetter: true }" à un <form>, qui activera ce comportement pour tous les <input>s à l'intérieur.

Un exemple montre comment utiliser ngModel avec un getter/setter: page de démonstration

0
Prabhakaran S

ngModel ne fonctionnera pas comme l'a souligné @VtoCorleone. ngModel docs

The ngModel directive binds an input,select, textarea (or custom form control) to a property on the scope using NgModelController, which is created and exposed by this directive.

Vous pouvez consulter la directive contentable .

Sinon, solution de contournement potentielle: avoir une fonction qui est appelée. Cette fonction met ensuite à jour le $scope.chunk.value dans votre contrôleur. Et il prendrait en charge le contenu des autres éléments lors de la mise à jour de la liaison.

Je ne suis pas sûr de l'apparence ou des fonctionnalités exactes que vous recherchez, mais mettez-les simplement dans un <textarea> et le style pour ressembler à un <span> (pas de bordure ni d'arrière-plan, etc.). Ensuite, quand il est dans focus, vous ajoutez un style supplémentaire pour savoir qu'il peut être modifié. Cette façon vous permettrait d'utiliser le ng-model tel qu'il est destiné à être utilisé. Voici une implémentation de base de cette approche: Plunker

0
EnigmaRM