I'm learning AngularJS. I've come across something I can't explain, nor can I find any explanation for (or solution).
I have a simple AngularJS app and I am attempting to bind a <span contenteditable="true">
to a value, but it doesn't work. 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>
How can I make the last span use 2-way binding, such that editing its value updates chunk.value and vice versa?
ng-bind! Use ng-bind for one-way binding in 'span'.
Please refer here for an example: https://docs.angularjs.org/api/ng/directive/ngBind
So your line would be:
<span contenteditable="true" ng-bind="chunk.value"></span>
Hope this help
To make ng-model
work with contenteditable <span>
elements, use a custom directive:
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>
For more infomation, see
ngModelController
API Reference - Custom Control Exampleangular.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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With