AngularJSで、リストをドラック&ドロップで入れ替える為のメモ

##やりたいこと
下記のようなリストをドラック&ドロップで順番を入れ替えたい

* リスト1
* リスト2
* リスト3

##準備
**ui-sortable**ライブラリを使用します。
他にもng-sortableなど似たライブラリがあったのですが、ui-sortableがシンプルだったのでこちらを使うことにしました。

<a href="https://github.com/angular-ui/ui-sortable" target="_blank">https://github.com/angular-ui/ui-sortable</a>

###インストール
```
bower install angular-ui-sortable --save
```
※ ui-sortableの他に、jQuryと、jQuery.UIも必要です。

###ライブラリを読み込む
```lang:javascript
angular.module('myApp', ['ui.sortable']);
```

##使い方

###最もシンプルな設定方法

入れ替えの制御をしたい要素を、scopeに入れます。

```lang:javascript
angular.module('App', ['ui.sortable'])
  .controller('AppCtrl', ['$scope', function($scope) {
    $scope.items = ["いれかえたい", "とてもいれかえたい", "なんとかいれかえたい"];
  }]);
```

入れ替えたい項目の親要素に、**ui-sortable**属性を設定。
scopeで入れた要素を、**ng-model**に入れる。

```lang:html
<body ng-app="App" ng-controller="AppCtrl">
  <ul ui-sortable ng-model="items">
    <li ng-repeat="item in items">{{ item }}</li>
  </ul>
</body>
```

cssでカーソルをmoveに設定すると、動かせそうな感じになります。

もしくは後述する、optionで**cursor: "move"**を設定する。

```lang:css
li{
 cursor:move;
}
```

<a href="http://codepen.io/satofaction/pen/GpKjdL" target="_blank">サンプル</a>

ユーザー側で入れ替えたデータは、ng-modelに反映されるので、controllerのscopeから取得できます。


##Optionを使う

###参考
<a href="http://api.jqueryui.com/sortable/" target="_blank">http://api.jqueryui.com/sortable/</a>

###Optionの設定方法
ui-sortable属性に追加して使用します。

```lang:html
  <ul ui-sortable="sortableOptions" ng-model="items">
    <li ng-repeat="item in items">{{ item }}</li>
  </ul>
```

```lang:javascript
 angular.module('App', ['ui.sortable'])
  .controller('AppCtrl', ['$scope', function($scope) {
    $scope.items = ["いれかえたい", "とてもいれかえたい", "なんとかいれかえたい"];
    $scope.sortableOptions = {
      axis: 'y'
    };
  }]);
```

下記のような書き方でもいいみたいです。

```lang:html
  <ul ui-sortable="{axis:'y'}" ng-model="items">
    <li ng-repeat="item in items">{{ item }}</li>
  </ul>
```

###各オプションの機能
####axis
移動方向を制御できる。

```lang:javascript
   //横方向に固定
    $scope.sortableOptions = {
      axis: 'x'
    };

   //縦方向に固定
    $scope.sortableOptions = {
      axis: 'y'
    };
```

<a href="http://codepen.io/satofaction/pen/YXmbvw" target="_blank">サンプル</a>


####update
モデルデータが変更された際に実行される

```lang:javascript
angular.module('App', ['ui.sortable'])
  .controller('AppCtrl', ['$scope', function($scope) {
    $scope.items = ["いれかえたい", "とてもいれかえたい", "なんとかいれかえたい"];
    $scope.sortableOptions = {
      update: function() {
        alert('ok')
      }
    };
  }]);
```

<a href="http://codepen.io/satofaction/pen/VvZKdV" target="_blank">サンプル</a>

特定の要素だけ移動をキャンセルするには下記のようにupdateの引数を使って、キャンセルする。
ただ、他を入れ替えると入れ替わっちゃうので、使い方がちょっと違うのかもしれない。

```lang:javascript
angular.module('App', ['ui.sortable'])
  .controller('AppCtrl', ['$scope', function($scope) {
    $scope.items = ["いれかえたい", "とてもいれかえたい", "動かさないで！！", "なんとかいれかえたい"];
    $scope.sortableOptions = {
      update: function(e, ui) {
        if (ui.item.sortable.model === "動かさないで！！") {
          ui.item.sortable.cancel();
        }
      }
    };
  }]);
```

<a href="http://codepen.io/satofaction/pen/GpKjPb" target="_blank">サンプル</a>

####update以外のイベント

updateの他に下記のようなイベントが取得できる。

```lang:javascript
angular.module('App', ['ui.sortable'])
  .controller('AppCtrl', ['$scope', function($scope) {
    $scope.items = ["いれかえたい", "とてもいれかえたい", "なんとかいれかえたい"];

    $scope.sortableOptions = {
      start: function(e, ui) {
        console.log('start')
      },
      stop: function(e, ui) {
        console.log('stop')
      },
      activate: function() {
        console.log('activate')
      },
      deactivate: function() {
        console.log('deactivate')
      },
      beforeStop: function() {
        console.log('beforeStop')
      }
    };
  }]);
```

####connectWith

connectWithを設定することで、違うmodel間での入れ替えが可能になる。
connectWithには、関連させるui-sortableのセレクタを指定する。


```lang:html
<body ng-app="App" ng-controller="AppCtrl">
  <ul class="box" ui-sortable="sortableOptions" ng-model="items1">
    <li ng-repeat="item in items1">{{ item }}</li>
  </ul>
    <ul class="box" ui-sortable="sortableOptions" ng-model="items2">
    <li ng-repeat="item in items2">{{ item }}</li>
  </ul>
</body>
```

```lang:javascript
angular.module('App', ['ui.sortable'])
  .controller('AppCtrl', ['$scope', function($scope) {
    $scope.items1 = ["いれかえたい", "とてもいれかえたい", "なんとかいれかえたい"];
    
     $scope.items2 = ["いいいいい", "あああああ", "ううううう"];

    $scope.sortableOptions = {
      connectWith: ".box"
    };
  }]);
```

<a href="http://codepen.io/satofaction/pen/bVbwyE" target="_blank">サンプル</a>


####placeholder

placeholderは入れ替え位置をドラッグ中に表示することができます。
placeholderには、class名を指定することで、表示を変更できます。


```lang:javascript
angular.module('App', ['ui.sortable'])
  .controller('AppCtrl', ['$scope', function($scope) {
    $scope.items1 = ["いれかえたい", "とてもいれかえたい", "なんとかいれかえたい"];

    $scope.sortableOptions = {
      placeholder:"placeholder"     
    };
  }]);
```

```lang:css
.placeholder{
  border:1px dotted #ccc;
  height:30px;
  background-color:#eee;
}
```

<a href="http://codepen.io/satofaction/pen/gaYXGo" target="_blank">サンプル</a>

####opacity

opacityを設定することで、ドラック中の要素の透明度を調整できます。


```lang:javascript
angular.module('App', ['ui.sortable'])
  .controller('AppCtrl', ['$scope', function($scope) {
    $scope.items1 = ["いれかえたい", "とてもいれかえたい", "なんとかいれかえたい"];

    $scope.sortableOptions = {
      opacity:0.5    
    };
  }]);
```

<a href="http://codepen.io/satofaction/pen/jbNaYX" target="_blank">サンプル</a>

####disabled

disabledを設定することで、要素の活性非活性を制御できます。

<a href="http://codepen.io/satofaction/pen/PPYOeR" target="_blank">サンプル</a>


他にもたくさんオプションがあるので、<a href="http://api.jqueryui.com/sortable/" target="_blank">こちら</a>をみていただくと参考になると思います。