Bagaimana Kami Membuat Komponen UI Taiga Dasar Lebih Fleksibel: Konsep Pengontrol Komponen dalam Sudut

Dalam perjalanan evolusi pustaka komponen UI Taiga kami, kami mulai memperhatikan bahwa beberapa komponen yang lebih kompleks memiliki @Input hanya untuk meneruskan nilainya ke @Input komponen dasar kami yang lain di dalamnya. Terkadang ada sarang seperti itu bahkan dalam tiga lapisan.





Kami melakukannya dengan beberapa arahan rumit yang disebut pengontrol. Mereka benar-benar memecahkan masalah bersarang dan mengurangi beban perpustakaan.





Pada artikel ini, saya akan menunjukkan kepada Anda bagaimana kami telah mengatur sistem pengaturan umum untuk semua bidang masukan berkat konsep ini dan kemampuan DI di Angular.





Textfield di "Taiga" sebelumnya: kasus yang bagus ketika Anda dapat menggunakan pengontrol

Kami memiliki komponen input dasar yang disebut Primitive Textfield.





Komponen ini adalah input asli yang ditata seperti tema kita dengan pembungkusnya. Ini tidak bekerja dengan bentuk Angular dan diperlukan untuk membangun kontrol penuh. 





Versi pertama bidang teks cukup sederhana dan digunakan di beberapa komponen masukan komposit. Namun segera menjadi lebih rumit: fitur baru ditambahkan, dan jumlah @Inputs untuk komponen semakin banyak. 





«» Textfield 17 . :





  • @Input’ , , . , textfield - 17 .





  • @Input’ , . : @Inputs — . 10 , . .





, .





@Input’ , . , , : ( ).





@Input’ , . , . - :





@Directive({
   selector: '[tuiHintContent]'
})
export class TuiHintControllerDirective {
   @Input('tuiHintContent')
   content: PolymorpheusContent = ’’;
 
   @Input('tuiHintDirection')
   direction: TuiDirection = 'bottom-left';
 
   @Input('tuiHintMode')
   mode: TuiHintMode | null = null;
}
      
      



— @Input’ , . “tuiHintContent”, .





. DI . , .





@Input’ OnPush-, @Input’. , , @Input . Controller, :





export abstract class Controller implements OnChanges {
   readonly change$ = new Subject<void>();
 
   ngOnChanges() {
       this.change$.next();
   }
}
      
      



ngOnChanges, . :





@Directive({
   selector: '[tuiHintContent]'
 })
export class TuiHintControllerDirective extends Controller {
    // ...
}

      
      



, change$ . — ChangeDetectorRef, markForCheck change$. , :





constructor(
  @Inject(ChangeDetectorRef) private readonly changeDetectorRef: ChangeDetectorRef,
  @Optional()
  @Inject(TuiHintControllerDirective)
  readonly hintController: TuiHintControllerDirective | null,
) {
  if (!hintController) {
    return;
  }

  hintController.change$.pipe(takeUntil(this.destroy$)).subscribe(() => {
    changeDetectorRef.markForCheck();
  });
}
      
      



. — .





, “tuiHintContent” textfield .





: - @Input’ . .





, : , .





, null, DI- Angular:





constructor(
  @Inject(TUI_HINT_WATCHED_CONTROLLER)
  readonly hintController: TuiHintControllerDirective,
) {}
      
      



. TUI_HINT_WATCHED_CONTROLLER :





export const TUI_HINT_WATCHED_CONTROLLER = new InjectionToken('watched hint controller');
 
export const HINT_CONTROLLER_PROVIDER: Provider = [
   TuiDestroyService,
   {
       provide: TUI_HINT_WATCHED_CONTROLLER,
       deps: [[new Optional(), TuiHintControllerDirective], ChangeDetectorRef, TuiDestroyService],
       useFactory: hintWatchedControllerFactory,
   },
];
 
export function hintWatchedControllerFactory(
   controller: TuiHintControllerDirective | null,
   changeDetectorRef: ChangeDetectorRef,
   destroy$: Observable<void>,
): Controller {
  if (!controller) {
     return new TuiHintControllerDirective();
  }
 
   controller.change$.pipe(takeUntil(destroy$)).subscribe(() => {
      changeDetectorRef.markForCheck();
   });
 
   return controller;
}
      
      



, HINT_CONTROLLER_PROVIDER. “providers” , deps ChangeDetectorRef TuiDestroyService. , ngOnDestroy , ( , ).





:





@Component({
   //...
   providers: [HINT_CONTROLLER_PROVIDER],
})
export class TuiPrimitiveTextfieldComponent {
   constructor(
       //...
       @Inject(TUI_HINT_WATCHED_CONTROLLER)
       readonly hintController: TuiHintControllerDirective,
   ) {}
}
      
      



, . @Input’ .





: DI , .





: hintWatchedControllerFactory , . , .





?

. @Input’ , . : , — , . , . DI , .





-, , . — .





DI , , , . , , DI, API.








All Articles