jQuery.sortable
AngularJSのng-repeat
要素で簡単に使用できますか?
アイテムを並べ替えると、その順序がソース配列に自動的に反映されれば素晴らしいことです。しかし、2つのシステムが戦うのではないかと心配しています。これを行うより良い方法はありますか?
jQuery.sortable
AngularJSのng-repeat
要素で簡単に使用できますか?
アイテムを並べ替えると、その順序がソース配列に自動的に反映されれば素晴らしいことです。しかし、2つのシステムが戦うのではないかと心配しています。これを行うより良い方法はありますか?
Angular UI には並べ替え可能なディレクティブがあります。デモはここをクリックしてください
ui-sortableにあるコード、使用法:
<ul ui-sortable ng-model="items" ui-sortable-update="sorted">
<li ng-repeat="item in items track by $index" id="{{$index}}">{{ item }}</li>
</ul>
$scope.sorted = (event, ui) => { console.log(ui.item[0].getAttribute('id')) }
私は同じことをしようとしましたが、次の解決策を思いつきました:
angular.directive("my:sortable", function(expression, compiledElement){
return function(linkElement){
var scope = this;
linkElement.sortable(
{
placeholder: "ui-state-highlight",
opacity: 0.8,
update: function(event, ui) {
var model = scope.$tryEval(expression);
var newModel = [];
var items = [];
linkElement.children().each(function() {
var item = $(this);
// get old item index
var oldIndex = item.attr("ng:repeat-index");
if(oldIndex) {
// new model in new order
newModel.push(model[oldIndex]);
// items in original order
items[oldIndex] = item;
// and remove
item.detach();
}
});
// restore original dom order, so angular does not get confused
linkElement.append.apply(linkElement,items);
// clear old list
model.length = 0;
// add elements in new order
model.push.apply(model, newModel);
// presto
scope.$eval();
// Notify event handler
var onSortExpression = linkElement.attr("my:onsort");
if(onSortExpression) {
scope.$tryEval(onSortExpression, linkElement);
}
}
});
};
});
次のように使用します。
<ol id="todoList" my:sortable="todos" my:onsort="onSort()">
それはかなりうまくいくようです。トリックは、モデルを更新する前に sortable によって行われた DOM 操作を元に戻すことです。そうしないと、angular が DOM から非同期になります。
変更の通知は、コントローラ メソッドを呼び出すことができる my:onsort 式を介して機能します。
angular todoチュートリアルに基づいてJsFiddleを作成し、それがどのように機能するかを示しました:http://jsfiddle.net/M8YnR/180/
これは、Angular v0.10.6 で行っている方法です。ここにjsfiddleがあります
angular.directive("my:sortable", function(expression, compiledElement){
// add my:sortable-index to children so we know the index in the model
compiledElement.children().attr("my:sortable-index","{{$index}}");
return function(linkElement){
var scope = this;
linkElement.sortable({
placeholder: "placeholder",
opacity: 0.8,
axis: "y",
update: function(event, ui) {
// get model
var model = scope.$apply(expression);
// remember its length
var modelLength = model.length;
// rember html nodes
var items = [];
// loop through items in new order
linkElement.children().each(function(index) {
var item = $(this);
// get old item index
var oldIndex = parseInt(item.attr("my:sortable-index"), 10);
// add item to the end of model
model.push(model[oldIndex]);
if(item.attr("my:sortable-index")) {
// items in original order to restore dom
items[oldIndex] = item;
// and remove item from dom
item.detach();
}
});
model.splice(0, modelLength);
// restore original dom order, so angular does not get confused
linkElement.append.apply(linkElement,items);
// notify angular of the change
scope.$digest();
}
});
};
});
jquery.ui を使用しない、ソート可能な Angular.js ディレクティブの実装を次に示します。
軽量でjqueryを使用しないng-sortableディレクティブを使用できます。ここにリンクがありますng-sortable ドラッグアンドドロップ要素