タグ「AngularJS」が付けられているもの

ブラウザ側に情報を取っておく手段としてlocalStorageがあります。 昔はcookieを使っていたことが多く、今でもまだよく使われているのですが、 モダンブラウザ対応ならlocalStorageの方が適しているのではないかと思います。

以前、JavaScript nativeでlocalStorageを使うコードは書いたことがあって、 別に不満はなかったのですが、AngularでlocalStorageを簡単に扱えるライブラリがあると 思って調べてみました。

このあたりがメジャーそうです。順当に行くとStar数が一番多いangular-local-storageを選ぶのですが、 じっくりREADMEを読んでみます。APIは自明で分かりやすいです。bindはangularならではのAPIで便利そうです。 localStorageが使えない場合はcookieにfallbackするそうです。APIは抽象的に作られているということですね。

さて、2つ目のangularLocalStorageはどうでしょう。名前が似ていますが別物です。 bindもあるしAPIもシンプルで分かりやすいです。cookieへのfallbackもあるそうです。 angular-local-storageと比較すると若い分、Star数が少ないだけでしょうか。issueも処理されて アクティブに見えます。でも違いがない分、ドキュメントが充実しているangular-local-storageを選びたくなります。

最後の、ngStorageは、in the Angular Wayということで少し変わった感じです。

No Cookie Fallback - With Web Storage being readily available in all the browsers AngularJS officially supports, such fallback is largely redundant.

だそうです。確かにangularを使うようなブラウザでは、localStorageをサポートしていないケースは無いですね。 これは思い切りがよいです。気に入りました。

$scope.$storage = $localStorage;

使い方もこれだけです。APIとかそういうレベルではない感じ。とてもいいです。

And use it like you-already-know

だそうです。気に入りました。 これはつまり、localStorageを加えた3-way data bindingということですね。 これは応用が広がりそうです。時間があったらコードも読んでみたいです。

というわけで、おすすめはngStorageでした。

ng-conf 2015の動画を見ていたら、angular meteor integrationの動画がありました。

https://www.youtube.com/watch?v=uFmf-DeCdEE

Meteorを試した時に、angularを利用する可能性は考えましたし、 そのような記事もどこかで読んだ気がします。 しかし、Meteorが元から持っているテンプレート機能と重複しますし、 Meteorの恩恵をあまり受けられないかと思っていました。

ところが、Angular-Meteorはそれなりにうまく作られているようです。 興味がある方は、チュートリアル を見てみるとよいでしょう。 話が脱線しますが、このチュートリアルとてもやりやすいです。 Meteor本体のチュートリアルもそうですが、チュートリアルなのにかなり本格的な アプリを作っています。 Famo.us universityを見たときも思いましたが、チュートリアル周りの ベストプラクティスがたまってきていますね。 自分でもうまく活用できればいいと思います。

Angular-Meteorのチュートリアルをやってみて一番気に入ったのは、 3-way data bindingです。 これができるということは、AngularFireの代替になるのではないでしょうか。 ちょっとなにか作ってみたくなりました。 逆に一番気になったのは、getReactively周りの処理です。 特に手動でunsubscribeしなければいけないのは面倒です。

Maybe in the future we will add an automatic way to open and close subscriptions in scope's load and destroy events.

とあるので、解決されることを期待します。

話はまた変わりますが、Firebaseのtalkもng-conf 2015にありました。

https://www.youtube.com/watch?v=4nD5fjpIesk

こちらは、本家本流なのですごいですね。v1.0がリリースされたそうです。 彼らが3-way data bindingの名付け親です、たぶん。

Meteorはとても魅力的なのですが、自分が本当に気に入るか分からずちょっと悩んでいます。 その理由は、Fiberを使っていることと、jQueryを使っていること。 callbackは結構好きなのでFiberに魅力をあまり感じません。 一応、Fiberの流儀を使わず、callbackでも書けるので プロジェクトのコーディング規約で気をつければいいのですが。 jQueryの方は、非依存にする話もあるようですが、コアが依存しているという記述もあり、 完全に非依存になるには時間がかかりそうです。

https://groups.google.com/forum/?fromgroups=#!topic/meteor-talk/21y9NbM9v90

別に、jQuery依存だからといって困ることはないのですが、単に気分の問題です。

いずれにしても、Angualr-Meteorにはちょっと興味を持ちました。

Angularのdependency injectionはminifyに弱いです。 angular.jsのチュートリアルにも書かれています。

https://code.angularjs.org/1.3.8/docs/tutorial/step_05

A Note on Minificationのセクションに、 annotationをつけると書いてあります。

しばらく悩まずこの書式で書いていましたが、これはとても気をつかいます。スペルミスや並び替えをするときなど。なによりも、同じ文字を2回タイプするのは効率が悪いです。

ngminというのは聞いたことがあったのですが、100%変換できるわけではないという噂を聞いて使っていませんでした。今ではng-annotateというツールがあります。

https://github.com/olov/ng-annotate

ngminとの違いも説明されています。うまく行かない場合のためにコメントで明示的に指示できるというのが安心感があります。

これで快適になりました。やはり、自動化できることを人がやるのは無駄ですね。

ng-annotateはminifyをしてくれないので、minifyツールと合わせて使うことになります。今回は、

https://github.com/mishoo/UglifyJS2

を使うことにしました。下記にpackage.jsonを載せます。

{
  "scripts": {
    "minify:main": "ng-annotate -a public/main.js | uglifyjs -c -m > public/main.min.js"
  },
  "devDependencies": {
    "ng-annotate": "*",
    "uglify-js": "*"
  }
}

これで、

npm run minify:main

で動きます。 grunt等を使いたい人は、対応しているプラグインを使えばできるでしょう。

AngularでBootstrapを使うライブラリとして、以前の記事では、UI Bootstrapを紹介しました。

最近、AngularStrapも使ってみたので感想を書いておきます。

AngularStrapは初期の頃に名前を聞いたことがあるような気がします。確か、bootstrap v2の時代に。今では、AngularStrapもv2になってjQuery依存がなくなりました。いい時代の流れです。

さて、AngularStrapはUI Bootstrapと比べると根本的な設計思想は似ています。どちらも、bootstrapのcssだけ再利用して、javascript部分は作り直し、jQueryには依存しない、Look&Feelのカスタマイズ性を考慮している、と言ったところです。

しかし、使ってみるとだいぶ考え方に違いがあるような気がします。 UI Bootstrapはできるだけシンプルにbootstrapのcssを使えるようにしている一方、AngularStrapはbootstrapのcssをベースにしてよりリッチな機能を提供しようとしているようです。最大の違いは、アニメーションのサポートでしょうか。

簡単な例として、Alertの違いを見てみます。最初は、UI Bootstrap。

<alert type="{{alert.type}}" close="closeAlert(alert)">{{alert.content}}</alert>

これだけです。ng-repeatを使う例がドキュメントに載っていますが、直感的です。ng-showとも組み合わせられます。

次に、AngularStrapです。いろいろあるようですが、attributeを使う例。

<button class="btn" title="{{alert.title}}" data-content="{{alert.content}}" data-type="{{alert.type}}" bs-alert>Show alert</button>

buttonではなくdivで直接表示しようと思いましたが、できませんでした。ドキュメントではできそうなので、何か間違えているのかもしれません。 ng-showは使わず、オプションか属性でshowフラグを指定します。このあたり思想が異なる感じです。durationとか指定できるのは便利です。 alertは単純な機能なので、そこまで違いませんが、他の機能はもっと違いがありそうです。

個人的には、ui-bootstrapの方が使いやすいです。しかし、AngularStrapでアニメーションが簡単に使えるのも魅力的です。使い分けることにします。

人に勧めるのはどちらがよいか迷います。勉強が目的ならui-bootstrapでしょうか、リッチな機能が欲しいならAngularStrapでしょうか。

GitHub便利です。その一つが、Compare ViewのDiffです。Pull Requestを確認するときもよく見ます。コマンドラインでgit diffと普通にやるより見やすいです。

さて、背景は省略しますが、HTMLでdiffを表示したいと思いました。AngularJSでの利用を想定しているので、JavaScriptのライブラリが欲しいです。

ところが探してもあまり見つかりません。よくまとまっているのはこちら。

http://stackoverflow.com/questions/3053587/javascript-based-diff-utility

ちょっと古い投稿ですが。一番人気なのは、これです。

https://github.com/cemerick/jsdifflib

オンラインデモはこちら。

http://cemerick.github.io/jsdifflib/demo.html

だいぶ求めているもののイメージに近いです。 コードも枯れているらしい。 HTMLが出力されるので、Angularで使うならdirectiveを書かなければいけないですが、それは仕方ないですね。

これで行こうかと思ったところでしたが、なにか物足りません。 なんというか、見た目がワクワクしないのです。 改めてGitHubのDiffと比較してみると、全体的に色が濃すぎる。 あと、単語の差分がハイライトされない。色については自分でcssを書いて調整すればよいでしょうが、単語のハイライトはそれでは済みません。

というわけで、もう一度検索しました。見つけたのがこちらです。

https://github.com/rtfpessoa/diff2html

オンラインデモはこちら。

http://rtfpessoa.github.io/diff2html/

おお、おしゃれ。これですよこれ。なんとStar数は3でした。まったく注目されていません。コードも枯れていないでしょう。まだ不具合もあります。でも、魅力的です。これを使いましょう。

ところが、使うには一つ問題がありました。diff2htmlはdiffの出力を入力としているのです。例えば、

diff --git a/foo.txt b/foo.txt
---
+++
@@ -1,4 +1,5 @@
+zero
 one
 two
-three
+tree
 four

このようなものです。つまり、次はこれを出力するライブラリを探しました。いくつかありそうでしたが、比較的すんなり結合できたのはこちらです。

https://github.com/qiao/difflib.js

入力の行が配列になることと、出力の一行目のヘッダが付かないことなど不足点はありまして、それらは自力で対応しました。

最後にこれらを全部つなげて、angular.jsのdirectiveを書いてできあがりです。下記のような感じで使えるようになりました。

<my-diff path="foo.txt" old-content="one\ntwo\nthree\nfour\n" new-content="zero\none\ntwo\n\tree\nfour\n">

便利です。ちょっと気になることと言えば、依存javascriptが3ファイルもあって、グローバルに関数を定義するようなものであることです。なにかうまく隠蔽する方法があるのでしょうか。

AngularJSの流れにちゃんとついていくためng-europeをyoutubeで見ようと思い始めて一ヶ月が過ぎてしまいました。 まだ全部は見ていませんが、今日は一本見ました。興味深かったので記事にします。

https://www.youtube.com/watch?v=tfVA1syv-3o

AngularUIのui-bootstrapのお話です。 単にラップするわけではなくAngular流に作られているのと、カスタマイズ性を重視しているあたりは参考になります。

ui-bootstrapはBootstrap 3のcssのみを利用していてjavascriptの部分は全部書き直しているようです。つまり、jQuery依存もなしです。

ちょっと昔話を。当初、Bootstrap 2を使っていたのですが、クラス名などがどうも好きになれず、その後inkというcssフレームワークを見つけて 、しばらく使っていました。

その時から、inkのcssのみを使ってコーディングしていました。ロジックが必要な場合はAngular側で自前で作ってました。 例えば、カレンダーも当初はAngularUIのui-calendarを使っていましたが、 jQuery依存に抵抗があったため、カレンダーも単純な機能ならinkで自前で実装していました。

その後、Bootstrap 3が登場し、クラス名がinkのようにシンプルになったので、少し気に入ってBootstrap 3を使い始めました。でも、cssだけで、jsは使いません。例えば、alertもロジックはangularで自前で書いていました。と言っても、あまりコーディング量は多くなく、特に困っていません。

さて、話を戻しますと、ui-bootstrapは上記でやっていたようなことをちゃんとやっているような印象です。cssだけを使って、ロジックはangular用にdirectiveを設計してあるようです。 alertを見る限りでは単純なので自前で用意しても変わりませんが、他の複雑な機能はui-bootstrapのdirectiveを使うとだいぶ楽できそうです。

というわけで、jQuery非依存のui-bootstrapはおすすめです。

夏ごろに「暑さをみんなでふっとばせ!」というアプリを作りました。

1bitで使い捨てで匿名のコミュニケーションツールを作ってみた

に経緯が書いてあります。

当時は、Famo.usやF/Aのライブラリに手を入れないといけなかったのですが、その後バージョンアップして不具合が解消されました。 新しいバージョンでは読み込み速度なども改善しています。

せっかくなので、GitHubにソースをアップロードしました。 Famo.us/Angularとsocket.ioの組み合わせでこんなことができるというサンプルによいかと思います。

ついでに、「暑」を「寒」に変更する機能もつけました。タイトルはそのままですが。

GitHubのページはこちらです。

https://github.com/dai-shi/atsufut

実際に動作しているアプリのページはこちらです。

http://atsufut.axlight.com/#?color=blue&label=%E5%AF%92

AngularJSの1.3.0がリリースされました。

これまで、1.2系を使っていたのですが、これを機に1.3も試してみようと思いました。

1.0から1.2に移行したときは、はまったのですが、今回はなにも不都合がありませんでした。

ところが、e2eテストが動かなくなってしまいました。具体的には、下記のようなテストがエラーになりました。

expect(element(by.repeater('item in list').row(0).column('{{item.name}}')).getText()).toEqual('foo');

エラー文は、

NoSuchElementError: No element found using locator: ...

です。

https://github.com/angular/protractor/blob/master/docs/api.md

のドキュメントを見ても問題なさそうですし、StackOverflowなどでも話題になっているのは見つからず、途方にくれていました。

が、試しに下記のように変更したら動きました。

expect(element(by.repeater('item in list').row(0).column('item.name')).getText()).toEqual('foo');

これって正しい解決法なのでしょうか。

過去にKarma(Testacular)を使ったことはありますが、今回やっと時代に追いついてProtractorを使ってみました。特にPhantomJSを使ってheadlessでE2Eテストするときに気づいたことをまとめます。

Protractorは、 Seleniumの WebDriverJSのラッパーで、AngularJSのE2Eテストのためのフレームワークです。

https://docs.angularjs.org/guide/e2e-testing

がエントリーポイントになるでしょう。 しかし、これだけ読んでも最終的な実行方法は分かりづらいです。 今回の目的は、コマンド一つ、例えば、

$ npm run e2e-test

でE2Eテストを実行してするための環境セットを作ることです。また、headlessで動かしたかったので、典型的に使われるChromeではなく、PhantomJSを前提にしました。サーバはExpress/Node.jsの想定ですが、それ以外の場合にも応用できるかと思います。

初めによくある環境設定です。

$ npm install protractor
$ npm install phantomjs
$ ./node_modules/.bin/webdriver-manager update

この例ではローカルディレクトリにモジュールをインストールしていますが。グローバルにインストールしたい人はそのようにどうぞ。

まず初めにはまったことはwebdriverが起動しないことでした。

$ ./node_modules/.bin/webdriver-manager start
INFO - Launching a standalone server
WARN - null
java.net.SocketException: No such device
    at java.net.NetworkInterface.isLoopback0(Native Method)

このようなエラーがでました。ワーニングかと思って無視していたらいけませんでした。どうやら、IPv6のアドレスのみを使っていてうまく行かないようだったので、Javaのオプションを追加して次のようにするとうまく行くことが分かりました。

$ env _JAVA_OPTIONS=-Djava.net.preferIPv4Stack=true ./node_modules/.bin/webdriver-manager start

さて、Protractorのチュートリアルには、webdriverをコマンドラインで手動で実行するように書いてありますが、個人的にはこれは面倒に感じます。時間はかかりますが、毎回自動で起動して欲しいです。これは簡単で、protractor.conf.jsにseleniumAddressを書かなければよいだけでした。下記に、protractor.confを載せます。

exports.config = {
  specs: [
    '*-spec.js'
  ],
  capabilities: {
    'browserName': 'phantomjs',
    'phantomjs.binary.path': './node_modules/.bin/phantomjs'
  },
  baseUrl: 'http://localhost:' + (process.env.PORT || 3000) + '/'
};

これだけで大丈夫でした。baseUrlは、specにURLをフルパスで書かなくてもよいようにするためで、expressが下記のように起動されている想定です。

app.listen(process.env.PORT || 3000);

specの細かい内容は今回は書きませんが、もっとも単純なものは例えば次のようになります。

describe('tutorial', function() {
  it('should have a title', function() {
    browser.get('index.html');
    expect(browser.getTitle()).toEqual('The Title');
  });
});

ところで、Protractorはテストのフレームワークであるもののアプリの起動には関与せず、アプリは自分で起動しなければいけません。また、テスト終了後はアプリも終了したいです。今回はお手軽にシェルスクリプトを書きました。

#!/bin/sh

export _JAVA_OPTIONS=-Djava.net.preferIPv4Stack=true
export PORT=12345
node ./app.js &
PID=$!
./node_modules/.bin/protractor ./e2e-test/protractor.conf.js
kill $PID

このスクリプトをpackage.jsonのscriptsに書いておけば、当初の目的であったnpmで一発でE2Eテストを走らせることができました。

Happy e2e testing!

自分が興味あるものの一つにコミュニケーションツールがあります。 と言っても普通のコミュニケーションではないです。 例えば、見知らぬ人と一時的なつながりを感じられるようなそんなツールがいいと思います。言語も使わず、世界のどこかの誰かと。

FacebookのPokeはよかったです。1bitで行うコミュニケーションとでも呼びましょうか。日本では「あいさつ」となり、意味が分からなくなりました。 ちなみに、Pokeは一度機能が隠れてしまったのですが、また復活しました。 最近は、Yoが流行っているらしいです。これも1bitコミュニケーションだと思います。どこまで流行るのか、気になるところです。

流行っているついでに、Snapchatについても気になるところです。 実は使ったことありませんが、これは使い捨てコミュニケーションだと思っています。 使い捨てコミュニケーションができたら面白いだろうなぁとは思っていましたが、 まさかそんなものが流行るとは想像していませんでした。 写真だからうまくいったのでしょうか。

あとは、匿名コミュニケーションにも興味あります。 最近は実名指向で、あまり匿名を重視したコミュニケーションツールは登場していないのでしょうか。

と言うわけで、前置きが長くなりましたが、1bitで使い捨てで匿名のコミュニケーションツールを作ってみようと思いました。 1bitで伝えたいことはなんだろう、と考えたその日が暑い日だったので、「暑い」にしました。 「暑い」を伝え合うだけでは、どんどん暑苦しくなるだけですので、 ストレス発散をできるような「吹き飛ばし」機能をつけることにしました。

atsufut_title.png

これがタイトル画面です。

atsufut_main.png

これがメイン画面です。これだけです。 画面の上半分をクリック(タップ)すると、丸が落ちてきます。 何度も押すと、丸がたまってきます。 次に画面の下半分をクリックすると、丸を吹き飛ばします。 それだけです。

それでは、やってみましょう。

http://atsufut.axlight.com/

このURLをスマホで開きましょう。PCでも大丈夫です。モダンブラウザ必須です。

一人でやると、すぐに飽きます。 複数人で同時にやるとまあまあ面白いとは思います。 しかし、たまたま同時に開いている人がいることは稀です。 ここをどうするかが悩みどころです。

今回、開発に利用したライブラリは、 node.js, socket.io, angular.js, famo.us あたりです。