Angularでポプテピピックをしてみた
前提
元ネタに便乗(https://renidentia991.bitbucket.io/pptp.html)
して、同じものを勉強中のAngular,RxJSで作成してみた。
要件
- ボタンを押すと、ポ,プ,テ,ピピックのいずれかが一定時間ごとに選択される
- ↑を末尾に追加した文字列を画面に表示
- 表示文字列の末尾が'ポプテピピック'になるとAAを表示し、文字列の追加をやめる
作っていく
方針
方針
イベントを契機に、一定時間ごとに処理が走るのでRxJSを使うとうまく書けそう
→ Angularで書く
準備
angular-cliで雛形を作成。
cd work
ng new popTeamEpic
cd popTeamEpic
動作確認をする。
ng serve
localhost:4200
にアクセスし、デフォルトページが表示されることを確認する。
htmlの準備
app/src/app.component.html
に書いていく。
<h1>
「ポ」「プ」「テ」「ピピック」をランダムに出力して「ポプテピピック」が
完成したら竹●房を破壊するAngular
</h1>
<button
(click)="start()"
>クリックしてね
</button>
<p>{{displayString}}</p>
<div *ngIf="isPopTeamEpic(this.displayString,this.targetString)">
<p
style="font-family:'MS Pゴシック',sans-serif;"
>
AAは省略
</p>
</div>
クリックしてね
ボタンを押下後、start()
によって文字の表示が始まる。
コンポーネントに処理を書いていく
必要な定数と変数の準備
import { Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent{
outputStrings:Array<string> = ['ポ','プ','テ','ピピック'];
targetString:string = 'ポプテピピック';
displayString:string='';
popTeamEpicObservable:Observable<string> = new Observable();
}
各変数の意味は省略。
Observableの設定
Observable
は簡単に表すと、何かしらを契機として値をObserver
に流し始めるオブジェクト。
今回はpopTeamEpicObservable
にポ,プ,テ,ピピックを流す設定をする。
import { OnInit,Component } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/interval';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/takeWhile';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
outputStrings:Array<string> = ['ポ','プ','テ','ピピック'];
targetString:string = 'ポプテピピック';
displayString:string='';
popTeamEpicObservable:Observable<string> = new Observable();
ngOnInit():void{
// 一定期間ごとに文字列をstreamするObservableを設定
this.popTeamEpicObservable = Observable
.interval(100) // 一定時間(ms)ごとに流す
.map(
()=>this.getPopTeamEpic(this.outputStrings)
) //outputStringのいずれか一つを流す
.takeWhile(
(str)=> !this.isPopTeamEpic(this.displayString
,this.targetString)
); //表示文字列の末尾が'ポプテピピック'になるまで
}
// strArray(ポ,プ,テ,ピピック)のいずれかの文字列を返す関数
private getPopTeamEpic(strArray:Array<string>):string{
return strArray[
Math.floor(Math.random()*(strArray.length))
];
}
// 表示文字列の末尾がポ,プ,テ,ピピックかどうか判定する関数
public isPopTeamEpic(str:string,targetString:string):boolean{
return str.endsWith(targetString);
}
Observable
はsubscribe()
されると処理が実行されて値が下流に流されるが、初期化処理ではまだObserver
がsubscribe()
しないので値が流れない。
ここではOperators
によって流す値や周期、条件の設定をしている。
今回利用したOperators
は下記の通り。
Operator名 | 処理 |
---|---|
interval | 一定時間ごとに値を流す。 今回は100msで設定。 |
map | 流れてきた値を加工する。今回は値を加工せず, ポ,プ,テ,ピピックのいずれかを流すように設定。 |
takeWhile | 条件を満たす間、値を流す。今回は、表示文字列の末尾がポプテピピックでないことを条件に設定。 |
まとめると、popTeamEpicObservable
は100msごとにポ,プ,テ,ピピックのいずれかを流し、表示文字列の末尾がポプテピピックになったら完了
というObservable
になる。
この段階ではまだObserver
によってsubscribe()
されていないため、文字列は表示され始めない。
次に、流された後の処理、つまりObserver
の処理を追加する。
Observerの設定
前項で設定したpopTeamEpicObservable
の値を受け取るために、start()
関数を作成してObserver
を設定する。
start():void{
// ポ,プ,テ,ピピックが流れ始める
this.popTeamEpicObservable
.subscribe(
// onNext() 表示文字列にポ,プ,テ,ピピックを追加
(str)=> this.displayString+= str,
// onError()
(err)=> console.log(err),
// onComplete()
()=> console.log('complete')
);
}
Observer
の持つsubscribe()
メソッドは3つの関数を設定できる。
関数 | 処理 |
---|---|
onNext() |
Observable から正常に値が流れてきた場合の処理 |
onError() |
Observable が途中でエラーとなった場合の処理 |
onComplete() |
Observable が完了した後の処理 |
Observable
が値を流す時点で既に文字を追加する周期や条件が設定されているので、ここではonNext()
に文字列の結合処理を書くだけで良い。
また、表示文字列の末尾がポプテピピック
となった場合はpopTeamEpicObservable
が完了するので,onComplete()
が実行され文字列の結合が終わる。
出来上がったもの
感想
RxJSを使うとif文,for文も使わずに書くことが出来る。
条件分岐が増えると可読性、保守性が下がってつらいので、全く使わずに実装できるのはとても良い。
とっつきにくいように見えるが使いこなせると強力な武器になると思うので、積極的に勉強していきたい。
参考
Author And Source
この問題について(Angularでポプテピピックをしてみた), 我々は、より多くの情報をここで見つけました https://qiita.com/lilik2229/items/f6221989e1c5f9a16b36著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .