この素晴らしきフロントエンドに祝福を

アニヲタからフロントエンドエンジニアへ転身した私の備忘録。

悩めるangular2使い【CSSスタイリング】

angular2を使っていて、
とても悩ましく思うことが多々あります。

そのうちの1つは
実現可能な実装方法が複数ある中で
どの方法を選択するのかという悩みです。

これはプログラミングする上では当たり前の悩みですし、
どの方法を選択するかは腕の見せ所ではあるのですが、
angular2に関してはまだ判断基準が曖昧でして。

ここでズバリこれがベストプラクティスだ!
と示すことができればかっこいいんですが
現状、結論のでないまま悶々とした気持ちで
悶々とさせる記事を投稿しやがります。

例えば、
コンポーネント内でh1タグの背景色を赤色にする
という初歩的な実装があったとします。

それを実現するにあたり、
私が思いつく限りでは6つの実装方法があるかと
思います。

ソースを見た方が早いかと思うので
こちらをご覧ください。

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `

  <!-- ①定石通りにやる場合 -->
  <h1 style="background-color:#ff6666;">
    {{title}}
  </h1>

  <!-- ②カプセルCSSの場合 -->
  <h1 class="sample">
    {{title}}
  </h1>

  <!-- ③プロパティバインドの場合 -->
  <h1 [style.backgroundColor]="'#ff6666'">
    {{title}}
  </h1>

  <!-- ④ngStyleを使う場合 -->
  <h1 [ngStyle]="{'background-color':'#ff6666'}">
    {{title}}
  </h1>

  <!-- ⑤ngClassを使う場合 -->
  <h1 [ngClass]="{sample:true}">
    {{title}}
  </h1>

  <!-- ⑥カスタムディレクティブを使う場合 -->
  <h1 sample>
    {{title}}
  </h1>
  `,
  styles: [`
  .sample{
    background-color:#ff6666;
  }
  `]
})
export class AppComponent {
  title = 'app works!';
}

import { Directive,ElementRef,Renderer } from '@angular/core';
@Directive({
  selector:'[sample]'
})
export class SampleDirective{
  constructor(private el:ElementRef,private renderer:Renderer){
    this.renderer.setElementStyle(this.el.nativeElement,'background-color','#ff6666');
  }
}

画面はこのように表示されます。

f:id:zetton110:20161014021126p:plain

すべて同様の結果となっています。
この①〜⑥の使いドコロとメリデメを自分の中で
明確にしたいのですが結論はでていません。

自分なりの答えが見つかり次第、
随時追記していく予定です。

もしこの記事を見たangular2使いの方で
思うところがある方はぜひコメントを残していただけると
泣いて喜びます。

angular2入門【ディレクティブ編】

こんにちわ、
ゼットンです。

今日はangular2のディレクティブを
作ってみましょう。

ディレクティブについて簡単に説明すると、
HTML要素に対して修飾や振る舞いの変化を
与えるものです。

口で説明するより
実際にやってみた方が早いので
早速手を動かしてみましょう。

例によって
ng newをした後からスタートです。

https://www.evernote.com/l/AS3VRC7AXjlJkLbMhu4mr3-lhPmk8LrFspgB/image.png

https://www.evernote.com/l/AS1nvFoLPiFAXY3gdC3dQ6q2udpYqQ1GenEB/image.png

お、マリさんが来たので、
今回はタイトルを少々変えましょう。

https://www.evernote.com/l/AS3vhLTuJ1FLeLcZ_uP2EN1LJjFd7rRuuFAB/image.png

画面はこうなってます。

https://www.evernote.com/l/AS0Qe5iWudJPx5wTLBXuCIxDd_PbyQLYHCEB/image.png

では、今回のテーマのディレクティブを作ります。
src>appフォルダ配下に
shiny.directive.tsというファイルを追加します。

https://www.evernote.com/l/AS1x_Q4UuXVH_oldNezkNifCcqMnlNxEpskB/image.png

内容はこのようにしてみました。

https://www.evernote.com/l/AS3lYvkbmGFERaM_Aocw8k2T9Hi4uqIrujMB/image.png

importするのは3つのモジュール。
それぞれの役割は以下になります。
・Directive    ・・・ディレクティブの定義付け
・ElementRef  ・・・ HTML要素へのアクセス
・Renderer   ・・・ 要素の修飾

@Directiveのselectorプロパティに
ディレクティブ名を定義します。
this.el.nativeElementによって
ディレクティブが付与されるHTML要素に
アクセスできます。
それをrendererのsetElementStyleメソッドに第1引数として
渡し、CSSの指定を第2、3引数で行っています。 ではこのディレクティブを使ってみましょう。
app-rootに下記を追加実装します。

https://www.evernote.com/l/AS38R_pjIJ5KIYEFljOqOPapj0oXx6RyfJEB/image.png

先ほど作成したディレクティブを読み込み、
h1タグにディレクティブ名を与えています。

次に、モジュールに作成したディレクティブを追加します。
app.module.tsを下記のようにします。

https://www.evernote.com/l/AS1ZgJrdtQNIrJ61C34hwB6HaQNhEn9ZFckB/image.png

declarationsに作成したディレクティブを
登録することをお忘れなく。

ここまできたら
画面を確認してみましょう。

https://www.evernote.com/l/AS1N4VZNvQNEZqCY7iBUh5f2CV1BEyyPsgYB/image.png

https://www.evernote.com/l/AS2eXwdZdd5EwpPRivDKP1CdSxRMan2dp_oB/image.png

ありがとうございました。

angular2入門【Bootstrap導入】

こんにちわ
ゼットンです。

ng-bootstrapの導入

今回は、angular2のプロジェクトにbootstrapを導入してみます。
手順としては

1.npmインストール
2.バンドルの中へ含まれるようにする
3.アプリ内でグローバルに使えるようにする
という感じ。

1. npmインストール

プロジェクトフォルダに移動し、
下記を実行します。

npm install --save ng2-bootstrap

2. バンドルの中へ含まれるようにする (src/app/shared/index.ts)

angular-cliはwebpackによって
自動的に一つのJavascriptファイルに連結されます。
その中にbootstrapが含まれるようにindex.tsに定義します。

import '../../../node_modules/ng2-bootstrap/bundles/ng2-bootstrap.min.js'

3. アプリ内でグローバルに使えるようにする (src/styles.css)

styles.cssに下記の定義を加えることで、 アプリ全体にBootstrapを適応できます。

@import url("https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css");

angular2入門【パイプ編②】

こんにちわ
ゼットンです。

前回はangular2の組み込みパイプについて
扱いました。
今回のテーマはカスタムパイプです。

カスタムパイプ

カスタムパイプとは
独自に定義したパイプです。
例えば前回UpperCaseパイプやDateパイプを
使ってサクッと表記の変更をしました。
あのような機能を勝手に作れちゃうんですね。
もちろん変換部分はそれぞれで実装が必要ですが。
ではやってみましょう。

まずは例によって、ng newをした直後の
Hello world状態からスタート。

https://www.evernote.com/l/AS1VK0hKYZNDFaWgxfJYwFCf3bL4EpgPeeYB/image.png

app-rootタグの中身です。
デフォルト状態だとコンポーネント内が分割されて見通しが悪いので、
1ファイルにまとめてあります。ここは気になさらず。

ではapp-rootタグと同じ階層に
カスタムパイプ用のtsファイルを追加しましょう。
名前は「hina.pipe.ts」でいきましょうか。

https://www.evernote.com/l/AS1EwcNFhv1NfoxOj7W0IMGpHTf7j2gOr7cB/image.png

中身はこんな感じで実装してみました。

https://www.evernote.com/l/AS3HkmeQIqpPeoY7Q4cdUHsmAzB-QVS6iSEB/image.png

カスタムパイプは@angular/coreからPipeとPipeTransformを
インポートして作成します。
@Pipeのnameプロパティにパイプの名前を指定しています。
中の実装については、簡単すぎるので説明しません。
後の動作確認で全てわかります。

ではこのパイプを使うために、
app-rootタグの中身をちょこっと変えちゃいます。

https://www.evernote.com/l/AS251yREk4pFN72wpXXGtZ3ty7LBlGIxgSIB/image.png

画面は以下のような感じ。
テキストボックスに入力すると・・・

https://www.evernote.com/l/AS1BUXAr5rNCfqwR1Qn3qj5hAF0uDeVGDVcB/image.png

即座に画面に描画されるようになっています。
inputタグに#inputという形で
Template Syntaxを付加し、
pタグ内でバリューを取り出しているという実装です。
ここについては追々詳しく話せたらと思います。
そんで、今回はパイプ!ですね。
ここに、先ほど作成したhinaパイプを実装してみます。
とは言っても簡単です。こんな感じ。

https://www.evernote.com/l/AS0G6XuJklxL8o73XajhMwC7esaRxzle8_EB/image.png

ファイルをimportして
組み込みパイプと同じようにパイプ名で呼び出しています。
パイプ名は先ほど@Pipeのnameプロパティに
設定してあげた名前です。

そんで画面を見てみると・・・

https://www.evernote.com/l/AS1Skmy2QalNY6jrGE9WSci1PpXNB7fsYWgB/image.png

おやぁ?
Loadingから動きません。
これはエラってるやーつですね。
F12を押してコンソールを確認すると

https://www.evernote.com/l/AS0PiUwckVhKmLvufgj3zbX5KXu-FeHNBUAB/image.png

https://www.evernote.com/l/AS3N4MF6dDtDCJEIDhVTEKGQoUqEv9J9ZAEB/image.png

大丈夫!
おいたんに任せろ!
このエラーは前に見たことあるぞ!!(前々回を参照)

このエラーの原因は、

カスタムパイプをモジュールに追加していないから

です。

というわけで、
hinaパイプをモジュールに追加してやりましょう。
app.module.tsに追記します。

https://www.evernote.com/l/AS2iigHQgkpDD4nLQtxmhFoFcgL3o0aZnlsB/image.png

コンポーネントと同様に、
パイプを追加した場合もモジュールのdeclationsに追加
してあげないといけません。
これでhinaパイプが使えるようになりました。

では、動作確認をしましょう。

https://www.evernote.com/l/AS01fuhMzvNFAaQFjAGI5631hy7ui2vJHh4B/image.png

まずは誤動作しないか、
適当な文字列を入力しましょう。

https://www.evernote.com/l/AS06FHi4icFP25gjnXE-9poQm0_TuY4LuIwB/image.png

大丈夫ですね。
ひなパイプは反応してません。

https://www.evernote.com/l/AS1TLvUkjcxC5JtznRWJmUsa3jCenIeT5RcB/image.png

こちらも大丈夫です。
ひなパイプは反応してません。

では、
最後に「ひな」と入力してみます。

https://www.evernote.com/l/AS30J2X3LTBEDaPWY1fwdK97COmw10WiuxcB/image.png

ドクン・・・ッ

https://www.evernote.com/l/AS0ubNHJ0utFVbO-u7OdQjeHXSNmWeA-aowB/image.png

キターーーーーーーーーーーーーーーーーーーー!!!!

https://www.evernote.com/l/AS2QvwK_oDdG5p5EcYeUBUyC0fAsj9J7IboB/image.png

次回はディレクティブでも扱いますか。

angular2入門【パイプ編】

前回はコンポーネントの追加について、
お話しました。

https://www.evernote.com/l/AS2jE5iaf9JCpYIXWZvcDpVqxgiurMK-5PYB/image.png

ひな〜〜おいたんはゼットンだよ〜 本日はパイプを使ってみるよ〜

組み込みパイプ

https://www.evernote.com/l/AS2pLGHPyZNKm5rUi5bJazPXodRYxC-5v7wB/image.png

パイプとは何かと言いますと
文字列や数字を整形する機能、とでも言いましょうか。
実際に使って見せた方が早いので
やってみます。

ng newしたところからスタート。
コンポーネントは1ファイルにまとめてますが
構造は変わってません。
app-rootの中身はこんな感じ。

https://www.evernote.com/l/AS3VRC7AXjlJkLbMhu4mr3-lhPmk8LrFspgB/image.png

そして画面は

https://www.evernote.com/l/AS1eZx_V-EhLo6xJBJe44BL_37nRTVDXUp8B/image.png

超デフォルトです。
これにパイプをくわえて見ましょう。
そーい!

https://www.evernote.com/l/AS13M9oLFVFM-ZZ5ynfrWjUR6wM3yheJ8d4B/image.png

変数titleの右に変なものがつきましたねぇ。
これがパイプってやつです。
それで画面がどうなったかというとー

https://www.evernote.com/l/AS3r0C1ru2JA34ewyKa4yv2wa7NnVUfUpR4B/image.png

おわかりいただけただろうか。
app works!がAPP WORKS!になりました。
これがUpperCaseパイプの機能です。
angular2にデフォルトで組み込まれている機能なので、
特に何もインポートしなくても使えます。

組み込みのパイプは他にも色々あります。
例えば〜の話をするために、
app-rootを再び書き変えちゃいます。

https://www.evernote.com/l/AS22DaYOmwFOOZAU3noyxu6YYrHumpz3nzUB/image.png

変数todayに今日の日付のDate型オブジェクトを入れて
画面に出してみました。
これがどんな風に見えるのかというと

https://www.evernote.com/l/AS0Yy80LG0xNBoPl0CxNCOPZHElm4BgFJiIB/image.png

長い!
情報が多くてよくわからん。
まあDate型のオブジェクトをそのまま
出したらこうなりますよね。
普通は年月日をそれぞれ取り出して連結する手間を
加えてから画面に出すかと思います。
ですが、パイプを使うと簡単にいい感じに
整形できます。こんな感じ。

f:id:zetton110:20161007004759p:plain

やってることはこれだけ。

https://www.evernote.com/l/AS3pHctamz1PZpTTeCHSUOmwp8Dm2Usnsm8B/image.png

これがDateパイプです。
他にも組み込みのパイプは色々あります。

https://www.evernote.com/l/AS3RZ930SQlLzIvjLqgIjEpdrjQn3QIV4GMB/image.png

詳しくは公式ドキュメントをご覧あれ。

angular.io

パイプは単独でも使えますが、 複数のパイプを組み合わせることもできます。 例えばこんな感じ。

https://www.evernote.com/l/AS1j_E-2lPtK37KkE4LSbhQIM3ucZAnHeF0B/image.png

これで画面がどうなってるのかというと

https://www.evernote.com/l/AS0h8ffSLuxND7P5uAyU4SWlv2ZCxkrHx8sB/image.png

おわかりいただけただろうか・・・ 地味にNovがNOVに変わりました。 Dateパイプで書式が変換されたものを 更にuppercaseパイプで大文字に変換したんですね。 これは便利、色々使えそうです。

組み合わせて使う以外にも、 オプションをつけて使うということもできます。 例えば先ほどのdateパイプにオプションをつけてみます。 こんな感じ。

https://www.evernote.com/l/AS17L9HCG_RER55QdvKA8oNPRMxVCQ3A8C8B/image.png

なんとなくどうなるか想像できますね〜
こうなります。

https://www.evernote.com/l/AS2QvwK_oDdG5p5EcYeUBUyC0fAsj9J7IboB/image.png

くうぅぅぅぅぅぅかわいいーー!!!!!
ってダメでしょ、ひな!!
画面はこっちです。

https://www.evernote.com/l/AS2DsM50khNAHLZAtko7BCcpxctUoKf9mssB/image.png

やっぱりね!
こうなるよね!!
今日はもう一つだけパイプにオプションをつけた例を
紹介して終わりにしましょう。

app-rootを書き換えて〜
ひなのことを考えてたら
次のような実装になっちゃいました。

https://www.evernote.com/l/AS1jb7kCm6RGUp7SUirlAemQuU7kxtCy_woB/image.png

画面はこんな感じ。

https://www.evernote.com/l/AS35rZ3n5vlGYbM6vYGw92mSSnihxfIyP78B/image.png

ここにSliceパイプをオプション付きで加えてみます。
ほいっ!!

https://www.evernote.com/l/AS1cNiBQIrFHWoG53vc9T3yBEt3ObD3AL2gB/image.png

そして画面は!

https://www.evernote.com/l/AS0-UHhhu-BF1JvAYdi5xBOQjQ9DB78LV4kB/image.png

https://www.evernote.com/l/AS2QvwK_oDdG5p5EcYeUBUyC0fAsj9J7IboB/image.png

次回はカスタムパイプだお!!

angular2入門【コンポーネント編②】

ゼットンです。
前回は自動生成されたソースを見ながら
Componentについて説明しました。
今回はここに新たなコンポーネントを追加してみます。

Componentの追加

https://www.evernote.com/l/AS3JgkcxhaFC64vs3XvIx6UfOeMDShxnMJoB/image.png

src>appフォルダにchild.component.tsというファイルを
追加します。
中身は下記のようにします。

https://www.evernote.com/l/AS3bPgo-SM9ClqezkAQXKVXYLSMa1NPN6QwB/image.png

タグ名はapp-childとします。
名前はなんでもいいですが、
独自定義のタグはapp-xxにするとか
ルールを設けとくと標準のタグと
すぐに見分けがついていいと思います。
そんで、変数titleにchild component!という
文字列を格納します。

ではでは、このChildコンポーネント
前回説明したapp-rootの中で使いたいと思います。

というわけで、
app-rootに下記の実装を追加。

https://www.evernote.com/l/AS2_CbX8AmxM65wlVBcE8ni_HhSHu6OhvhoB/image.png

import文で先ほどのchildコンポーネントを読み込みます。
ここはファイル名で指定します。
そんで、タグ名をHTML部分に書いてあげてます。
つまり、ファイルを読み込み、タグ名で呼び出しているというわけ。
なんとなく動きそうな気がします!
ng serveコマンドを打って、
http://localhost:4200にアクセスしてみましょう。

https://www.evernote.com/l/AS2GnsHrjL9AbYPqp35gQRLVOjGZWzU_VYgB/image.png

おやぁ?

https://www.evernote.com/l/AS2UKoX7S1BC5oRHv0PZRW0vsGlMlsH2wsEB/image.png

ゆう〜〜〜
大丈夫だよ〜〜〜
こういうときはブラウザ上でF12を
押すんだよ〜〜〜

https://www.evernote.com/l/AS2z7prydrpB8JzCw2fado2yB696yv1ZQJgB/image.png

こうすると開発者モードに移行し、
デバッグコンソールが見れます。
おや、なんかエラーが出てますね。なになに

https://www.evernote.com/l/AS2ZkglIgBhIRp-hWTIm2MrFcP5u3V5BTKoB/image.png

https://www.evernote.com/l/AS2drXm1RH1CLYRHzunO7lmdctQrltdxZHgB/image.png

それな!
いや、でもここは避けて通れないから
頑張ろう。
とりあえず最初の3行だけでも・・・。

https://www.evernote.com/l/AS2vAR0O271JBKL7zKyvHYltHQWULwAuaJMB/image.png

んー、テンプレートエラー?
HTML部分でエラー?
app-childなんて知らないって??
お、頑張れば読めるぞ!NEW HORIZONレベルの英語だ!
app-childがangularのコンポーネントなら
このモジュールの一部かどうか確かめなさい。

モジュールってなんぞ・・・?

https://www.evernote.com/l/AS0cmfGUlvtNf62a34rtsm-kBmicbLrZmE8B/image.png

実は新たに追加したコンポーネントを使うためには、
モジュールに追加する必要があるんです。

モジュールとは、複数のコンポーネントを束ねる役割をします。
正しくはコンポーネントだけでなく、
パイプやサービス、ディレクティブなどもそうですし、
モジュールの中にモジュールを含めることもできます。
あらゆる部品をパッケージ化する単位という感じ。

そのモジュールというのがここでいうと
app.module.tsです。
とりあえずファイルを開けてみます。

https://www.evernote.com/l/AS1Mhj_XzodGzr8LcsVihUBQK3TWpBqk5F8B/image.png

いろいろ書いてありますが、
要はモジュールに含めるものを定義してます。
内訳はこんな感じ。

https://www.evernote.com/l/AS1-nb7veE9HQZRCAqOxTE3_S106NasCdnIB/image.png

ここの詳しい説明はおいおいします。
というわけで、
これにchildコンポーネントを追加すべく、
次のような実装を加えます。

https://www.evernote.com/l/AS3XIPB1v3lGbYWXPdTrU_MgYJqR6NfvE4QB/image.png

新たにコンポーネントを追加するので、
ファイルを読み込んでdeclarationsに追加するわけです。
これでブラウザを見てみるとー

https://www.evernote.com/l/AS0dkV_Xmd5LS4rcUN7NkOZzi8GaugXLijAB/image.png

いけました!

https://www.evernote.com/l/AS1qtzkXgQlEva6X3jPZN9zYF5T_EPCgZvsB/image.png

こんな感じで、新たに追加したものを使いたい場合は
同一のモジュールに含めてあげることをお忘れなく!

次回はパイプを扱ってみます。
ではでは。

angular2入門【コンポーネント編①】

ゼットンです。

前回はangular2入門【環境構築編】をお送りしました。
今回は【コンポーネント編】です。

前回、Hello worldならぬapp works!という1文が表示できましたが、
正直「へー」って感じだったと思います。

とりあえず下記のようなディレクトリ構成で出力されたかと思います。

https://www.evernote.com/l/AS1umj1FOa9AH4D4uVzUSwDrxUOayd3l_Y8B/image.png

今回はこの自動生成されたソースをいじりながら
angular2のコンポーネントのイメージをつけていきましょう。

https://www.evernote.com/l/AS3aPvVEMP1LQIE4-bZbTXSq5x7mcTREFhoB/image.png

うん、うん。
わかりますよ、妖精さん
まずは最初に表示されるindex.htmlを見てみましょう。

https://www.evernote.com/l/AS3UTWxPOMJG4oMGH6bXvJ0kft8Tz2YcJN8B/image.png

https://www.evernote.com/l/AS12CjXNi2lAlJJUDaTK2yZkbdGz-mn0KIUB/image.png

まあ落ち着いて、セラ。
こういうもんなんです。
さっきから言ってるコンポーネントはこれです。

https://www.evernote.com/l/AS1qM5E2PjxCLYhMYTItA1GChLX5cZUDDQoB/image.png

そう、タグなんです。
コンポーネントとは、独自定義のタグのことです。
独自タグを作り、それらを組み合わせてアプリを作っていくのが
angular2の開発スタイル。
コンポーネント志向ってやつです。

ではではこの<app-root>の中身は
どこで定義しているんでしょう。 ここです。

https://www.evernote.com/l/AS2GlSLbSTdA-bfxxtzzyh0bDXOJhsp3rOsB/image.png

TypeScriptのクラスの中に@Componentって形で
angular2の定義が挟まってます。
中にはタグの名前/HTML参照先/CSS参照先が
記述されています。
下の方では変数titleに文字列を格納してます。

https://www.evernote.com/l/AS34s7oqSF5NzoT7zcEexRe-kBgPJbKEhzoB/image.png

app.component.tsは何も記述されていないのでスルー
app.component.htmlを開けてみます。

https://www.evernote.com/l/AS3lJqb3DoFFG7GLQTKOdtczi3xJLbh9nD4B/image.png

{{ title }}の部分は、 app.component.tsにて宣言した 変数titleを表示しています。

1コンポーネントの中身が別ファイルに分割されると、 どうも見通しが悪いので下記のように書き換えてます。

https://www.evernote.com/l/AS1VK0hKYZNDFaWgxfJYwFCf3bL4EpgPeeYB/image.png

見慣れないうちは不自然極まりないですが、
公式サイトのチュートリアルもこの形でやっているし、
コード量が多くならない限りはこれでいいと思うってます。

とりあえず、今日はここまで(深夜アニメが始めってしまう)。
次回はここに新たなコンポーネントを追加してみます。

ちなみに私は、
これゾンのキャラの中ではとものりが断トツで好き。

https://www.evernote.com/l/AS31ddLQg_1EoKrMtTQSVPIrymRrbMUxbKQB/image.png