Angularjs and CKEditor

今天研究如何將CKEditor整合到AngularJS時花了不少時間。主要的問題在如何將CKEditor產生的textarea資料綁定後隨著表單的ng-submit一同上傳到server端。經過一番嘗試與搜尋終於在萬能的stackoverflow找到。有人很貼心的將ckeditor做成Directive,未來這種簡單方便的做法應該越來多。不過儘管寫成directive,還是花了一些時間測試,畢竟AngularJS在很多觀念上還是與目前習慣Rails寫法的我有很大的不同。

事先準備

當然是使用angularjs-railsckeditor,這樣還可以支援圖片上傳。在Gemfile設定後bundle install他們。 把這兩隻放在要include的javascript中掛起來:

1
2
3
4
5
//= require jquery
//= require jquery_ujs
//= require angular
//= require angular-resource
//= require ckeditor/init

再來就是透過$ngResource或$http將必要的CRUD建立起來,這邊就不再討論。

建立CKEditor的directive

參考從stackoverflow的程式碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
app.directive('ckEditor', function() {
var calledEarly, loaded;
loaded = false;
calledEarly = false;
return {
require: '?ngModel',
compile: function(element, attributes, transclude) {
var loadIt, local;
local = this;
loadIt = function() {
return calledEarly = true;
};
element.ready(function() {
return loadIt();
});
return {
post: function($scope, element, attributes, controller) {
if (calledEarly) {
return local.link($scope, element, attributes, controller);
}
loadIt = (function($scope, element, attributes, controller) {
return function() {
local.link($scope, element, attributes, controller);
};
})($scope, element, attributes, controller);
}
};
},
link: function($scope, elm, attr, ngModel) {
var ck;
if (!ngModel) {
return;
}
if (calledEarly && !loaded) {
return loaded = true;
}
loaded = false;
ck = CKEDITOR.replace(elm[0]);
ck.on('pasteState', function() {
$scope.$apply(function() {
ngModel.$setViewValue(ck.getData());
});
});
ngModel.$render = function(value) {
ck.setData(ngModel.$viewValue);
};
}
};
});

在FORM表這邊,參考以下程式碼:

<form ng-submit="create()">
    <textarea ck-editor ng-model="item.text"></textarea>
    <input class="btn btn-large btn-primary" type="submit" value="建立資料" />
</form>

看到textarea多了個ckeditor的屬性嗎?要注意的是,ng-model=”item.text”就是準備要上傳的資料欄位,可以在angularjs的controller中透過console.log($scope.item.text)來觀察。