Где я должен инициализировать мою FormGroup, находится ли она в компоненте контейнера или компоненте представления? Спасибо - PullRequest
0 голосов
/ 23 апреля 2020

Я использую Angular в своем приложении, и я просто хочу знать, верен ли этот подход, где я инициализирую свою FormGroup в компоненте контейнера и передаю его в качестве реквизита в компонент представления. Спасибо

speech-admin-page.component.ts

import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core';
import { FormControl, FormBuilder, FormGroup } from '@angular/forms';
import { select, Store } from '@ngrx/store';
import { Observable, of } from 'rxjs';
import { SpeechPageAction } from '../../actions';
import { Speech } from 'app/speeches/models';
import * as fromSpeeches from '../../reducers';
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
import { Dictionary, Update } from '@ngrx/entity';
import { first, take, tap } from 'rxjs/operators';

declare var $: any;

@Component({
    selector: 'app-speeches',
    changeDetection: ChangeDetectionStrategy.OnPush,
    templateUrl: './speech-admin-page.component.html',
    styles: ['./speech-admin-page.component.scss']
})
export class SpeechAdminPageComponent implements OnInit {

  date = Date.now();
  private speeches$: Observable<Speech[]>;
  private selectedSpeech$: Observable<Speech>;
  private selectedSpeechId$: Observable<string>;
  private selectedSpeechForm: FormGroup;
  private newSpeechForm: FormGroup;
  private newSpeechToastNotif$: Observable<object>;
  // private showNewSpeechNotif$: Observable<boolean>;


  constructor(
    private afs: AngularFirestore,
    private store: Store<fromSpeeches.State>,
    private formBuilder: FormBuilder) {
    this.speeches$ = store.pipe(select(fromSpeeches.selectAllSpeeches));
    this.selectedSpeech$ = store.pipe(select(fromSpeeches.selectSelectedSpeech));
    this.selectedSpeechId$ = store.pipe(select(fromSpeeches.selectSelectedSpeechId));
  }

  ngOnInit() {
    this.buildForm();
    this.store.dispatch(SpeechPageAction.loadSpeeches());
    this.speeches$.subscribe(speeches => {
      speeches.map((speech, index) => {
        if(index === 0)
          this.store.dispatch(SpeechPageAction.selectSpeech({ id: speech.id }))
      })

      this.selectedSpeech$.subscribe(speech => {
        if(speech){
          this.selectedSpeechForm = new FormGroup({
            'id': new FormControl(speech.id),
            'subject': new FormControl(speech.subject),
            'content': new FormControl(speech.content),
            'author': new FormControl(speech.author),
            'group': new FormControl(speech.group),
            'publishedDate': new FormControl(new Date(speech.publishedDate.toDate())),
          });
        }
      })
    });
  }
}

speech-admin-page.component. html

<div class="wrapper">
    <div class="main-panel w-100">
        <div class="container-fluid">
            <div class="row">
                <div class="col-lg-8 col-md-12 mx-auto">
                    <nav-tab-table
                        [speeches]="speeches$ | async"
                        [selectedSpeech]="selectedSpeech$ | async"
                        [selectedSpeechId]="selectedSpeechId$ | async"
                        [selectedSpeechForm]="selectedSpeechForm"
                        [newSpeechForm]="newSpeechForm"
                        (selectSpeech)="onSelectSpeech($event)"
                        (addSpeech)="onAddSpeech($event)"
                        (updateSpeech)="onUpdateSpeech($event)"
                        (removeSpeech)="onDeleteSpeech($event)"
                        >
                    </nav-tab-table>
                    </div> <!-- end of col -->
            </div> <!-- end of row -->
        </div> <!-- end of container-fluid -->
    </div>
</div>

nav-tab-table .component.ts

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { Speech } from 'app/speeches/models';
import { FormControl, FormGroup, FormBuilder } from '@angular/forms';

@Component({
  selector: 'nav-tab-table',
  templateUrl: './nav-tab-table.component.html',
  styleUrls: ['./nav-tab-table.component.scss']
})
export class NavTabTableComponent implements OnInit{

  @Input() speeches!: Speech[];
  @Input() selectedSpeechId!: string;
  @Input() selectedSpeech!: Speech;
  @Input() selectedSpeechForm: FormGroup;
  @Input() newSpeechForm: FormGroup;
  @Output() selectSpeech = new EventEmitter<string>();
  @Output() addSpeech = new EventEmitter<Speech>();
  @Output() updateSpeech = new EventEmitter<Speech>();
  @Output() removeSpeech = new EventEmitter<Speech>();

  constructor() { }

  ngOnInit() {

  }

  ngOnChanges() {
    console.log(this.selectedSpeechForm)
  }

  onEnterSpeech(e) {
    e.preventDefault();
  }

  onSelectSpeech(id: string) {
    this.selectSpeech.emit(id);
  }

  onSubmit() {
    // TODO: Use EventEmitter with form value
    console.warn(this.selectedSpeechForm.value);
  }

  onSave() {
    console.log(this.selectedSpeechForm.value);
  }

  onAddSpeech(e) {
    this.addSpeech.emit(this.newSpeechForm.value);
  }

  onUpdateSpeech(e) {
    this.updateSpeech.emit(this.selectedSpeechForm.value);
  }

  onDeleteSpeech(e) {
    this.removeSpeech.emit(this.selectedSpeechForm.value);
  }
}

nav-tab-table.component. html

<div class="card">
    <div class="card-header card-header-tabs card-header-primary">
        <div class="nav-tabs-navigation">
            <div class="nav-tabs-wrapper">
                <ul class="nav nav-tabs" data-tabs="tabs">
                    <li class="nav-item">
                        <a mat-button class="nav-link active" href="#profile" data-toggle="tab">
                            <i class="material-icons">description</i> View my Speeches
                            <div class="ripple-container"></div>
                        </a>
                    </li>
                    <li class="nav-item">
                        <a mat-button class="nav-link" href="#messages" data-toggle="tab">
                            <i class="material-icons">note_add</i> Submit a new Speech
                            <div class="ripple-container"></div>
                        </a>
                    </li>
                    <li class="nav-item">
                        <a mat-button class="nav-link" href="#settings" data-toggle="tab">
                            <i class="material-icons">find_in_page</i> Search all Speeches
                            <div class="ripple-container"></div>
                        </a>
                    </li>
                </ul>
            </div>
        </div>
    </div>
    <div class="card-body">
        <div class="tab-content">
            <div class="tab-pane active" id="profile">
                <div class="row">
                    <div class="col-lg-3">
                        <div class="card p-2 custom-height">
                            <button
                                *ngFor="let speech of speeches; index as i"
                                (click)="onSelectSpeech(speech.id)"
                                mat-button 
                                class="text-left btn btn-block"
                                [ngClass]="{'btn-primary': speech.id == selectedSpeechId}">
                                    Speech {{ i + 1 }}
                                    <i *ngIf="speech.id == selectedSpeechId" class="material-icons">play_arrow</i>
                            </button>
                        </div>
                    </div>
                    <div class="col-lg-9">
                        <div class="card p-2">
                            <form [formGroup]="selectedSpeechForm" (ngSubmit)="onSubmit()">
                                <mat-form-field>
                                    <textarea
                                        formControlName="content"
                                        matInput 
                                        rows="5" 
                                        cols="40"
                                        placeholder="Speech Content shown here"></textarea>
                                </mat-form-field> 
                                <div class="row">
                                    <div class="col-lg-3">
                                        <mat-form-field>
                                            <input formControlName="author" matInput type="text" placeholder="Author">
                                        </mat-form-field>
                                    </div>
                                    <div class="col-lg-5">
                                        <mat-form-field>
                                            <input formControlName="subject" matInput type="text" placeholder="Subject Area Keywords">
                                        </mat-form-field>
                                    </div>
                                    <div class="col-lg-4">
                                        <mat-form-field>
                                            <mat-label>Speech Date</mat-label>
                                            <input
                                                formControlName="publishedDate"
                                                matInput 
                                                [matDatepicker]="picker">
                                            <mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
                                            <mat-datepicker #picker></mat-datepicker>
                                        </mat-form-field>
                                    </div>
                                    <div class="col-lg-12 d-flex justify-content-end">
                                        <button (click)="onDeleteSpeech($event)" mat-button class="text-left btn btn-danger">
                                            <i class="material-icons">delete</i>
                                            Delete
                                        </button>
                                        <button 
                                            (click)="onUpdateSpeech($event)"
                                            mat-button class="text-left btn btn-primary ml-2">
                                            <i class="material-icons">save</i>
                                            Save
                                        </button>
                                        <button mat-button class="text-left btn btn-info ml-2">
                                            <i class="material-icons">share</i>
                                            Share
                                        </button>
                                    </div> <!-- end of col -->
                                </div>
                            </form>
                        </div>
                    </div> <!-- end of col -->
                </div> <!-- end of row -->
            </div> <!-- end of tab-pane -->
            <div class="tab-pane" id="messages">
                <form [formGroup]="newSpeechForm" (ngSubmit)="onAddSpeech($event)">
                    <mat-form-field>
                        <input matInput formControlName="subject" type="text" placeholder="Subject Area Keywords">
                    </mat-form-field>
                    <mat-form-field>
                        <textarea 
                            matInput 
                            formControlName="content"
                            rows="5" 
                            cols="40" 
                            placeholder="Speech Content"></textarea>
                    </mat-form-field>
                    <button mat-button class="btn btn-primary float-right">
                        <i class="material-icons">save</i>
                        Save
                    </button>
                </form>
            </div> <!-- end of tab-pane -->
            <div class="tab-pane" id="settings">
                <form class="w-25">
                    <div class="input-group no-border">
                            <input type="text" value="" class="form-control" placeholder="Search...">
                            <button mat-raised-button type="submit" class="btn btn-white btn-round btn-just-icon">
                                    <i class="material-icons">search</i>
                                    <div class="ripple-container"></div>
                            </button>
                    </div>
            </form>
                <table class="table">
                    <thead class=" text-primary">
                        <th>
                                ID
                        </th>
                        <th>
                                Author
                        </th>
                        <th>
                                Subject
                        </th>
                        <th>
                                Content
                        </th>
                        <th>
                                Action
                        </th>
                    </thead>
                    <tbody>
                        <tr *ngFor="let speech of speeches">
                            <td>{{ speech.id }}</td>
                            <td>{{ speech.author }}</td>
                            <td>
                                {{ ( speech.subject.length > 16 ) ? ( speech.subject | slice: 0:16 ) + '...' : ( speech.subject ) }}
                            </td>
                            <td>
                                {{ ( speech.content.length > 25 ) ? ( speech.content | slice: 0:25 ) + '...' : ( speech.content ) }}
                            </td>
                            <td>
                                <button mat-raised-button type="button" matTooltip="View Details" [matTooltipPosition]="'above'" class="btn btn-info btn-link btn-sm btn-just-icon">
                                    <i class="material-icons">visibility</i>
                                </button>
                            </td>
                        </tr>
                    </tbody>
                </table>
            </div>
        </div>
    </div> <!-- end of card-body -->
</div> <!-- end of card -->

1 Ответ

0 голосов
/ 23 апреля 2020

Форма должна быть внутри компонента, который будет ее использовать, то есть в компоненте presentational. Если ваша форма очень сложна с вложенными полями и т.д. c, но если вы хотите сгруппировать поля в компоненте - рассмотрите возможность реализации интерфейса ControlValueAccessor для компонента presentational с подмножеством полей.

...