いつも説明が長ったらしくなる傾向にあるので、今回こそは要点だけスパスパッとかいつまんで書いてみます。
angularjs で Twitter クライアントを作成し AWS.S3 で動かす
Twitterクライアントにプロフィールページを追加
の続きです。
プロフィール画面まで作ってあるブランチはこちら。
やりたいこと
- Twitterクライアントでつぶやく
- formを使う
- バリデーションとか
- 投稿結果をダイアログで表示してみる
最終的にこうなります。
サービス追加
投稿機能を twitterService
に追記します。
postTweet: function(message) {
var deferred = $q.defer(),
url = '/1.1/statuses/update.json',
params = {
data: {
status: message
}
};
authResult.post(url, params)
.done(function(result) {
deferred.resolve(result);
}).fail(function(err) {
deferred.reject(err);
});
return deferred.promise;
}
ルート作成
いつもどおり新しいルートを作成し、ナビを追加します。
$ yo angular:route tweet
<div class="collapse navbar-collapse" id="js-navbar-collapse">
<ul class="nav navbar-nav">
<li><a href="#/">Home</a></li>
<li><a ng-href="#/profile">Profile</a></li>
<li><a ng-href="#/tweet">Tweet</a></li>
<li><a ng-href="#/about">About</a></li>
<li><a ng-href="#/">Contact</a></li>
</ul>
</div>
追加したら grunt serve
で動作確認することをお勧めします。
投稿画面作成
モジュール追加
以下のモジュールを追加します。
- angular-messages(フォームのメッセージ表示)
- angular-bootstrap(
bootstrap
コンポーネントのディレクティブを扱う)
$ bower install angular-messages angular-bootstrap --save
モジュール参照を app.js
に追加します。
angular
.module('mytwitterApp', [
'ngAnimate',
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',
'mytwitterApp.services',
'ngMessages',
'ui.bootstrap'
])
画面作成
前回のように layoutit で粗方の HTML を作成し、ディレクティブを記述します。
<div class="container-fluid">
<div class="row">
<div class="col-md-12" ng-show="tweet.showTweet">
<form class="well" name="tweetForm" ng-submit="tweet.submit()" novalidate role="form">
<div class="form-group">
<label for="tweet">Tweet Text</label>
<textarea class="form-control" name="tweet" ng-model="tweet.inputText" placeholder="tweeeeeeeeeeeeeeeeeeet"></textarea>
</div>
<button class="btn btn-primary" type="submit">つぶやく</button>
</form>
</div>
</div>
</div>
submit
時の振る舞いは form
タグ内に ng-submit
で記述する方法と、submit
ボタンに ng-click
で記述する方法があります。両方に書くと多重実行してしまう恐れがあるため、どちらかに書きましょう。
バリデーションとボタン制御
Twitter
クライアントなので、0 文字と 140 文字を超える入力をエラーにしたいです。テキストエリアに入力上限 ng-maxlength
と 必須 ng-required
を追加します。
<textarea class="form-control" name="tweet" ng-maxlength="140" ng-model="tweet.inputText" ng-required="true" placeholder="tweeeeeeeeeeeeeeeeeeet"></textarea>
<div ng-if="tweetForm.tweet.$dirty" ng-messages="tweetForm.tweet.$error" role="alert">
<div ng-message="required">入力は必須です。</div>
<div ng-message="maxlength">入力は140文字までです。</div>
</div>
form
ディレクティブはテキストエリアのバリデーション結果を tweetForm.tweet.$error
に格納します。ng-messages
は $error
の内容に基づき出力するメッセージを選択するディレクティブです。
参考:https://docs.angularjs.org/api/ngMessages
メッセージの <div>
タグに ng-if="tweetFrom.tweet.$dirty"
を指定しているのは、値変更時のみバリデーション結果を表示したいからです。画面表示直後に必須入力のエラーが表示されたらイヤですもの。
ng-disabled
でフォームの入力が有効な場合のみ「つぶやく」ボタンを有効にします。
<button class="btn btn-primary" ng-disabled="tweetForm.$invalid" type="submit">つぶやく</button>
tweetForm.$invalid
は、フォームの入力に不備がある場合のみ true
が入っているため、ここでは、テキストエリアが未入力または 140 文字を超える入力がある場合は「つぶやく」ボタンが押下不可になるわけです。今回は入力コンポーネントが1つですが、複数ある場合に便利ですね。
tweet.html
は以下のようになります。
<div class="container-fluid">
<div class="row">
<div class="col-md-12" ng-show="tweet.showTweet">
<form class="well" name="tweetForm" ng-submit="tweet.submit()" novalidate role="form">
<div class="form-group">
<label for="tweet">Tweet Text</label>
<textarea class="form-control" name="tweet" ng-maxlength="140" ng-model="tweet.inputText" ng-required="true" placeholder="tweeeeeeeeeeeeeeeeeeet"></textarea>
<div ng-if="tweetForm.tweet.$dirty" ng-messages="tweetForm.tweet.$error" role="alert">
<div ng-message="required">入力は必須です。</div>
<div ng-message="maxlength">入力は140文字までです。</div>
</div>
</div>
<button class="btn btn-primary" ng-disabled="tweetForm.$invalid" type="submit">つぶやく</button>
</form>
</div>
</div>
</div>
angularjs はフォームを作成すると内部的にコントローラを作成します。フォーム内のコンポーネントには formのname属性.コンポーネントのname属性
でアクセスします。フォームはいろいろな情報を持っています。ng-inspector(Chromeプラグイン)を使えば、スコープ内の要素、関数を参照可能です。べんり。
CSS
入力に NG がある場合にコンポーネントをピンクにしてみましょう。ナウい感じになります。
form .ng-invalid.ng-dirty {
background-color: lightpink;
}
form .ng-valid.ng-dirty {
background-color: lightcyan;
}
コントローラ作成
TweetCtrl
を作成します。
'use strict';
function TweetController(twitterService) {
var vm = this;
vm.inputText = '';
vm.showTweet = false;
twitterService.initialize();
if (twitterService.isReady()) {
vm.showTweet = true;
}
vm.submit = function() {
twitterService.postTweet(vm.inputText)
.then(function(result) {
console.log(result);
alert('Twitter投稿完了!');
}, function(err) {
console.log(err);
alert('Twitter投稿に失敗しました。');
});
};
}
angular.module('mytwitterApp')
.controller('TweetCtrl', TweetController);
Twitterへの投稿ができました!
では、投稿結果画面作ります。
と思ったけど、やっぱり長くなっちゃったので次回に続きます。。。Orz