使用 ng-model 的 Contenteditable 不起作用
Contenteditable with ng-model doesn't work
我正在尝试将 contenteditable
的值存储到我的 JS 代码中。但我无法找出为什么 ng-model
在这种情况下不起作用。
<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>
有解决办法吗?
参见:JSFiddle
注意: 我正在创建一个文本编辑器,所以用户应该看到结果,而我将 HTML 存储在它后面。 (即用户看到:"This is an example !",而我存储:This is an <b>example</b> !
)
contenteditable 标签不能直接与 angular 的 ng-model 一起工作,因为 contenteditable 在每次更改时重新呈现 dom 元素的方式。
您必须为此使用自定义指令包装它:
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>
只需将读取函数调用移动到 $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);
}
}
};
}]);
其他答案都不适合我。我需要在初始化控件时呈现模型的初始值。我没有调用 read()
,而是在 link
函数中使用了这段代码:
ngModel.$modelValue = scope.$eval(attrs.ngModel);
ngModel.$setViewValue(ngModel.$modelValue);
ngModel.$render()
我正在尝试将 contenteditable
的值存储到我的 JS 代码中。但我无法找出为什么 ng-model
在这种情况下不起作用。
<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>
有解决办法吗?
参见:JSFiddle
注意: 我正在创建一个文本编辑器,所以用户应该看到结果,而我将 HTML 存储在它后面。 (即用户看到:"This is an example !",而我存储:This is an <b>example</b> !
)
contenteditable 标签不能直接与 angular 的 ng-model 一起工作,因为 contenteditable 在每次更改时重新呈现 dom 元素的方式。
您必须为此使用自定义指令包装它:
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>
只需将读取函数调用移动到 $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);
}
}
};
}]);
其他答案都不适合我。我需要在初始化控件时呈现模型的初始值。我没有调用 read()
,而是在 link
函数中使用了这段代码:
ngModel.$modelValue = scope.$eval(attrs.ngModel);
ngModel.$setViewValue(ngModel.$modelValue);
ngModel.$render()