JULY 2018
VOLUME 33 NUMBER 7
働くプログラマ - MEAN あれこれ: 動的な Angular
によってTed Neward |2018 年 7 月
「MEANers」の皆さん、お帰りなさい。
前回のコラムで"どのようにする平均。リアクティブ プログラミング"(msdn.com/magazine/mt846724)、Angular、フォームを構築し、ユーザー イベントに応答する別の方法が内で作成を提供するの事後対応型フォーム モジュールについて詳しく説明しました。この記事の末尾には、質問をもたらすは。コントロールの非常に大きな数が、または作成されたコントロールが変更する必要がある場合は、下にあるモデル オブジェクトの特性の変化に基づくでしょうか。これは、いずれかのような場合は、率直に言って、Angular を採用する従来の「テンプレート」システムの証明書利用者は不十分です。可能性のあらゆる組み合わせのテンプレートを作成する場合は、非常に長い 1 日になります。
仮定、今のところ、会議講演者、講演、会議の会場、Web サイトを評価する参加者のポーリング システムを構築することを希望を名前にするとします。されるようにする必要がある自体は、会議中もかなり迅速に、可能性のあるを新しい質問を展開することが発生します。つまり、次に、Web ページを求められる質問の種類に基づいてフィールドを生成する方法を理解することと、これらの種類の質問は、外部ソース (JSON サービス、さらに、ファイルなど) から公開します。
マジックではありません。任意の GUI (Web ベースまたはそれ以外の場合) をサポートするシステム (コントロール自体を「新規」できることには) などのランタイムの構造を使用してコントロールの構築での設定では、合理的かつ非常に元に戻せることです。Angular で確実に元に戻せるです。モデル オブジェクトからすべてのフォームと関連付けられている (暗黙的または明示的な) メタデータをそのビルド システムを構築はことができます。
そのためを続行するアンケートなど、一連の「質問」オブジェクトを取得する方法を認識している単純な Angular サービスを構築する場合、関連の Angular フォームできますそれらのオブジェクトの一部またはすべてを実行してフォーム要素の対応するコレクションを構築質問を提示し、どこかのストレージのため、回答をキャプチャします。すべてのキーは、FormGroup と Angular を使用して、実行時にそれらのコントロールを表す FormControls になります。
動的なモデル
すべての質問は、すべての質問とその関連するコントロールのいくつかの一般的な動作は期待 (および必要があります) をキャプチャするのに役立つ基底クラスから始めましょう。そのためのコードは以下のようになります。
export type ControlType = "textbox" | "dropdown";
export abstract class Question {
constructor(public value: string = '',
public key: string = '',
public label: string = '',
public required: boolean = false,
public controlType: ControlType = 'textbox')
{ }
}
この大部分は、ここで、クラスのほとんどは (どのようなパターン チーム場合がありますを呼び出す、DTO、またはデータ転送オブジェクト)、単なるプロパティですが、重要な要素が controlType フィールドになるため、非常に簡単にれます。どのような HTML に対応する記述子がなりますを生成する構成要素。現時点では、すべての 2 つの可能性が: (に拡張可能なテキストの入力を許可) テキスト ボックスまたはドロップダウン (1 つの項目を可能性の境界付けられた範囲から選択)。
同様に明らかな場合は、質問が抽象クラスを作成するここでは、質問の種類ごとに 1 つの派生型を期待どおりです。TextboxQuestion のコードは、次のようになります。
export class TextboxQuestion extends Question {
constructor(value: string = '',
key: string = '',
label: string = '',
required: boolean = false,
public type: string = '') {
super(value, key, label, required, 'textbox');
}
}
このようなコード DropdownQuestion と:
export class DropdownQuestion extends Question {
constructor(value: string = '',
key: string = '',
label: string = '',
required: boolean = false,
public options: {key: string, value: string}[] = [])
{
super(value, key, label, required, 'dropdown');
}
}
各質問は、その親では、基本パラメーターのセットを渡し、1 つをミックスにそれぞれ追加します。TextboxQuestion の場合、パラメーターを追加型テキスト ボックスのパスワードや電子メールのテキスト ボックスであることを示すしたい場合。DropdownQuestion の場合は、ドロップダウンの選択肢として使用するキー/値ペアの配列を追加します。
次に、ただし、ある FormControl および FormGroup オブジェクトにこれらを有効にする方法を把握します。おそらく、方法に応じて Angular は、スタンドアロン サービス、設計について考えている。 が、静的メソッドとして、質問クラスの一部にするほうが効果的です。(これまでに、新しい質問の種類を追加した場合に保持し、すべて同じモジュール内でグループ化を行う方のために、更新する必要があるこのメソッドは)。 コード側から必要な FormControl オブジェクトを作成する非常に簡単ですが、とおりです。
export abstract class Question {
public static toFormGroup(questions: Question[]): FormGroup {
let group: any = {};
questions.forEach(question => {
group[question.key] =
question.required ? new FormControl(question.value, Validators.required)
: new FormControl(question.value);
});
return new FormGroup(group);
}
// ...
}
基本的に、このメソッドは、質問の配列を受け取り、FormGroup オブジェクト内に収まっている FormControl オブジェクトの配列に変換します。この側から唯一の真の質問では、コントロールが必要かどうかがあることを確認しますその他の表示ロジックは、テンプレート内でキャプチャする必要があります。
ダイナミック表示
ここでは関連する Angular UI コンポーネントの検討を開始することも必要基本的に、ポーリングまたはアンケートで構成される 1 つまたは複数の質問のため、作業モデルとしてを使用します。 QuestionnaireComponent がいくつかの QuestionComponents を使用して、各 QuestionComponent が入力として質問オブジェクト。
多少簡単に、上からを起動し、動作を [ダウンしましょうを感じます。最初、オフがある、アンケートを自体で示すように、ここで表示される AppComponent図 1します。
図 1、AppComponent
@Component({
selector: 'app-root',
template: `
<div>
<h2>How was our conference?</h2>
<app-questionnaire [questions]="questions"></app-questionnaire>
</div>
`,
providers: [QuestionService]
})
export class AppComponent {
questions: Question[];
constructor(service: QuestionService) {
this.questions = service.getQuestions();
}
}
このコードは、コンポーネントの完全なシナリオを提供します。だけ、それを使用し、コードは、ライト、シンプルで簡単に Angular 開発者にとって直感的なままになるため、コンポーネントに必要なで、入力を提供する方法を認識しているサービスがあります。
次のように、QuestionnaireComponent を見てみましょう図 2します。
図 2、QuestionnaireComponent
@Component({
selector: 'app-questionnaire',
templateUrl: './questionnaire.component.html'
})
export class QuestionnaireComponent implements OnInit {
@Input() questions: Question[] = [];
form: FormGroup;
payload = '';
ngOnInit() {
this.form = Question.toFormGroup(this.questions);
}
onSubmit() {
this.payload = JSON.stringify(this.form.value);
}
}
ここでも、非常に簡単で単純な方法がいます。QuestionnaireComponent 質問の入力に配列を受け取り、FormGroup を使用して、テンプレートで作成するフォーム照合します。図 3これを示しています。
図 3 の FormGroup でフォームを作成する準備をしています
<div>
<form (ngSubmit)="onSubmit()" [formGroup]="form">
<div *ngFor="let question of questions" class="form-row">
<app-question [question]="question" [form]="form"></app-question>
</div>
<div class="form-row">
<button type="submit" [disabled]="!form.valid">Save</button>
</div>
</form>
<div *ngIf="payload" class="form-row">
<strong>Saved the following values</strong><br>{{payload}}
</div>
</div>
一般に、ペイロードは HTTP 経由でからアップロード Angular サービスでは、おそらく、データベースに格納されるが、スコープ外の例に少し時間が。ここでは、表示するには、データが検証済みになっていること、キャプチャおよび配布の準備を行うことを示すために機能します。
もちろん、私はまだ、フォーム内で個々 の質問の要素を構築して QuestionComponent コードは、ここに表示する分類します。
@Component({
selector: 'app-question',
templateUrl: './question.component.html'
})
export class QuestionComponent {
@Input() question: Question;
@Input() form: FormGroup;
get isValid() { return this.form.controls[this.question.key].valid; }
}
入力が (論理的に) 属する; FormGroup として QuestionComponent 受け取りことに注意してください。(実装については、isValid プロパティ)、FormControl を取得する対象のさまざまな手段を検索しようとしてでしたが、このように動作し、単純なを保つのに役立ちます。
このコンポーネントのテンプレートは、動的なフォームの作成の真価が行われる場所です。質問オブジェクトの controlType に賢く ngSwitch に協力してくれたを構築できる HTML 要素非常に簡単のように図 4します。
図 4 つの HTML 要素の構成
<div [formGroup]="form">
<label [attr.for]="question.key">{{question.label}}</label>
<div [ngSwitch]="question.controlType">
<input *ngSwitchCase="'textbox'" [formControlName]="question.key"
[id]="question.key" [type]="question.type">
<select *ngSwitchCase="'dropdown'" [formControlName]="question.key"
[id]="question.key">
<option *ngFor="let opt of question.options" [value]="opt.key">
{{opt.value}}
</option>
</select>
</div>
<div class="errorMessage" *ngIf="!isValid">{{question.label}} is required</div>
</div>
ご覧のように、こういったいくことが非常に洗練されたです。スイッチは、controlType プロパティをこれは、かどうかに応じてドロップダウン リストまたはテキスト ボックスの種類の質問、ビルド別の HTML。
最後に、いくつかの質問がここでも、通常はそのため、ファイルまたはサーバー側 API などのいくつかの外部リソースからの要求を処理する QuestionService だけ必要があります。示すように、この例では、サービスがメモリから質問をプル図 5します。
図 5 の QuestionService からの質問の取得
@Injectable()
export class QuestionService {
getQuestions() {
return [
new TextboxQuestion('', 'firstName',
'Speaker\'s First name', true),
new DropdownQuestion('', 'enjoyment',
'How much did you enjoy this speaker\'s talk?',
false,
[
{key: 'great', value: 'Great'},
{key: 'good', value: 'Good'},
{key: 'solid', value: 'Solid'},
{key: 'uninspiring', value: 'Uninspiring'},
{key: 'wwyt', value: 'What Were You Thinking?'}
]),
];
}
}
当然ながら、実際のアンケートでは、いくつかの詳細について疑問が浮かぶでしょうが、この例、ポイントを取得します。
まとめ
このようなシステムの任意の並べ替えに関連する問題は、拡張性です。大幅な変更を必要とせずに新しいアンケートを追加できますか。明らかに、キーがあるは、QuestionnaireService-無限の数、カンファレンスの参加者が質問できますアンケートの質問のオブジェクトの配列を別のバックアップを得ることの限りがあります。唯一の制限は、さまざまな質問できる今、複数の選択肢または open ended テキストのいずれかの回答にとらわれることです。
2 番目の質問が発生します。どの程度難しいことでしょうかに関する質問を不連続の数値に評価コントロールなど、システムの新しい種類を追加するにはこれを行うには、新しい質問サブクラス (RatingsQuestion) の作成数値の範囲を使用するには、オンにするテンプレートおよび QuestionComponent テンプレートを変更するための新しい ControlType 列挙値を新しい列挙値をオンにすると、(ただし、なります) に応じて、HTML を表示します。他のすべては変更されませんが、コンポーネント テクノロジの目的は、これは — 新機能を活用することを選択しない限り、クライアントを構造の変更に関係なく保持します。
モ ノ閉じるここに移行しますので、この全体の概念、スピンを提供する angular リーダーが始めされます。ただしはさらに必要なわずかためここでは、次回そのをヒット、Angular のカバレッジをラップする前に経由する必要がありますの。それまでコーディングに励んでください。
Ted Newardはシアトル ポリテクノロジーに関するコンサルタント、講演者、および指導者、エンジニア リングで、開発者リレーションのディレクターとして働いていますSmartsheet.comします。彼は、さまざまな記事、執筆および共同執筆のさまざまな書籍を執筆していて、世界中で講演を行っています。彼の連絡先は、ted@tedneward.com です。また、blogs.tedneward.com にブログを公開しています。
次のテクニカル エキスパート: に協力してくれたGarvice Eakins (Smartsheet)