web-dev-qa-db-fra.com

Le contenu modifiable avec ng-model ne fonctionne pas

J'essaie de stocker la valeur d'un contenteditable dans mon code JS. Mais je ne peux pas savoir pourquoi ng-model ne fonctionne pas dans ce cas.

<div ng-app="Demo" ng-controller="main">
    <input ng-model="inputValue"></input>
    <div>{{inputValue}}</div> // Works fine with an input
    <hr/>
    <div contenteditable="true" ng-model="contentValue"></div>
    <div>{{contentValue}}</div> // Doesn't work with a contenteditable
</div>

Existe-t-il une solution de contournement pour ce faire?

Voir: JSFiddle

Remarque: Je crée un éditeur de texte, donc l'utilisateur devrait voir le résultat pendant que je stocke le code HTML derrière. (ie. l'utilisateur voit: "Ceci est un exemple !", tandis que je stocke: This is an <b>example</b> !)

13
Elfayer

la balise contenteditable ne fonctionnera pas directement avec le modèle ng d'angular car la façon dont contenteditable restitue l'élément dom à chaque changement.

Vous devez l'envelopper avec une directive personnalisée pour cela:

JS:

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);
      }
    }
  };
}]);

HTML

<form name="myForm">
 <div contenteditable
      name="myWidget" ng-model="userContent"
      strip-br="true"
      required>Change me!</div>
  <span ng-show="myForm.myWidget.$error.required">Required!</span>
 <hr>
 <textarea ng-model="userContent"></textarea>
</form>

Sourcez-le dans les documents originaux

31
Ben Diamant

Déplacez simplement l'appel de la fonction de lecture dans $ render

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 || ''));
        read(); // initialize
      };

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

      // 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);
      }
    }
  };
}]);
7
goonerify

Aucune des autres réponses n'a fonctionné pour moi. J'avais besoin que la valeur initiale du modèle soit rendue lors de l'initialisation du contrôle. Au lieu d'appeler read(), j'ai utilisé ce code dans la fonction link:

ngModel.$modelValue = scope.$eval(attrs.ngModel);
ngModel.$setViewValue(ngModel.$modelValue);
ngModel.$render()
0
JstnPwll