Detaylı Rehberler
Formlar

Dinamik form'lar oluşturma

Anketler gibi birçok form, biçim ve amaç açısından birbirine çok benzer olabilir. Bu tür formların farklı sürümlerini daha hızlı ve kolay oluşturmak için, iş nesnesi modelini tanımlayan meta verilere dayalı bir dinamik form şablonu oluşturabilirsiniz. Ardından, veri modelindeki değişikliklere göre yeni formları otomatik olarak oluşturmak için şablonu kullanın.

Bu teknik, içeriğinin hızla değişen iş ve düzenleyici gereksinimleri karşılamak için sık sık değişmesi gereken bir form türüne sahip olduğunuzda özellikle kullanışlıdır. Tipik bir kullanım durumu ankettir. Farklı bağlamlarda kullanıcılardan girdi almanız gerekebilir. Kullanıcının gördüğü formların biçimi ve stili sabit kalmalı, ancak sormanız gereken asıl sorular bağlama göre değişir.

Bu eğitimde, temel bir anket sunan dinamik bir form oluşturacaksınız. İş arayan kahramanlar için çevrimiçi bir uygulama oluşturursunuz. Ajans sürekli olarak başvuru sürecini değiştirmektedir, ancak dinamik formu kullanarak uygulama kodunu değiştirmeden anında yeni formlar oluşturabilirsiniz.

Eğitim sizi aşağıdaki adımlardan geçirir:

  1. Bir proje için reaktif formları etkinleştirin.
  2. Form kontrollerini temsil edecek bir veri modeli oluşturun.
  3. Modeli örnek verilerle doldurun.
  4. Dinamik olarak form kontrolleri oluşturacak bir bileşen geliştirin.

Oluşturduğunuz form, kullanıcı deneyimini iyileştirmek için girdi doğrulaması ve stil kullanır. Yalnızca tüm kullanıcı girdisi geçerli olduğunda etkinleştirilen bir Gönder düğmesine sahiptir ve geçersiz girdiyi renk kodlaması ve hata mesajlarıyla işaretler.

Temel sürüm, daha zengin bir soru çeşitliliğini, daha zarif oluşturmayı ve üstün kullanıcı deneyimini desteklemek için geliştirilebilir.

Projeniz için reactive form'ları etkinleştirme

Dinamik formlar reaktif formlara dayanır.

Uygulamaya reaktif form direktiflerine erişim vermek için, @angular/forms paketinden ReactiveFormsModule'ü gerekli bileşenlere içe aktarın.

Form nesne modeli oluşturma

Dinamik bir form, form işlevselliğinin gerektirdiği tüm senaryoları tanımlayabilen bir nesne modeli gerektirir. Örnek kahraman uygulama formu bir dizi sorudur -- yani formdaki her kontrol bir soru sormalı ve bir cevap kabul etmelidir.

Bu tür form için veri modeli bir soruyu temsil etmelidir. Örnek, modeldeki temel nesne olarak soruyu tanımlayan DynamicFormQuestionComponent'i içerir.

Aşağıdaki QuestionBase, formda soruyu ve cevabını temsil edebilecek bir kontrol kümesi için temel sınıftır.

question-base.ts

export class QuestionBase<T> {
  value: T | undefined;
  key: string;
  label: string;
  required: boolean;
  order: number;
  controlType: string;
  type: string;
  options: {key: string; value: string}[];

  constructor(
    options: {
      value?: T;
      key?: string;
      label?: string;
      required?: boolean;
      order?: number;
      controlType?: string;
      type?: string;
      options?: {key: string; value: string}[];
    } = {},
  ) {
    this.value = options.value;
    this.key = options.key || '';
    this.label = options.label || '';
    this.required = !!options.required;
    this.order = options.order === undefined ? 1 : options.order;
    this.controlType = options.controlType || '';
    this.type = options.type || '';
    this.options = options.options || [];
  }
}

Kontrol sınıflarını tanımlama

Bu temelden, örnek farklı kontrol türlerini temsil eden TextboxQuestion ve DropdownQuestion olmak üzere iki yeni sınıf türetir. Bir sonraki adımda form şablonunu oluşturduğunuzda, uygun kontrolleri dinamik olarak oluşturmak için bu belirli soru türlerini örneklersiniz.

TextboxQuestion kontrol türü, formda bir <input> öğesi ile temsil edilir. Bir soru sunar ve kullanıcıların girdi yapmasına olanak tanır. Öğenin type niteliği, options argümanında belirtilen type alanına göre tanımlanır (örneğin text, email, url).

question-textbox.ts

import {QuestionBase} from './question-base';

export class TextboxQuestion extends QuestionBase<string> {
  override controlType = 'textbox';
}

DropdownQuestion kontrol türü, bir seçim kutusunda seçeneklerin bir listesini sunar.

question-dropdown.ts

import {QuestionBase} from './question-base';

export class DropdownQuestion extends QuestionBase<string> {
  override controlType = 'dropdown';
}

Form gruplarını oluşturma

Dinamik bir form, form modeline dayalı olarak gruplandırılmış girdi kontrol kümeleri oluşturmak için bir hizmet kullanır. Aşağıdaki QuestionControlService, soru modelinden meta verileri kullanan bir dizi FormGroup örneği toplar. Varsayılan değerler ve doğrulama kuralları belirleyebilirsiniz.

question-control.service.ts

import {Injectable} from '@angular/core';
import {FormControl, FormGroup, Validators} from '@angular/forms';

import {QuestionBase} from './question-base';

@Injectable()
export class QuestionControlService {
  toFormGroup(questions: QuestionBase<string>[]) {
    const group: any = {};

    questions.forEach((question) => {
      group[question.key] = question.required
        ? new FormControl(question.value || '', Validators.required)
        : new FormControl(question.value || '');
    });
    return new FormGroup(group);
  }
}

Dinamik form içeriklerini oluşturma

Dinamik formun kendisi, sonraki bir adımda eklediğiniz bir kapsayıcı bileşenle temsil edilir. Her soru, DynamicFormQuestionComponent'in bir örneğiyle eşleşen bir <app-question> etiketi ile form bileşeninin şablonunda temsil edilir.

DynamicFormQuestionComponent, veri bağlı soru nesnesindeki değerlere dayalı olarak bireysel bir sorunun ayrıntılarını oluşturmaktan sorumludur. Form, şablon HTML'sini altta yatan kontrol nesnelerine bağlamak için [formGroup] direktifine dayanır. DynamicFormQuestionComponent, soru modelinde tanımlanan kontrollerle doldurarak form grupları oluşturur, görüntüleme ve doğrulama kurallarını belirtir.

DynamicFormQuestionComponent'in amacı, modelinizde tanımlanan soru türlerini sunmaktır. Bu noktada yalnızca iki soru türünüz var ancak çok daha fazlasını hayal edebilirsiniz. Şablondaki @switch bloğu hangi soru türünün görüntüleneceğini belirler. Switch, formControlName ve formGroup seçicilerine sahip direktifleri kullanır. Her iki direktif de ReactiveFormsModule'da tanımlanmıştır.

Veri sağlama

Bireysel bir form oluşturmak için belirli bir soru kümesi sağlamak üzere başka bir hizmete ihtiyaç vardır. Bu alıştırma için, sabit kodlanmış örnek verilerden bu soru dizisini sağlamak üzere QuestionService'i oluşturursunuz. Gerçek dünya uygulamasında, hizmet verileri bir arka uç sisteminden alabilir. Ancak kilit nokta, kahraman iş başvurusu sorularını tamamen QuestionService'ten döndürülen nesneler aracılığıyla kontrol etmenizdir. Gereksinimler değiştikçe anketi sürdürmek için, yalnızca questions dizisinden nesne eklemeniz, güncellemeniz ve kaldırmanız yeterlidir.

QuestionService, input() sorularına bağlı bir dizi biçiminde bir soru kümesi sağlar.

question.service.ts

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

import {DropdownQuestion} from './question-dropdown';
import {QuestionBase} from './question-base';
import {TextboxQuestion} from './question-textbox';
import {of} from 'rxjs';

@Injectable()
export class QuestionService {
  // TODO: get from a remote source of question metadata
  getQuestions() {
    const questions: QuestionBase<string>[] = [
      new DropdownQuestion({
        key: 'favoriteAnimal',
        label: 'Favorite Animal',
        options: [
          {key: 'cat', value: 'Cat'},
          {key: 'dog', value: 'Dog'},
          {key: 'horse', value: 'Horse'},
          {key: 'capybara', value: 'Capybara'},
        ],
        order: 3,
      }),

      new TextboxQuestion({
        key: 'firstName',
        label: 'First name',
        value: 'Alex',
        required: true,
        order: 1,
      }),

      new TextboxQuestion({
        key: 'emailAddress',
        label: 'Email',
        type: 'email',
        order: 2,
      }),
    ];

    return of(questions.sort((a, b) => a.order - b.order));
  }
}

Dinamik form şablonu oluşturma

DynamicFormComponent bileşeni, formun giriş noktası ve ana kapsayıcısıdır ve şablonda <app-dynamic-form> kullanılarak temsil edilir.

DynamicFormComponent bileşeni, her birini DynamicFormQuestionComponent ile eşleşen bir <app-question> öğesine bağlayarak soruların bir listesini sunar.

Formu görüntüleme

Dinamik formun bir örneğini görüntülemek için, AppComponent kabuk şablonu QuestionService tarafından döndürülen questions dizisini form kapsayıcı bileşeni olan <app-dynamic-form>'a iletir.

app.component.ts

import {Component, inject} from '@angular/core';
import {AsyncPipe} from '@angular/common';

import {DynamicFormComponent} from './dynamic-form.component';

import {QuestionService} from './question.service';
import {QuestionBase} from './question-base';
import {Observable} from 'rxjs';

@Component({
  selector: 'app-root',
  template: `
    <div>
      <h2>Job Application for Heroes</h2>
      <app-dynamic-form [questions]="questions$ | async" />
    </div>
  `,
  providers: [QuestionService],
  imports: [AsyncPipe, DynamicFormComponent],
})
export class AppComponent {
  questions$: Observable<QuestionBase<string>[]> = inject(QuestionService).getQuestions();
}

Model ve verinin bu şekilde ayrılması, soru nesne modeliyle uyumlu olduğu sürece, bileşenleri herhangi bir anket türü için yeniden kullanmanıza olanak tanır.

Geçerli verileri sağlama

Form şablonu, belirli sorular hakkında sabit kodlanmış varsayımlar yapmadan formu oluşturmak için meta verilerin dinamik veri bağlamasını kullanır. Hem kontrol meta verilerini hem de doğrulama kriterlerini dinamik olarak ekler.

Geçerli girdi sağlamak için, Save düğmesi form geçerli bir durumda olana kadar devre dışı bırakılır. Form geçerli olduğunda, Save'e tıklayın ve uygulama geçerli form değerlerini JSON olarak oluşturur.

Aşağıdaki şekil son formu gösterir.

Dynamic-Form

Sonraki adımlar