I try to integrate The beautifull WYSIWYG Redactor (http://imperavi.com/redactor/) in an custom AngularJS directive.
我试图在一个自定义的AngularJS指令中集成漂亮的WYSIWYG Redactor (http://imperavi.com/redactor/)。
Visualy it works, but my custom directive is not compatible with ng-model (and I don't understand why)
它可以工作,但是我的自定义指令与ng-model不兼容(我不明白为什么)
This is how you can use my directive :
这就是你如何使用我的指令:
<wysiwyg ng-model="edited.comment" id="contactEditCom" content="{{content}}" required></wysiwyg>
And this is the directive code :
这是指令码:
var myApp = angular.module('myApp', []);
myApp.directive("wysiwyg", function(){
var linkFn = function(scope, el, attr, ngModel) {
scope.redactor = null;
scope.$watch('content', function(val) {
if (val !== "")
{
scope.redactor = $("#" + attr.id).redactor({
focus : false,
callback: function(o) {
o.setCode(val);
$("#" + attr.id).keydown(function(){
scope.$apply(read);
});
}
});
}
});
function read() {
var content = scope.redactor.getCode();
console.log(content);
if (ngModel.viewValue != content)
{
ngModel.$setViewValue(content);
console.log(ngModel);
}
}
};
return {
require: 'ngModel',
link: linkFn,
restrict: 'E',
scope: {
content: '@'
},
transclude: true
};
});
And finally this is the fiddle -> http://fiddle.jshell.net/MyBoon/STLW5/
最后,这是小提琴-> http://fiddle.jshell.net/MyBoon/STLW5/。
5 个解决方案
#1
4
I made one based on Angular-UI's TinyMCE directive. This one also listen to format button clicks. It also handles the case when the model is changed outside the directive.
我根据Angular-UI的TinyMCE指令做了一个。这一个也听格式化按钮点击。它还处理在指令之外更改模型的情况。
directive.coffee (sorry for the coffeescript)
指令。咖啡(对不起,咖啡稿)
angular.module("ui.directives").directive "uiRedactor", ["ui.config", (uiConfig) ->
require: "ngModel"
link: (scope, elm, attrs, ngModelCtrl) ->
redactor = null
getVal = -> redactor?.getCode()
apply = ->
ngModelCtrl.$pristine = false
scope.$apply()
options =
execCommandCallback: apply
keydownCallback: apply
keyupCallback: apply
scope.$watch getVal, (newVal) ->
ngModelCtrl.$setViewValue newVal unless ngModelCtrl.$pristine
#watch external model change
ngModelCtrl.$render = ->
redactor?.setCode(ngModelCtrl.$viewValue or '')
expression = if attrs.uiRedactor then scope.$eval(attrs.uiRedactor) else {}
angular.extend options, expression
setTimeout ->
redactor = elm.redactor options
]
html
html
<textarea ui-redactor='{minHeight: 500}' ng-model='content'></textarea>
#2
4
UPDATED --- Rails 4.2 --- Angular-Rails 1.3.14
更新--- Rails 4.2 --- - Angular-Rails 1.3.14
Alright guys, after lots of research and some help from other members on stack overflow here is a solution that feeds straight into the controller $scope and into the ng-model you apply to the textarea:
好了,同学们,经过大量的研究和其他成员对stack overflow的帮助这里有一个解决方案,可以直接输入控制器$scope和你应用到textarea的ng模型:
** Render Raw HTML**
* * * *呈现原始HTML
# Filter for raw HTML
app.filter "unsafe", ['$sce', ($sce) ->
(htmlCode) ->
$sce.trustAsHtml htmlCode
]
功劳过滤器
Directive:
指令:
# For Redactor WYSIWYG
app.directive "redactor", ->
require: "?ngModel"
link: ($scope, elem, attrs, controller) ->
controller.$render = ->
elem.redactor
changeCallback: (value) ->
$scope.$apply controller.$setViewValue value
buttons: ['html', '|', 'formatting', '|',
'fontcolor', 'backcolor', '|', 'image', 'video', '|',
'alignleft', 'aligncenter', 'alignright', 'justify', '|',
'bold', 'italic', 'deleted', 'underline', '|',
'unorderedlist', 'orderedlist', 'outdent', 'indent', '|',
'table', 'link', 'horizontalrule', '|']
imageUpload: '/modules/imageUpload'
elem.redactor 'insert.set', controller.$viewValue
最后一行更新的原因
in the HTML View:
在HTML视图:
<div ng-controller="PostCtrl">
<form ng-submit="addPost()">
<textarea ng-model="newPost.content" redactor required></textarea>
<br />
<input type="submit" value="add post">
</form>
{{newPost.content}} <!-- This outputs the raw html with tags -->
<br />
<div ng-bind-html="newPost.content | unsafe"></div> <!-- This outputs the html -->
</div>
And the Controller:
控制器:
$scope.addPost = ->
post = Post.save($scope.newPost)
console.log post
$scope.posts.unshift post
$scope.newPost.content = "<p>Add a new post...</p>"
To PREVENT a TypeError with redactor populate a value into the textarea before the action is called, this worked best for me to preserve formatting:
为了防止在调用动作之前将一个值填充到textarea中的输入错误,我最好保存格式:
# Set the values of Reactor to prevent error
$scope.newPost = {content: '<p>Add a new post...</p>'}
If you are on running into CSRF errors this will solve that problem:
如果您正在运行CSRF错误,这将解决这个问题:
# Fixes CSRF Error OR: https://github.com/xrd/ng-rails-csrf
app.config ["$httpProvider", (provider) ->
provider.defaults.headers.common['X-CSRF-Token'] = angular.element('meta[name=csrf-token]').attr('content')
]
]
Much Thanks to: AngularJS & Redactor Plugin
非常感谢:AngularJS & Redactor插件
Lastly....
最后....
If you are using an ng-repeat to create these redactor text areas and are having trouble accessing the scope, check out this answer: Accessing the model inside a ng-repeat
如果您正在使用一个ng-repeat来创建这些redactor文本区域,并且在访问范围方面遇到困难,请查看以下答案:在ng-repeat中访问模型
#3
1
See if this fiddle is what you want.
看看这个小提琴是不是你想要的。
ng-model can be set to content:
ng模型可以设置为内容:
<wysiwyg ng-model="content" required></wysiwyg>
Inside the linking function, el is already set to the element where the directive is defined, so an id
is not needed. And el is already a wrapped jQuery element.
在链接函数中,el已经设置为定义指令的元素,所以不需要id。el已经是一个封装的jQuery元素。
Link function:
链接功能:
var linkFn = function (scope, el, attr, ngModel) {
scope.redactor = el.redactor({
focus: false,
callback: function (o) {
o.setCode(scope.content);
el.keydown(function () {
console.log(o.getCode());
scope.$apply(ngModel.$setViewValue(o.getCode()));
#4
1
My solution is
我的解决方案是
1) clone https://github.com/dybskiy/redactor-js.git 2) include jquery, redactor.js, redactor.css 3) add tag: <textarea wysiwyg ng-model="post.content" cols="18" required></textarea>
to your html body 4) add directive:
1)克隆https://github.com/dybskiy/redactor-js.git 2)包括jquery, redactor。js,编辑者。添加标签:到您的html主体4)添加指令:
yourapp.directive('wysiwyg', function () {
return {
require: 'ngModel',
link: function (scope, el, attrs, ngModel) {
el.redactor({
keyupCallback: function(obj, e) {
scope.$apply(ngModel.$setViewValue(obj.getCode()));
}
});
el.setCode(scope.content);
}
};
});
Best regards, Jeliuc Alexandr
最好的问候,Jeliuc Alexandr
#5
1
The above solutions didn't work for me for all situations so I used them to create the following directive that does keep model and redactor in sync.
上面的解决方案并不适用于所有情况,所以我使用它们创建了以下指令,以保持模型和编校器的同步。
angular.module('redactor', [])
.directive('redactor', function () { return { require: '?ngModel', link: function (scope, el, attrs, ngModel) {
.指令('redactor', function () {return {require: '?链接:功能(范围、el、attrs、ngModel) {
// Function to update model
var updateModel = function() {
scope.$apply(ngModel.$setViewValue(el.getCode()));
};
// Get the redactor element and call update model
el.redactor({
keyupCallback: updateModel,
keydownCallback: updateModel,
execCommandCallback: updateModel,
autosaveCallback: updateModel
});
// Call to sync the redactor content
ngModel.$render = function(value) {
el.setCode(ngModel.$viewValue);
};
}
};
});
});
Just add the redactor module as a dependency and the following to your html:
只需将编校器模块添加为依赖项,并将以下内容添加到html中:
Note: I had to update the code after upgrading to version 9.1.1
注意:我必须在升级到9.1.1版本后更新代码
Here is the new version:
这是新版本:
.directive('redactor', function () {
return {
require: '?ngModel',
link: function (scope, el, attrs, ngModel) {
var updateModel, errorHandling;
// Function to update model
updateModel = function() {
if(!scope.$$phase) {
scope.$apply(ngModel.$setViewValue(el.redactor('get')));
}
};
uploadErrorHandling = function(response)
{
console.log(response.error);
alert("Error: "+ response.error);
};
// Get the redactor element and call update model
el.redactor({
minHeight: 100,
buttons: ['formatting', '|', 'bold', 'italic', 'deleted', '|',
'unorderedlist', 'orderedlist', 'outdent', 'indent', '|',
'image', 'video', 'file', 'table', 'link', '|', 'alignment', '|', 'horizontalrule'],
keyupCallback: updateModel,
keydownCallback: updateModel,
changeCallback: updateModel,
execCommandCallback: updateModel,
autosaveCallback: updateModel,
imageUpload: '/file/upload/image',
imageUploadErrorCallback: uploadErrorHandling,
imageGetJson: '/api/v1/gallery'
});
// Call to sync the redactor content
ngModel.$render = function(value) {
el.redactor('set', ngModel.$viewValue);
};
}
};
});
#1
4
I made one based on Angular-UI's TinyMCE directive. This one also listen to format button clicks. It also handles the case when the model is changed outside the directive.
我根据Angular-UI的TinyMCE指令做了一个。这一个也听格式化按钮点击。它还处理在指令之外更改模型的情况。
directive.coffee (sorry for the coffeescript)
指令。咖啡(对不起,咖啡稿)
angular.module("ui.directives").directive "uiRedactor", ["ui.config", (uiConfig) ->
require: "ngModel"
link: (scope, elm, attrs, ngModelCtrl) ->
redactor = null
getVal = -> redactor?.getCode()
apply = ->
ngModelCtrl.$pristine = false
scope.$apply()
options =
execCommandCallback: apply
keydownCallback: apply
keyupCallback: apply
scope.$watch getVal, (newVal) ->
ngModelCtrl.$setViewValue newVal unless ngModelCtrl.$pristine
#watch external model change
ngModelCtrl.$render = ->
redactor?.setCode(ngModelCtrl.$viewValue or '')
expression = if attrs.uiRedactor then scope.$eval(attrs.uiRedactor) else {}
angular.extend options, expression
setTimeout ->
redactor = elm.redactor options
]
html
html
<textarea ui-redactor='{minHeight: 500}' ng-model='content'></textarea>
#2
4
UPDATED --- Rails 4.2 --- Angular-Rails 1.3.14
更新--- Rails 4.2 --- - Angular-Rails 1.3.14
Alright guys, after lots of research and some help from other members on stack overflow here is a solution that feeds straight into the controller $scope and into the ng-model you apply to the textarea:
好了,同学们,经过大量的研究和其他成员对stack overflow的帮助这里有一个解决方案,可以直接输入控制器$scope和你应用到textarea的ng模型:
** Render Raw HTML**
* * * *呈现原始HTML
# Filter for raw HTML
app.filter "unsafe", ['$sce', ($sce) ->
(htmlCode) ->
$sce.trustAsHtml htmlCode
]
功劳过滤器
Directive:
指令:
# For Redactor WYSIWYG
app.directive "redactor", ->
require: "?ngModel"
link: ($scope, elem, attrs, controller) ->
controller.$render = ->
elem.redactor
changeCallback: (value) ->
$scope.$apply controller.$setViewValue value
buttons: ['html', '|', 'formatting', '|',
'fontcolor', 'backcolor', '|', 'image', 'video', '|',
'alignleft', 'aligncenter', 'alignright', 'justify', '|',
'bold', 'italic', 'deleted', 'underline', '|',
'unorderedlist', 'orderedlist', 'outdent', 'indent', '|',
'table', 'link', 'horizontalrule', '|']
imageUpload: '/modules/imageUpload'
elem.redactor 'insert.set', controller.$viewValue
最后一行更新的原因
in the HTML View:
在HTML视图:
<div ng-controller="PostCtrl">
<form ng-submit="addPost()">
<textarea ng-model="newPost.content" redactor required></textarea>
<br />
<input type="submit" value="add post">
</form>
{{newPost.content}} <!-- This outputs the raw html with tags -->
<br />
<div ng-bind-html="newPost.content | unsafe"></div> <!-- This outputs the html -->
</div>
And the Controller:
控制器:
$scope.addPost = ->
post = Post.save($scope.newPost)
console.log post
$scope.posts.unshift post
$scope.newPost.content = "<p>Add a new post...</p>"
To PREVENT a TypeError with redactor populate a value into the textarea before the action is called, this worked best for me to preserve formatting:
为了防止在调用动作之前将一个值填充到textarea中的输入错误,我最好保存格式:
# Set the values of Reactor to prevent error
$scope.newPost = {content: '<p>Add a new post...</p>'}
If you are on running into CSRF errors this will solve that problem:
如果您正在运行CSRF错误,这将解决这个问题:
# Fixes CSRF Error OR: https://github.com/xrd/ng-rails-csrf
app.config ["$httpProvider", (provider) ->
provider.defaults.headers.common['X-CSRF-Token'] = angular.element('meta[name=csrf-token]').attr('content')
]
]
Much Thanks to: AngularJS & Redactor Plugin
非常感谢:AngularJS & Redactor插件
Lastly....
最后....
If you are using an ng-repeat to create these redactor text areas and are having trouble accessing the scope, check out this answer: Accessing the model inside a ng-repeat
如果您正在使用一个ng-repeat来创建这些redactor文本区域,并且在访问范围方面遇到困难,请查看以下答案:在ng-repeat中访问模型
#3
1
See if this fiddle is what you want.
看看这个小提琴是不是你想要的。
ng-model can be set to content:
ng模型可以设置为内容:
<wysiwyg ng-model="content" required></wysiwyg>
Inside the linking function, el is already set to the element where the directive is defined, so an id
is not needed. And el is already a wrapped jQuery element.
在链接函数中,el已经设置为定义指令的元素,所以不需要id。el已经是一个封装的jQuery元素。
Link function:
链接功能:
var linkFn = function (scope, el, attr, ngModel) {
scope.redactor = el.redactor({
focus: false,
callback: function (o) {
o.setCode(scope.content);
el.keydown(function () {
console.log(o.getCode());
scope.$apply(ngModel.$setViewValue(o.getCode()));
#4
1
My solution is
我的解决方案是
1) clone https://github.com/dybskiy/redactor-js.git 2) include jquery, redactor.js, redactor.css 3) add tag: <textarea wysiwyg ng-model="post.content" cols="18" required></textarea>
to your html body 4) add directive:
1)克隆https://github.com/dybskiy/redactor-js.git 2)包括jquery, redactor。js,编辑者。添加标签:到您的html主体4)添加指令:
yourapp.directive('wysiwyg', function () {
return {
require: 'ngModel',
link: function (scope, el, attrs, ngModel) {
el.redactor({
keyupCallback: function(obj, e) {
scope.$apply(ngModel.$setViewValue(obj.getCode()));
}
});
el.setCode(scope.content);
}
};
});
Best regards, Jeliuc Alexandr
最好的问候,Jeliuc Alexandr
#5
1
The above solutions didn't work for me for all situations so I used them to create the following directive that does keep model and redactor in sync.
上面的解决方案并不适用于所有情况,所以我使用它们创建了以下指令,以保持模型和编校器的同步。
angular.module('redactor', [])
.directive('redactor', function () { return { require: '?ngModel', link: function (scope, el, attrs, ngModel) {
.指令('redactor', function () {return {require: '?链接:功能(范围、el、attrs、ngModel) {
// Function to update model
var updateModel = function() {
scope.$apply(ngModel.$setViewValue(el.getCode()));
};
// Get the redactor element and call update model
el.redactor({
keyupCallback: updateModel,
keydownCallback: updateModel,
execCommandCallback: updateModel,
autosaveCallback: updateModel
});
// Call to sync the redactor content
ngModel.$render = function(value) {
el.setCode(ngModel.$viewValue);
};
}
};
});
});
Just add the redactor module as a dependency and the following to your html:
只需将编校器模块添加为依赖项,并将以下内容添加到html中:
Note: I had to update the code after upgrading to version 9.1.1
注意:我必须在升级到9.1.1版本后更新代码
Here is the new version:
这是新版本:
.directive('redactor', function () {
return {
require: '?ngModel',
link: function (scope, el, attrs, ngModel) {
var updateModel, errorHandling;
// Function to update model
updateModel = function() {
if(!scope.$$phase) {
scope.$apply(ngModel.$setViewValue(el.redactor('get')));
}
};
uploadErrorHandling = function(response)
{
console.log(response.error);
alert("Error: "+ response.error);
};
// Get the redactor element and call update model
el.redactor({
minHeight: 100,
buttons: ['formatting', '|', 'bold', 'italic', 'deleted', '|',
'unorderedlist', 'orderedlist', 'outdent', 'indent', '|',
'image', 'video', 'file', 'table', 'link', '|', 'alignment', '|', 'horizontalrule'],
keyupCallback: updateModel,
keydownCallback: updateModel,
changeCallback: updateModel,
execCommandCallback: updateModel,
autosaveCallback: updateModel,
imageUpload: '/file/upload/image',
imageUploadErrorCallback: uploadErrorHandling,
imageGetJson: '/api/v1/gallery'
});
// Call to sync the redactor content
ngModel.$render = function(value) {
el.redactor('set', ngModel.$viewValue);
};
}
};
});