Search code examples
angulartypescriptangular-reactive-formsform-controlformgroups

how to control each reactive form in same control name?


hello now I'm building Q&A page for my web-site. When customer ask a question, manager can answer each question in same page. But I don't know how to control each textarea. If I write answer for first question than click the second or other submit button, It will operate like when I click first button. How can I control each textarea?

Thank you

board.component.html

<div class="col-lg-7 col-xl-8">
        <!-- Post title -->
        <h3 class="font-weight-bold mb-3"><strong>{{post.title}}</strong></h3>
        <!-- Excerpt -->
        <p class="dark-grey-text">{{ post.message }}</p>
        <!-- Post data -->
        <p>by <a class="font-weight-bold">{{post.name}}</a>, <a type="date">{{ post.created_at }}</a></p>
        <!-- Read more button -->
        <form [formGroup]="responseForm" (ngSubmit)="onSubmit(post)">
            <div class="md-form">
                <textarea id="response" class="md-textarea form-control" formControlName="response" rows="3" id="responseText" type="text" length="120" mdbCharCounter mdbInput></textarea>
                <label for="input_text">Type your text</label>
            </div>
            <button [disabled] ="!responseForm.valid" type="submit()">dddd</button>
        </form>
      </div>

Board.component.ts

posts : Post[] = [];
  private postsSub: Subscription;

  responseForm: FormGroup; 

  headElements = ['Title', 'Name', 'Email', ''];
  masterHeadElements = ['Message'];
  constructor(private contactService : ContactService) { }

  ngOnInit(): void {
    this.responseForm = new FormGroup({
      id: new FormControl(''),
      response : new FormControl('', Validators.required)
    });

    this.contactService.getPosts();
    this.postsSub = this.contactService.getPostUpdatedLintenr().subscribe((posts: Post[]) => { 
      this.posts = posts
    });    
    //this.responseForm.controls['id'].patchValue(this.posts);

  }

  
  onSubmit(postData : Post){
      let newPost : Post = {
        id: postData.id,
        name : postData.name,
        email : postData.email,
        message : postData.message,
        response : this.responseForm.value.response     //I don't know how to make this part...
      }
      this.responseForm.reset();
      console.log(newPost)
  }


Solution

  • Correct me if I have understand wrong but I can't see the whole code. So I suppose:

    Board.component.html showcase all posts with an *ngFor for each post of posts[]

    However in board.component.ts only one form is created for all posts. Therefore each button submits the form that belongs to other posts as well.

    Considering your approach here what I would do is to break down this component to a smaller component. So I would create another smaller component for example post.component.ts

    with post.component.html being the following

    <div class="col-lg-7 col-xl-8">
            <!-- Post title -->
            <h3 class="font-weight-bold mb-3"><strong>{{post.title}}</strong></h3>
            <!-- Excerpt -->
            <p class="dark-grey-text">{{ post.message }}</p>
            <!-- Post data -->
            <p>by <a class="font-weight-bold">{{post.name}}</a>, <a type="date">{{ post.created_at }}</a></p>
            <!-- Read more button -->
            <form [formGroup]="responseForm" (ngSubmit)="onSubmit(post)">
                <div class="md-form">
                    <textarea id="response" class="md-textarea form-control" formControlName="response" rows="3" id="responseText" type="text" length="120" mdbCharCounter mdbInput></textarea>
                    <label for="input_text">Type your text</label>
                </div>
                <button [disabled] ="!responseForm.valid" type="submit()">dddd</button>
            </form>
          </div>
    

    Then post.component.ts would only submit a single post. post.component.ts would receive post details with @Input() post: Post

    Then the parent board.component.html would render each post with an ngFor

    <div class="col-lg-7 col-xl-8" *ngFor ="let post of posts">
      <app-post [post]="post"> </app-post>   <-- pass post details to child component
    </div>
    

    Then board.component.ts will become

      @Input() post : Post;
     
      responseForm: FormGroup; 
    
      headElements = ['Title', 'Name', 'Email', ''];
      masterHeadElements = ['Message'];
      constructor(private contactService : ContactService) { }
    
      ngOnInit(): void {
        this.responseForm = new FormGroup({
          id: new FormControl(''),
          response : new FormControl('', Validators.required)
        });
        this.responseForm.controls['id'].value = this.post.id;
      }
    
      
      onSubmit(postData : Post){
          let newPost : Post = {
            id: postData.id,
            name : postData.name,
            email : postData.email,
            message : postData.message,
            response : this.responseForm.controls['response'].value   
          }
          this.responseForm.reset();
          console.log(newPost)
      }