戯言

つらつらと気づいたことを書いていきます。人狼とか。

スポンサーサイト


上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

AngularJSで、動的に入力項目数を設定する


例えば「趣味は何ですか?」に対する回答はいくつになるかわかりません。
「料理」と答える人もいれば、「ゴルフ」と「TVゲーム」と「ショッピング」と答える人もいるかもしれない。
今回はこのように、あらかじめ幾つになるかわからない項目に対する入力画面を作るときに、AngularJS使うと簡単にできるよ、というお話です。

この例のような場合によくある入力画面は、複数行の入力欄があり、行ごとに削除ボタンがあって、入力した内容が消せるようになっており、最後の行だけは「削除」ボタンのでなく「追加」ボタンがあって、入力欄を一つずつ動的に増やせるってやつです。

こんなイメージのやつです。これはボタン押しても動きません。
ここに動くコードを置いときました。 http://jsfiddle.net/2Y88u/
  • 趣味の名前=月に何回やる?
  • 趣味の名前=月に何回やる?
  • 趣味の名前=月に何回やる?

これを、AngularJSを使って作ってみます。

早速ですが、コード例。これだけです。


HTML
<div ng-app="myApp" ng-controller="hobbyCtrl">
<ul>
<li ng-repeat="hobby in hobbyAry">
趣味の名前=<input type='text' ng-model="hobby.name">
月に何回?<input type='text' ng-model="hobby.times">
<input type='button' ng-if="!$last" ng-click='delHobby($index)' value='削除' />
<input type='button' ng-if="$last" ng-click='addHobby($index)' value='行を追加' /></li>
</ul>
{{hobbyAry}}
</div>
Javascript
var app = angular.module('myApp', []);
app.controller('hobbyCtrl', function($scope){

initSize = 3;

// 初期化
$scope.hobbyAry = new Array();
for (var i = 0; i < initSize; i++){
    $scope.hobbyAry[i] = {};
}

// 追加
$scope.addHobby = function(idx){
    $scope.hobbyAry[idx+1] = {};
};

// 削除
$scope.delHobby = function(idx){
    $scope.hobbyAry.splice(idx, 1);
};

});
すごくシンプルに書けます。

AngularJSを使わない場合は、
・最後の行かどうかを判断して、削除ボタンと追加ボタンを切り替えないといけないな・・・
・行を追加したら、行数が変わって、最後の行もずれるな・・・
・削除したら、一つずつ上に詰めないといけないな・・・
などなど、面倒なことを考えなければならなそうです。

AngularJSを利用する場合は、ng-repeatの最後かどうかを判別できる$lastを使い、$lastがtrueなら追加ボタン、falseなら削除ボタンを表示するようにします。


追加ボタンクリック時は、addHobby()が呼ばれ、最後+1番目の配列を増やして初期化するだけです。
削除ボタンクリック時は、spliceを使って削除ボタンが押された行の配列を削除し1つ詰めるだけです。

値を格納する配列は、最初に初期化しておく必要があるので、お忘れなく。

それでは、お試しあれ。




スポンサーサイト

AngularJSの複雑なfilterを、関数で実現する


AngularJSを使い始めて、まず誰もが便利だなと感じるのは、ng-repeat での繰り返しと、filter を使った検索ではないでしょうか。いろいろな紹介サイトでも、記述例が見受けられます。
<input type="text" ng-model="query.$" placeholder="全項目で検索">

<table><tbody>
<tr ng-repeat="row in rows | filter:query">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.address}}</td>
<td>{{row.note}}</td>
</tr>
</tbody></table>
これだけで、rowの全ての要素(id、name、address、note)のどこかに、input text で入力された内容を含んでいるものだけが、表示されます。

row.idに含んでてもいいし、row.nameに含んでいいし、row.addressに含んでいてもよい。「長野」と入力すれば、nameの長野さんも、addressの長野県も引っかかります。



では、row.nameのみに対して絞り込みをしたい場合。こうなります。
<input type="text" ng-model="query.name" placeholder="名前で検索">
filter の対象を name のみにするために、ng-model="query.$" の部分を ng-model="query.name" に変えればよいのです。
この場合は、nameの長野さんは検索対象となるが、addressに長野県とあってもひっかかりません。



では、nameとnoteの2項目のみを検索の対象にしたいという場合は、どのようにすればよいのでしょうか?

「複雑な検索を行う場合は、directiveを使いましょう。」ってのも間違いじゃないんだけど、directiveを使わずとも、単純な検索フィルタ用の関数を利用することもできます。
<input type="text" ng-model="query" placeholder="nameとnoteを対象に検索">

<table><tbody>
<tr ng-repeat="row in rows | filter:search">
<td>{{row.id}}</td>
<td>{{row.name}}</td>
<td>{{row.address}}</td>
<td>{{row.note}}</td>
</tr>
</tbody></table>
// JS
$scope.search = function(line){
    // 各行をlineオブジェクトで受け、trueを返した行だけがマッチ
    if (line.name.indexOf($scope.query) != -1 ||
        line.note.indexOf($scope.query) != -1){
	    return true;
    }
    return false;
};
これで、nameとnoteのみに対して、検索をすることができます。



AngularJSを扱いはじめた当初は、今まで数十行も書いて実現していたロジックを、とてもシンプルに書くことができて、非常に便利で生産性が高いと感じますよね。でも、ちょっと複雑なことをしようとすると、躓いてしまうことがよくあります。これは、日本語の解説サイトがまだまだ充実していないことも原因でしょうね。

もっと、AngularJSが広まってほしい。
便利だよ!



AngularJSのhttpリクエストに、固有のヘッダを付与する方法


X-Requested-By: true というヘッダを付与する例です。

個別の通信ごとにヘッダを付与する方法
$http({
	method: "POST", 
	url: "../resource/xxxdata", 
	data: detail
	headers: { "X-Requested-By": "true" } 
})

全POST通信に共通して付与したい場合は、モジュールを使用します。
module = angular.module('xxxxApp', []);
module.config(['$httpProvider', function ($httpProvider) {
	$httpProvider.defaults.headers.post["X-Requested-By"] = "true";
}
]);
同じ働きをするメソッドが、GET や PUT でも使えましたが、DELETEでは使えなかった…。
用意されていないのかな?





上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。