Angular2/4にてngSwitchを使ってtemplateの一部切り替えを行う
Angular2/4にてngSwitchを使ってtemplateの切り替えを行う
「routerを使う程ではないけど、templateを部分的に書き換えたいな〜」と思ったので、
ngSwitchを使用してtemplateの部分的な切り替えを行おうと思います。
0. 準備
新規プロジェクトを作成し、サーバをスタートさせます。
ng new ng-switch ng serve
1. app.component.htmlの修正
<!-- app.component.html --> <button (click)="onClick()">おしてね</button> <div [ngSwitch]="templateFlg"> <!-- 重要 --> <div *ngSwitchCase="true"> <!-- 重要 --> <img style="display: inline;" src="https://pbs.twimg.com/profile_images/442329275769683968/gvLogHdH.jpeg" width="250px" height="250px" > <div style="display: inline;">(・(ェ)・)</div> </div> <div *ngSwitchCase="false"> <!-- 重要 --> <img style="display: inline;" src="https://pbs.twimg.com/profile_images/795060602309726208/WAKx1L5U.jpg" width="250px" height="250px" > <div style="display: inline;">(ΘェΘ)</div> </div> </div>
templateの解説
<div [ngSwitch]="templateFlg"> <div *ngSwitchCase="true"> <!-- templateFlg == true の場合に表示されるtemplate --> </div> <div *ngSwitchCase="false"> <!-- templateFlg == false の場合に表示されるtemplate --> </div> </div>
ngSwitchには、出し分けするために用意した変数を代入します。
今回の場合はtemplateFlgという変数を用います。
それぞれのtemplateには*ngSwitchCaseを使って、
どの条件のときにtemplateを表示するかを記載します。
2. AppComponentの修正
import { Component } from '@angular/core'; import { NgSwitch } from '@angular/common'; // 追記 @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) export class AppComponent { /** ここから */ private templateFlg = true; onClick() { this.templateFlg = !this.templateFlg; } /** ここまで追記 */ }
結果
Angular2/4のLifecycle Hooksを理解する(ngOnInit編)
Angular2/4のLifecycle Hooksを理解する
Angular2/4のLifecycle Hooksのうち、ngOnInitについて簡単な実験をして、
どのタイミングでngOnInitが発火するのか確かめてみることにします。
前提
以下のような親子関係があるとします。
親Componentから子Componentへ、parentValueという値が渡されているとしましょう。
0. プロジェクトを立ち上げて、必要なComponentを生成する
ng new lifecycle-oninit ng g component child
1. templateファイルを以下のように修正
<!-- app.component.html -> <app-child [parentValue]="parentValue"></app-child>
親ComponentであるAppComponentから、parentValueを受け取るようにします。
2. ChildComponentにInputを追記
/** child/child.component.ts */ import { Component, Input, // 追記 OnInit // 追記 } from '@angular/core'; export class ChildComponent implements OnInit // 追記 { @Input() parentValue; // 追記 /** ここから */ constructor() { console.log(this.parentValue); console.log("@@@constructor"); } ngOnInit() { console.log(this.parentValue); console.info("@@@ngOnInit"); } /** ここまで追記 */ }
親からparentValueを受け取れるように、@Input()を追加します。
3. AppComponentにparentValueを追記
/** app.component.ts */ export class AppComponent { public parentValue = '親の値だよ'; }
ログをみてみる
ログを見てみると、
constructor → ngOnInit
の順で呼ばれていることがわかります。
また、ChildComponentが生成された時点(constructorが呼ばれた時点)では、
親からのInputをまだ受け取っていないことがわかります。
ngOnInitが実行された時点では、親からのInputを受け取っています。
つまり、ngOnInitが実行されるタイミングは、
Inputを受け取ったあと
ということになります。
Angular公式ドキュメントでは
Use ngOnInit() for two main reasons: 1. To perform complex initializations shortly after construction. 2. To set up the component after Angular sets the input properties.
上にあるように、
constructionの後に実行される「複雑な初期化」を行うときや、
inputプロパティがセットされた後にcomponentをset upする際に使われるようです。
rake aborted! Gem::LoadError: You have already activated rake *.*.*, but your Gemfile requires rake **.**.**. の解決方法
rakeコマンドを実行したときに時々起こる、rake aborted! の解決方法
結論。
rake ***
ではなく、
bundle exec rake ***
を使いましょう。
解説
まずはエラー文を確認
今回のエラー文を見てみましょう。
Gem::LoadError: You have already activated rake 12.0.0, but your Gemfile requires rake 11.2.2
この場合、
今使っているrakeコマンドのバージョンは12.0.0ですが、
Gemfileでは11.2.2のバージョンが指定されてますよ。
と伝えてくれています。
実は今回の場合、
rake ***
で実行された場合は12.0.0のバージョンが使われます。
bundle exec rake ***
で実行した場合は11.2.2のバージョンが使われます。
そしてこの場合はエラーが起きません。
なぜそういうことが起こるのか
rake ***
で実行した場合と、
bundle exec rake ***
で実行した場合とでは、 参照しているrakeが異なるからです。
それぞれどのrakeを参照しているのか
まずは
rake ***
がどのrakeを参照しているのか調べてみましょう。
gem environment
とすると、 色々出てくるのですが、
- GEM PATHS: - /home/vagrant/.rbenv/versions/2.3.0/lib/ruby/gems/2.3.0 - /home/vagrant/.gem/ruby/2.3.0
こちらのGEM PATHSにアクセスし、フォルダ内に入っているものをみてみましょう。
大量のgemが見つかりました。
これらは、今まで
bundle install
してinstallしてきたgemたちです。バージョン違いのgemがいっぱいあって恐ろしいですね。
rakeはいくつあるのか
ls | grep rake
をすると、
以上の3つのrakeが見つかりました。
rake *** を実行すると
この中の最新バージョンである12.0.0が実行されます。
なお、
rake -V
をすると、installされている最新バージョンが確認できます。
bundle exec rake *** を実行すると
「プロジェクトディレクトリ下のGemfile.lockに記載されているrakeのバージョン」が使用されます。
今回の場合は11.2.2ですね。
なお、
bundle exec rake --version
をすると、使用されるrakeのバージョンが確認できます。
解決策
プロジェクトで使っているrakeのバージョンと、異なるバージョンのrakeを使おうとするととエラーが起こるので、
基本的に
bundle exec rake ***
を使用するようにしましょう。
その他の解決策
gem install時にbundle install をするのではなく、
bundle install --path vendor/bundle
として、
gemはプロジェクト毎に管理しましょう(推奨)
こうすると、vendor/bundle内でgemが管理できるので、
複数のバージョンのgemが混在することがなくなります。
参考: http://dev.classmethod.jp/server-side/language/bundler-gem-management/
あなたのダイエットはなぜ続かないのか。行動心理学から考えてみる
ダイエットは本当につづかないのか?
ダイエットって、続かないですよね。
会社帰りにラーメン食べちゃいますよね。
ジム契約してもなんだかんだで行かなくなっちゃいますよね。
そんな続かないダイエットについて、
どうやったら続くのか
を行動心理学から紐解いてみました。
ちなみに行動心理学のお陰で、ダイエットが続くようになりました。
今のところ2ヶ月で4キロほどおちてきています。目指せ学生時代の体重。
強化と弱化
行動心理学で、強化・弱化という言葉があります。
強化
強化とは、「行動が繰り返されるようになる」ことを指します。
弱化
弱化とは、「行動がされなくなっていく」ことを指します。
今回の目的
つまり今回の目的は、
ジムへ行くという行動を強化
ラーメン食べるという行動を弱化
ということになります。
ジムへ行く行動を強化するには
まず強化には以下の2種類があることを知っておきましょう。
- 好子出現の強化
このように、
行動の結果、自分にとって好ましい状況(好子)が出現すると、
その行動を繰り返すようになります。これを「好子出現の強化」と言います。
- 嫌子消失の強化
逆に行動の結果、自分にとって好ましくない状況(嫌子)が消失すると、
その行動を繰り返すようになります。これを「嫌子消失の強化」と言います。
つまり、この法則を満たすようにすれば、
ジムへ行くという行動が強化されることになります。
みんなも考えてみよう(棒読み)
ラーメン食べるという行動を弱化するには
まず、弱化には以下の2つがあることを知っておきましょう。
- 好子消滅の弱化
まあこの例はあまり良くないですね。
寂しい→浮気する→寂しくない
で「好子出現による強化」のパターンもよくあります。今回は気にしないことにします。
- 嫌子出現の弱化
これは説明いらないかな。
つまり、この法則を満たすようにすれば、
ラーメン食べるという行動が弱化されることになります。
後はもう簡単ですね。
僕はどうしたか
- 美人インストラクターのいるジムに通った
- 近所にある、食べると絶対に腹をこわすラーメン屋に通い続けた(弱化されていった)
以上です。
向き不向きがあるので自分にあった方法を考えてみましょう。
試行錯誤です。
補足
ラーメンで腹を壊し続けたせいで体重が減ってる疑惑。
Angular4にて、サービスを介してコンポーネントからコンポーネントへ値を送る
コンポーネントから別のコンポーネントに値を送る
親子関係があるときは、@Input()を使用することにより親から子へ値を送りました。
今回、あるコンポーネントから親子関係にないコンポーネントへ、
サービスを介して値を送る実装をしてみたいと思います。
- コンポーネントから別のコンポーネントに値を送る
- 解説
- 0. 準備
- 1. componentA, componentB, SendValueServiceを作成
- 2. SendValueServiceにてSubjectを読み込む
- 3. SendValueServiceにprivateの口を追加
- 4. SendValueServiceにpubilcの耳を追加
- 5. app.moduleににSendValueServiceをDIする
- 6. compBのコンストラクタにSendValueServiceを記述
- 7. pubilcの耳を澄まさせる(subscribe)
- 8. SendValueServiceに喋りを実行するメソッドを追加
- 9. compAのコンストラクタにSendValueServiceを記述し、喋らせるメソッドを追加
- 10. componentAのtemplateにボタンを追加
- 結果
解説
具体的な手順に入る前に、大体の流れを確かめておきましょう。
今回やりたいことを図にすると、こんな感じになります。
Serviceを介して、ComponentAからComponentBへMessageを送る感じです。
これを実現するために、まずServiceクラス内に「privateの口」「publicの耳」を用意します。
次に、ComponentBにpublicの耳を配置します。
この時、耳を澄ませておくことが重要です(subscribe)
これで準備が整いました。
まず、ComponentAがServiceに以下のように依頼します。
次に、Serviceがこんにちは!と叫びます。
そうすると、耳を澄ませていたComponentBに聞こえます。
なにいってんだこいつ、という感じだと思いますので、
実際にコードを見て確認してみましょう。
0. 準備
新規プロジェクトを作成し、サーバをスタートさせます。
ng new send-value ng serve
1. componentA, componentB, SendValueServiceを作成
ng g component comp-a ng g component comp-b ng g service send-value
2. SendValueServiceにてSubjectを読み込む
// send-value.service.ts import { Subject } from 'rxjs/Subject';
3. SendValueServiceにprivateの口を追加
// send-value.service.ts private toCompBDataSource = new Subject<string>();
4. SendValueServiceにpubilcの耳を追加
// send-value.service.ts public toCompBData$ = this.toCompBDataSource.asObservable();
5. app.moduleににSendValueServiceをDIする
// app.module.ts import { SendValueService } from './send-value.service'; // 追加 @NgModule({ providers: [SendValueService], // 追加 })
SendValueServiceをDIするのはapp.moduleのみです。
compA, compBにもDIしてしまうと、
3つの別々のSendValueServiceインスタンスが出来てしまうので、うまく動きません。
サービスを使ってコンポーネント間で値のやり取りをするときは、
「同一のServiceインスタンス」を介して値のやり取りができるように注意しましょう。
今回はmoduleにDIしていますが、2つのコンポーネントが同一の親を保つ場合は、
その親にDIしてもOKです。
6. compBのコンストラクタにSendValueServiceを記述
// comp-b.component.ts import { SendValueService } from '../send-value.service'; // 追加 export class CompBComponent implements OnInit { constructor( private sendValueService :SendValueService // 追加 ) { } ngOnInit() { } }
7. pubilcの耳を澄まさせる(subscribe)
// comp-b.component.ts import { Subscription } from 'rxjs/Subscription'; // 追加 export class CompBComponent implements OnInit { private subscription: Subscription; // 追加 constructor( private sendValueService :SendValueService ) { } ngOnInit() { /** ここから */ this.subscription = this.dataService.toCompBData$.subscribe( msg => { console.log('compBは' + msg + 'をうけとりました'); }); } /** ここまで追加 */ }
8. SendValueServiceに喋りを実行するメソッドを追加
// send-value.service.ts public sendMessageToCompB(msg) { this.toCompBDataSource.next(msg); // 喋る }
9. compAのコンストラクタにSendValueServiceを記述し、喋らせるメソッドを追加
// comp-a.component.ts import { SendValueService } from '../send-value.service'; export class CompAComponent implements OnInit { constructor( private sendValueService :SendValueService // 追加 ) { } /** ここから */ onClick() :void { this.sendValueService.sendMessageToCompB('こんにちは!'); } /** ここまで追加 */ }
10. componentAのtemplateにボタンを追加
// comp-a.component.html <button (click)="onClick()">クリックしてね</button>
結果
パティシエが教えるgithub flowによるチーム開発
パティシエが教えるgithub flowによるチーム開発
※当方バックエンドエンジニアです(not パティシエ)
業務系の会社で働く傍ら、プログラミングスクールにて主に未経験の方にプログラミングを教えております。
この間、github flowによるチーム開発について説明したのですが、
リポジトリを「ケーキ」にたとえて説明したところなかなか評判が良かったので、
記事にしてみようと思います。
1. パティシエ長が管理するmasterケーキをcloneします
パティシエ長が、最終的にお客さんに売りに出すケーキである「masterケーキ」を管理してます。
ますはそのmasterケーキを自分の手元に持ってきます(git clone)
2. 自分がいじるケーキをつくります
今、手元には複製されたmasterケーキがあります。
シェフ長から、「Aさんはケーキにいちごを乗せてくれ」と頼まれたとします(issue)。
masterケーキをそのまま残したまま、
git checkout -b issue#ichigo
として、
いちごを乗せる作業を行うための、自分だけがいじるケーキを作ります。
他の3人についても同様です。
3. ケーキをいじります
それぞれのケーキをいじります。
Aさんはケーキにいちごを乗せ、
Bさんはりんごを乗せ、
Cさんはパイナップルを乗せます。
(どんなケーキだ。。。)
4. できあがったケーキをパティシエ長に提出
git push origin issue#ichigo:issue#ichigo
をして、パティシエ長にいちごが乗ったケーキを提出します。
この時、githubの機能である「pullリクエスト」を一緒に行います。
Bさん、Cさんについても同じです。
5. パティシエ長がそれぞれのケーキをチェック
パティシエ長が、提出されたケーキをチェックします。
変な位置に果物が載ってないか、果物が腐ってないかなど、
要件を満たしているか・バグがないコードなのかどうかをチェックします。
6. パティシエ長がマージ
提出されたケーキが問題ないようであれば、
それぞれのケーキのmasterとの差分を取り込みます。
今回で言えば、
いちご、りんご、パイナップルがmasterケーキの上に乗ることになります。
これが「マージ」と呼ばれる作業に当たります。
マージする際にいちごとりんごが同じ位置に載ってしまった場合は、
「コンフリクト」と言って、
パティシエ長が頑張って修正したり、AさんやBさんに修正依頼を出したりしてうまく調整します。
これを繰り返して、ちょっとずつmasterケーキを充実させていくことがシステム開発になります。
うまくissueを割り振らないと、マージするときに大変なので注意しなくてはなりません。
Angular4からgoogle mapを操作する「AGM (angular-google-maps)」を使ってmapを表示。
Angular4を使ってgoogle mapを表示する
「google map上でクリックしたときにマーカをプロットし、その位置情報をAjaxで投げてDB上に保存する」ということがしたくなりました。
google map上での操作については「Maps JavaScript API」を使用すればできるのですが、 生jsで書くとマーカや情報ウィンドウの管理が煩雑になりそうです。
そこで、「AGM (angular-google-maps)」というmoduleを使うことにしました。
今回はmapを表示させるところまでやってみようと思います。
0. 準備
新規プロジェクトを作成し、サーバをスタートさせます。
ng new angular-google-maps ng serve
1. angular-google-mapsのパッケージをinstall
npm install --save-dev @agm/core
moduleのgithubはこちら。 https://github.com/SebastianM/angular-google-maps
2. 必要なmoduleを読み込む
// app.module.ts import { AgmCoreModule, GoogleMapsAPIWrapper } from '@agm/core';
3. @NgModuleのimportに、読み込んだModuleを追加
// app.module.ts @NgModule({ // ... imports: [ AgmCoreModule.forRoot({ apiKey: 'googleから取得したapi key' }), ] // ... });
4. app.component.htmlに、mapを読み込むためのdirectiveを記述
<agm-map [latitude]="lat" [longitude]="lng" [zoom]="zoom" > </agm-map>
5. app.component.tsに、mapの初期設定(緯度/経度等)を記述
// app.component.ts export class AppComponent { lat: number = 35.681167; lng: number = 139.767052; zoom: number = 16; }
6. app.component.cssに、mapの高さを記述(忘れがち)
// app.component.css agm-map { height: 600px; }
これを書かないとmapが表示されません(どハマリした)。
結果