我已经开始使用角度js并且有一个问题需要获取控制器内部DOM的当前状态。基本上我正在一个可信的div内构建一个文本编辑器。 div中文本的修改可以来自外部服务(从服务器推送长轮询)以及实际在该字段中键入的用户。现在,服务器的修订版正在操纵我的角度模型,然后通过ng-bind-html-unsafe指令更新视图。唯一的问题是,这会消除用户当前光标位置和文本选择。
我已经想出了解决这个问题的方法,但它需要直接操作我的控制器中的dom元素,这似乎是在角度上不鼓励的。我正在寻找对我当前方法的验证,或者对更具“棱角分明”的东西的推荐。
基本上我所做的是在我的模型中添加两个事件,“contentChanging”和“contentChanged”。第一个是在我更新模型之前触发,第二个是在之后。在我的控制器中,我订阅了这样的事件。
//dmp is google's diff_match_patch library
//rangy is a selection management library http://code.google.com/p/rangy/wiki/SelectionSaveRestoreModule
var selectionPatch;
var selection;
scope.model.on("contentChanging", function() {
var currentText = $("#doc").html();
selection = rangy.saveSelection();
var textWithSelection = $("#doc").html();
selectionPatch = dmp.patch_make(currentText, textWithSelection);
});
scope.model.on("contentChanged", function() {
scope.$apply();
var textAfterEdit = $("#doc").html();
$("#doc").html(dmp.patch_apply(selectionPatch, textAfterEdit)[0]);
rangy.restoreSelection(selection);
});
所以基本上,当内容发生变化时,我会抓取可编辑区域的当前html。然后我使用rangy插件将隐藏的dom元素注入到文档中,以标记用户当前的位置和选择。我使用没有隐藏标记的html和带有标记的html,我使用google的diff_match_patch库(dmp)制作补丁。
更改内容后,我调用范围。$ apply()更新视图。然后我从视图中获取新文本并应用之前的补丁,这将隐藏的标记添加回html。最后,我使用范围来恢复选择。
我不喜欢的部分是我如何使用jquery从视图中获取当前的html来构建和应用我的补丁。它会让单元测试变得有点棘手,感觉不对劲。但鉴于这个笨拙的图书馆如何运作,我想不出另一种方法。
答案 0 :(得分:2)
以下是一个如何开始的简单示例:
<!doctype html>
<html ng-app="myApp">
<head>
<script src="http://code.angularjs.org/1.1.2/angular.min.js"></script>
<script type="text/javascript">
function Ctrl($scope) {
$scope.myText = "Here's some text";
}
angular.module("myApp", []).directive('texteditor', function() {
return {
restrict: 'E',
replace: true,
template: '<textarea></textarea>',
scope: {
text: '=' // link the directives scopes `text` property
// to the expression inside the text attribute
},
link: function($scope, elem, attrs) {
elem.val($scope.text);
elem.bind('input', function() {
// When the user inputs text, Angular won't know about
// it since we're not using ng-model so we need to call
// $scope.$apply() to tell Angular run a digest cycle
$scope.$apply(function() {
$scope.text = elem.val();
});
});
}
};
});
</script>
</head>
<body>
<div ng-controller="Ctrl">
<texteditor text="myText"></texteditor>
<p>myText = {{myText}}</p>
</div>
</body>
</html>
它只是绑定到textarea,所以你要用真正的文本编辑器替换它。关键是在文本编辑器中监听文本的更改,并更新范围的值,以便外界知道用户更改了文本编辑器中的文本。