今日も見に来てくださってありがとうございます。石川さんです。
先日に引き続き、Angularを勉強しています。今回はリアクティブフォームを使って、サンプルプログラムを作ってみました。
出来上がりイメージ
今回は、たまたまニュートン-ラフソン法について質問があったので、Angularで実装してみました。こんな感じになります。ルートを求めたい値「k」を入力して、Calcボタンをクリックすると、漸化式を繰り返します。二乗した結果が「k」との誤差0.01未満になったら終了します。

今回も、statsblitz.comを利用してみました。作業中に、デフォルトで用意されているコンポーネントの「hello.component.ts」を削除してみたところ、以下のエラーがでました。しばらく解決できなくて、何かの設定があるのかと、ウロウロしてしまったので、回避策をメモしておきます。
Error in src/app/hello.component.ts (1:1) File '/~/src/app/hello.component.ngtypecheck.ts' not found.
何のことはありません、おかしな状態になっているだけ、ということのようでした。画面のプロジェクトエクスプローラーの左下の「DEPENDENCIES」をポイントすると、くるりとなった矢印が登場するので、そちらをクリックしたところ、しばらく待って、エラーが消えました。

ソースコード
ソースコードは以下のとおりです。
まずは、コンポーネントのスクリプトです。リアクティブフォームのポイントは「FormGroup」ですね。TypeScript側で「myGroup」として定義しています。また、今回はFormBuilderを使って「k」を定義しました。また、Validatorsを使って、正の数をチェックするようにしました。
onSubmit()呼び出し時、漸化式で計算を実行して、二乗した結果がkに近づいて差が0.01を下回ったところで処理を完了します。
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
@Component({
selector: 'app-x2',
templateUrl: './x2.component.html',
styleUrls: ['./x2.component.css'],
})
export class X2Component implements OnInit {
myGroup: FormGroup;
results: string[];
guess: number;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.myGroup = this.fb.group({
k: [24, Validators.min(0)],
});
}
get k() { return this.myGroup.get('k'); }
onSubmit() {
console.log('Executed!')
this.results = [];
let k: number = this.k.value;
let epsilon: number = 0.01;
let guess: number = k / 2;
let newGuess: number;
while (Math.abs(guess * guess - k) >= epsilon) {
newGuess = guess - (guess ** 2 - k) / (2 * guess);
if (this.results.length == 0) {
this.results.push(guess.toString() + ' => ' + newGuess.toString());
} else {
this.results.push(' => ' + newGuess.toString());
}
guess = newGuess;
}
this.guess = guess;
}
}
そして、コンポーネントのHTMLファイルです。
<p>
ニュートン-ラフソン法でkの根を求めます。
</p>
<p>
f(x) = x<sup>2</sup> - k<br>
x<sub>n + 1</sub> = x<sub>n</sub> - f(x) / f'(x) = x<sub>n</sub> - (x<sub>n</sub><sup>2</sup> - k)/2x<sub>n</sub>
</p>
<form [formGroup]="myGroup" (submit)="onSubmit()">
<table>
<tr>
<th>k</th>
<td><input type="number" formControlName="k"></td>
</tr>
<tr>
<th></th>
<td *ngIf="k.invalid" [style.color]="'red'">正の数を入力してください。</td>
</tr>
<tr>
<th></th>
<td>
<input type="submit" value="Calc" [disabled]="myGroup.invalid">
</td>
</tr>
</table>
</form>
<ul>
<li>まず、guess = k / 2 = {{k.value}} / 2 = {{k.value / 2}} とします。<br>guess - (guess<sup>2</sup> - {{k.value}})/ (2 × guess)がより近い値になるので、計算結果の誤差が0.01になるまで繰り返します。<br>
<p *ngIf="!results">Calcを押して続行します。</p></li>
<li *ngFor="let ans of results">{{ans}}</li>
</ul>
<p *ngIf="guess">{{guess}} * {{guess}} = {{guess * guess}}</p>
WordPressへの組み込み
stackblitz.comを見ていると、「Share」メニューがあったので、クリックして見ると、「Embed」タブが出てきましたので、WordPressに組み込めるのではないか、と、調べて組み込んでみました。
組み込みブロックはあるのですが、stackblitz.com用のものがなく、調べているとここに書いてありました。iframeタグを使って、ということだったので、実験してみましたところ、以下のとおり、実行できました!
ただ、編集のプレビュー画面では「Calc」ボタンは動きませんでした。iframeではsubmitが無効になっているようです。ただ、確認画面では動作しました。こちらの原因はまた機会があったら調べてみます。公開された後に実行できるかどうかわかりませんので、stackblitz.comのソースコードはこちら、実行結果はこちらです。
まとめ
Angularのリアクティブフォームを使って、ページを作ってみました。

