これは、私たちのプロジェクトで最近直面したバグの簡単な例です。
「名前」と「位置」のプロパティを持つオブジェクトのリストがあり、テキストエリアの代わりに TinyMCE エディターを使用して「名前」を表示したいと考えています。
また、リストは編集可能な「位置」プロパティによって並べ替えられます。
「位置」プロパティが変更されると (リストが並べ替えられると)、TinyMCE エディターが空になることに注意してください。
なぜそれが起こるのか、これを修正する方法は誰にもありますか?
コード例: JsFiddle
HTML
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<script src="//tinymce.cachefly.net/4.1/tinymce.min.js"></script>
<body ng-app="myApp">
<div ng-controller="MyCtrl">
<p>List of activities:</p>
<div ng-repeat="activity in model.activities | orderBy: 'position'">
<label for="$index">Position</label>
<input id="$index" type="number" ng-model="activity.position" style="width: 50px">
<textarea ng-model="activity.name" ui-tinymce="tinyMceOptions" rows="2" cols="10"></textarea>
<hr>
</div>
</div>
</body>
JS
var myApp = angular.module('myApp', ['ui.tinymce']);
/**
* Binds a TinyMCE widget to <textarea> elements.
*/
angular.module('ui.tinymce', [])
.value('uiTinymceConfig', {})
.directive('uiTinymce', ['uiTinymceConfig', function (uiTinymceConfig) {
uiTinymceConfig = uiTinymceConfig || {};
var generatedIds = 0;
return {
priority: 10,
require: 'ngModel',
link: function (scope, elm, attrs, ngModel) {
var expression, options, tinyInstance,
updateView = function () {
ngModel.$setViewValue(elm.val());
if (!scope.$root.$$phase) {
scope.$apply();
}
};
// generate an ID if not present
if (!attrs.id) {
attrs.$set('id', 'uiTinymce' + generatedIds++);
}
if (attrs.uiTinymce) {
expression = scope.$eval(attrs.uiTinymce);
} else {
expression = {};
}
// make config'ed setup method available
if (expression.setup) {
var configSetup = expression.setup;
delete expression.setup;
}
options = {
// Update model when calling setContent (such as from the source editor popup)
setup: function (ed) {
var args;
ed.on('init', function(args) {
ngModel.$render();
ngModel.$setPristine();
});
// Update model on button click
ed.on('ExecCommand', function (e) {
ed.save();
updateView();
});
// Update model on keypress
ed.on('KeyUp', function (e) {
ed.save();
updateView();
});
// Update model on change, i.e. copy/pasted text, plugins altering content
ed.on('SetContent', function (e) {
if (!e.initial && ngModel.$viewValue !== e.content) {
ed.save();
updateView();
}
});
ed.on('blur', function(e) {
elm.blur();
});
// Update model when an object has been resized (table, image)
ed.on('ObjectResized', function (e) {
ed.save();
updateView();
});
if (configSetup) {
configSetup(ed);
}
},
mode: 'exact',
elements: attrs.id
};
// extend options with initial uiTinymceConfig and options from directive attribute value
angular.extend(options, uiTinymceConfig, expression);
setTimeout(function () {
tinymce.init(options);
});
ngModel.$render = function() {
if (!tinyInstance) {
tinyInstance = tinymce.get(attrs.id);
}
if (tinyInstance) {
tinyInstance.setContent(ngModel.$viewValue || '');
}
};
scope.$on('$destroy', function() {
if (!tinyInstance) { tinyInstance = tinymce.get(attrs.id); }
if (tinyInstance) {
tinyInstance.remove();
tinyInstance = null;
}
});
}
};
}]);
myApp.controller("MyCtrl", ["$scope", function($scope) {
$scope.model = {
activities: [
{name: "activity 1", position: 1},
{name: "activity 2", position: 2},
{name: "activity 3", position: 3},
{name: "activity 4", position: 4},
{name: "activity 5", position: 5}
]
};
$scope.tinyMceOptions = {
selector: "textarea",
theme: "modern",
plugins: [
"autolink lists link charmap print preview hr anchor pagebreak autoresize",//advlist
"searchreplace visualblocks visualchars code",
"insertdatetime nonbreaking save table directionality",
"emoticons template paste textcolor colorpicker textpattern"
],
toolbar1: "bold italic underline | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | forecolor backcolor | undo redo | link | pastetext",
paste_auto_cleanup_on_paste: true,
paste_strip_class_attributes: 'mso',
paste_data_images: false,
theme_advanced_buttons3_add: "pastetext,pasteword,selectall",
image_advtab: true,
//templates: [
// {title: 'Test template 1', content: 'Test 1'},
// {title: 'Test template 2', content: 'Test 2'}
//],
browser_spellcheck: true,
menubar: false,
//theme_advanced_disable: "bullist,numlist",
target_list: [{ title: 'New page', value: '_blank' }],
//advlist_number_styles: [
// {title : 'Standard', styles : {listStyleType : ''}},
// {title : 'a. b. c.', styles : {listStyleType : 'lower-alpha'}}
//],
//spellchecker_languages: "+English=en",
//spellchecker_rpc_url: 'spellchecker.php',
handle_event_callback: function (e) {
// put logic here for keypress
}
};
}]);