formをValidateしてAjaxで通信 2

# やりたいこと

* 現状TOP画面表示時はAPIから受け取ったホテルリストをJinja2テンプレートのfor文を使って表示している。
* その並んだホテルにそれぞれUpdateボタンを配置。
* Updateボタンを押したら対象のホテルのModalダイアログが開く。
* 開いた時点で、inputタグの中身は既存のホテルの状態をValueで持っている。
* 更新ボタンでValidate処理。
* OKならAPIへAjaxでPOSTリクエスト。
* 更新した結果を表示。　

## 最初実装した悪い例

### UPDATE専用Modalダイアログを作成

これでIdは一意です。

```html+jinja

<!-- Update Hotel Modal -->
<div class="modal fade bd-example-modal-lg" id="updateHotelModal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="modal-label">Update Hotel</h4>
            </div>
            <div class="modal-body">

            <form id="updateHotel">
                    <input type="hidden" name="id" id="updId" value="">
                <div class="form-group">
                    <label for="updName" class="form-control-label">Hotel Name:</label>
                    <input type="text" class="form-control" name="updName" id="updName" value="">
                </div>
                <div class="form-group">
                    <label for="updAddress" class="form-control-label">Hotel Address:</label>
                    <input type="text" class="form-control" name="updAddress" id="updAddress" value="">
                </div>
                <div class="form-group">
                    <label for="updCountryCode" class="form-control-label">Country Code:</label>
                    <input type="text" class="form-control" maxlength="2" name="updCountryCode" id="updCountryCode" value="">
                </div>
                <div class="form-group">
                    <label for="updCityCode" class="form-control-label">City Code:</label>
                    <input type="text" class="form-control" maxlength="3" name="updCityCode" id="updCityCode" value="">
                </div>
                    <div class="form-group">
                        <label for="updGrade">Hotel Grade:</label><br>
                        <select class="span1" name="updGrade" id="updGrade">
                        <option>1</option>
                        <option>2</option>
                        <option>3</option>
                        <option>4</option>
                        <option>5</option>
                        </select>
                    </div>
                <div class="form-group">
                    <label for="updFacility" class="form-control-label">Hotel Facility:</label>
                    <input type="text" class="form-control" name="updFacility" id="updFacility" value="">
                </div>
                <div class="form-group">
                    <label for="updImagePath" class="form-control-label">Image URL:</label>
                    <input type="text" class="form-control" name="updImagePath" id="updImagePath" value="">
                </div>
                <img class="img-responsive" id="updImage" >
            </form>

            </div>
            <div class="modal-footer">
                <div id="response_parameter" ></div>
                <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                <button type="button" id="updateBtn" class="btn btn-primary">Update</button>
            </div>
        </div>
    </div>
</div>
<!-- End Update Hotel Modal -->

```

### Modalダイアログ動的に変更

それぞれのホテル更新用にModalダイアログを作成すべく、Jinja2のホテルリスト表示用for文の中に下記ボタン設置。

※ボタン以外省略

```html+jinja
{% for hotel in data.hotels %}

        <button class="btn btn-warning" type="button" onclick="createUpdateHotelmodal( {{ hotel | to_json }} )">Update</button>

{% endfor %}
```

### Modalダイアログに対象ホテルのvalue埋め込み ⇒ Modalダイアログ開く

```javascript
function createUpdateHotelmodal( data ){
    $('#updId').val(data.id);
    $('#updName').val(data.name);
    $('#updAddress').val(data.address);
    $('#updCountryCode').val(data.countryCode);
    $('#updCityCode').val(data.cityCode);
    $('#updGrade').val(data.grade);
    $('#updFacility').val(data.facility);
    $('#updImagePath').val(data.imagePath);
    $('#updateHotelModal').modal('show');
}
```

### Updateボタン押下で、validate ⇒ Ajax通信 ⇒ 結果表示

```javascript
    $("#updateBtn").click(function(){
        $("#updateHotel").validate(hotelUpdateValid);
        if (!$("#updateHotel").valid()) {
            return false;
        };
        $.ajax( {
            type: "POST",
            url: "/hotel/update",
            dataType: "json",
            data: {
                "id" : $('#updId').val(),
                "name" : $('#updName').val(),
                "address" : $('#updAddress').val(),
                "countryCode" : $('#updCountryCode').val(),
                "cityCode" : $('#updCityCode').val(),
                "grade" : $('#updGrade').val(),
                "facility" : $('#updFacility').val(),
                "imagePath" : $('#updImagePath').val()
            }
        }).done(function( response ){
            alert( "Hotel Id = " + response.data.hotel.id + " updated." );
        }).fail(function( data ){
            alert( "faild" );
        });
```

これで一応要件を満たした動きはしてくれますが、JSの引数をテンプレートエンジンで組み立ててしまっているためNGです。

## 悪い例を修正

### UPDATE専用Modalダイアログ修正

UPDATE専用Modalダイアログを作成して、idとnameをわざわざ一意のものにしてましたがその必要はなかったので、Ajaxリクエストを送信するときとjsonと同じnameを持たせるように修正。

これで後述のformの内容をjsonに変換する処理が可能になります。

そしてValidateのOptionも同じ内容をInputとUpdate用に別々で用意する必要がなくなりました。

```html+jinja

<!-- Update Hotel Modal -->
<div class="modal fade bd-example-modal-lg" id="updateHotelModal" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title" id="modal-label">Update Hotel</h4>
            </div>
            <div class="modal-body">

            <form id="updateHotel">
                    <input type="hidden" name="id" id="id" value="">
                <div class="form-group">
                    <label for="updName" class="form-control-label">Hotel Name:</label>
                    <input type="text" class="form-control" name="name" id="name" value="">
                </div>
                <div class="form-group">
                    <label for="updAddress" class="form-control-label">Hotel Address:</label>
                    <input type="text" class="form-control" name="address" id="address" value="">
                </div>
                <div class="form-group">
                    <label for="updCountryCode" class="form-control-label">Country Code:</label>
                    <input type="text" class="form-control" maxlength="2" name="countryCode" id="countryCode" value="">
                </div>
                <div class="form-group">
                    <label for="updCityCode" class="form-control-label">City Code:</label>
                    <input type="text" class="form-control" maxlength="3" name="cityCode" id="cityCode" value="">
                </div>
                    <div class="form-group">
                        <label for="updGrade">Hotel Grade:</label><br>
                        <select class="span1" name="grade" id="grade">
                        <option>1</option>
                        <option>2</option>
                        <option>3</option>
                        <option>4</option>
                        <option>5</option>
                        </select>
                    </div>
                <div class="form-group">
                    <label for="updFacility" class="form-control-label">Hotel Facility:</label>
                    <input type="text" class="form-control" name="facility" id="facility" value="">
                </div>
                <div class="form-group">
                    <label for="updImagePath" class="form-control-label">Image URL:</label>
                    <input type="text" class="form-control" name="imagePath" id="imagePath" value="">
                </div>
                <img class="img-responsive" id="image" >
            </form>

            </div>
            <div class="modal-footer">
                <div id="response_parameter" ></div>
                <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
                <button type="button" id="updateBtn" class="btn btn-primary">Update</button>
            </div>
        </div>
    </div>
</div>
<!-- End Update Hotel Modal -->
```

### Modalダイアログ動的に変更

前処理でリスト表示されたhotelのうち、選択したhotelのそれぞれの値をformに持たせてから、Modalダイアログを開く点については変わりませんが、いくつか変更を加えました。

#### ボタンの修正

下記のようにJSの関数の引数としてJinja2を使ってしまっていましたが、これはNGなので修正。
※　場合によってはJSのコンパイルエラーが発生するなどの問題がある。

```html+jinja

<button class="btn btn-warning" type="button" onclick="createUpdateHotelmodal( {{ hotel | to_json }} )">Update</button>

```

属性としてデータを持たせておき、JS側で処理をするという方法をとる必要があるため下記のように変更しました。

```html+jinja

<button class="btn btn-success updModal" type="button" id="{{ hotel.id }}" data-hotel="{{ hotel | to_json }}" >Update</button>
```

#### fromのvalue埋め込みの修正

```js

function createUpdateHotelmodal( data ){
    $('#updId').val(data.id);
    $('#updName').val(data.name);
    $('#updAddress').val(data.address);
    $('#updCountryCode').val(data.countryCode);
    $('#updCityCode').val(data.cityCode);
    $('#updGrade').val(data.grade);
    $('#updFacility').val(data.facility);
    $('#updImagePath').val(data.imagePath);
    $('#updateHotelModal').modal('show');
}
```

前回は上記のようにひたすら```$('#id').val(data.value);```のようなことをしてそれぞれ値を埋め込む。

みたいなことを繰り返していましたが、変更があるたびに修正が必要になります。

なので今回は、jsonの値をそのままformの各idのvalueに埋め込むという方法に修正しました。

```js
    $('.updModal').click(function(){
        var targetHotel = JSON.parse($('#'+ this.id).attr('data-hotel'));
        $.each(targetHotel, function(key,value){
            $("#updateHotel").find("#"+key).val(value);
        })
        $('#updateHotelModal').modal('show');
    });
```

* 先ほど修正した```class="updModal"```のボタンをクリック
* data属性である```data-hotel="{{ hotel | to_json }}"```のjson文字列の値をObjectとして取り出す
* そのObjectのkeyとvalueから```$.each```を用いてformにそれぞれ埋め込む

このような流れです。埋め込んだ後で``` $('#updateHotelModal').modal('show');```でモーダルを開くと、inputの要素が既存のデータで埋まっている状態で開かれます。

もっとシンプルにする方法を考えましたが、いまはここで止まっています。

#### validate ⇒ Ajax通信

```js
data: {
    "id" : $('#updId').val(),
    "name" : $('#updName').val(),
    "address" : $('#updAddress').val(),
    "countryCode" : $('#updCountryCode').val(),
    "cityCode" : $('#updCityCode').val(),
    "grade" : $('#updGrade').val(),
    "facility" : $('#updFacility').val(),
    "imagePath" : $('#updImagePath').val()
}
```

こちらも前回は上記の様に、POSTするjsonの内容を、```"id" : $('#id').val(),```のようにひたすら書いていました。

今回は、formの内容をjsonに変換して```data : form_data```のようにシンプルで変更に強くなるように修正。


```js
$("#updateBtn").click(function(){
    $("#updateHotel").validate(hotelValid);
    if (!$("#updateHotel").valid()) {
        return false;
    };

    var form_data = {};
    $.each($("#updateHotel").serializeArray(),function(i,o){
        form_data[o.name] = o.value;
    })

    $.ajax( {
        type: "POST",
        url: "/hotel/update",
        dataType: "json",
        data: form_data // この部分
    }).done(function( response ){
        alert( "Hotel Id = " + response.data.hotel.id + " updated." );
        location.reload(true);
    }).fail(function( data ){
        alert( "faild" );
    });
});
```


`$("#updateHotel").serializeArray()`で取得したデータは、

```json

[{"name":"id","value":"47"},{"name":"name","value":"Yaoji Hakata Hotel"},...]
```

のようなリストになっているので、これをまた```$.each```を使って、json形式にします。

```json
{"id":"47","name":"Yaoji Hakata Hotel",...}
```

作成したjsonデータを```data : form_data```とすることで、仮にformの内容に変更があってもここでの修正が不要になります。