AngularJS - ng-модель терпит неудачу при контентоспособности <span>

Я изучаю AngularJS. Я столкнулся с чем-то, что не могу объяснить, и не могу найти объяснения (или решения).

У меня есть простое приложение AngularJS, и я пытаюсь привязать значение <span contenteditable="true"> к значению, но оно не работает. EG:

<!-- 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>

Как я могу использовать последний способ использования двухсторонней привязки, так что редактирование его значения обновляет значение chunk.value и наоборот?

Ответы

Ответ 1

нг-привязывать! Используйте ng-bind для односторонней привязки в 'span'.

Пожалуйста, обратитесь к приведенному ниже примеру: https://docs.angularjs.org/api/ng/directive/ngBind

Итак, ваша строка будет: <span contenteditable="true" ng-bind="chunk.value"></span>

Надеемся на эту помощь

Ответ 2

ngModel не будет работать, как указал @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.

Вы можете взглянуть на директиву contenteditable.

В противном случае потенциальное обходное решение: имеет функцию, которая вызывается. Затем эта функция обновляет $scope.chunk.value внутри вашего контроллера. И по мере обновления привязки он будет заботиться о содержимом других элементов.

Я не уверен, какой именно вид или функциональность вы собираетесь использовать, но просто вставьте его в <textarea> и создайте его как <span> (без границы или фона и т.д.). Затем, когда он находится в focus, вы добавляете дополнительный стиль, чтобы знать, что его можно редактировать. Этот способ позволит вам использовать ng-model, поскольку он предназначен для использования. Вот базовая реализация этого подхода: Plunker

Ответ 3

ng-model не предназначен для использования с span. Если вам абсолютно необходимо, что вы можете написать для этого специальную директиву. Эта директива настроит прослушиватель keydown,keyup на contentEditable span и обновит модель области (в пределах $apply()). Это будет привязывать контент диапазона к модели.

Я быстро создал plunker для вас. Проверьте это. Он синхронизирует модель <span> с контентом. Откройте консоль браузера, чтобы увидеть обновление модели области при каждом вводе чего-либо.

Ответ 4

Добавив поведение ng-model-options="{ getterSetter: true }" к элементу с ng-model, прикрепленным к нему. Вы также можете добавить ng-model-options="{ getterSetter: true }" в <form>, который позволит это поведение для всех <input>s внутри него.

Пример показывает, как использовать ngModel с getter/setter: демонстрационная страница

Ответ 5

Чтобы сделать ng-model работу с элементами contenteditable <span>, используйте настраиваемую директиву:

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

Использование:

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

Для получения дополнительной информации см.


DEMO

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>