0
votes

Rough Design

I'm relatively new to Angular and I'm looking to achieve the above with reactive forms. I think I'm getting confused between component design and reactive form patterns.

Questions

  1. The first time we load the parent component, with url params, it will pass the value to the child component and the search text box will have the correct value. If I click back on the browser and the parent updates it's searchTerm, which is passed to the child component again, it will never update the search text box as child.ngOnInit() will not execute again.

  2. Is this even a valid design having the formGroup declared in the child component? Most examples I've seen have a formGroup declared in the parent and then include a child component which then has 1 or many formControls....but doesn't that mean that now any other component that wants to include my child component must now declare a formGroup, the child component would seem less independent.

Parent View

<searchBox (search)="onSearchTextEntered($event)" [searchText]="this.searchText"></searchBox>

Parent Component

  ngOnInit() {
     
     /* 
        1) check url params, execute search, set searchText value that is passed to childComponent
        so it can populate searchBox text 
        
        2) Subscribe to NavigateEnd event of router to catch back/fwd browser click, execute search, set searchText value that is passed to childComponent
        so it can populate searchBox text
     */
  }

Child View

<input type="text" [formControl]="searchTerm">

Child Component

@Input() searchText: string;
@Output() search: EventEmitter<string> = new EventEmitter();
searchSection = new FormGroup({
    searchTerm: new FormControl()

ngOnInit() {
this.searchSection.get('searchTerm').setValue(this.searchText);
}
...
3

3 Answers

0
votes

Use @Input with setter function as ngOnInit will execute only once when component loaded.

//Parent component
ngOnInit() {
 this.route.queryParamMap.subscribe(queryParams => {
  this.searchText = queryParams.searchText;
 })
}

<searchBox (search)="onSearchTextEntered($event)" [searchText]="searchText"></searchBox>
//You don't even need `this` keyword in template
//Child component
@Input() set searchText(value: string) {
 //This setter function will execute whenever parent input `searchText` is changed.
 console.log(value); //New value from parent
 this.searchSection.get('searchTerm').setValue(value);
}
1
votes

I'ts totally valid to use formGroup in the child component.

    1) check url params, execute search, set searchText value that is passed to childComponent so it can populate searchBox text 

For this you would probably need to create subject and then subscribe in the template like so

<searchBox (search)="onSearchTextEntered($event)" [searchText]="subjectRoutes | async"></searchBox>

In this case you need to update this.searchSection.get('searchTerm').setValue(this.searchText) every time when

@Input() searchText: string; changes. You can achieve this by creating setter for this property or using ngOnChanges lifecycle method.

Alternatively you can create custom reusable formControl Custom form controls

1
votes

you needn't use a FormGroup, you can use a single formControl

controlSearch=new FormControl()

<input [formControl]="controlSearch">

and in ngOnInit you subscribe to valueChange to emit the response

ngOnInit(){
   this.controlSearch.valueChanges.pipe(
      startWith(this.controlSearch.value)
   ).subscribe(res=>{
      this.onSearchTextEntered.emit(res);
   })
}

The rxjs operator startWith makes that execute at first with the actual value

Use a setter in Input to give value to the control

@Input() set searchText(value){
    this.controlSearch.setValue(value);
}