0

I'm using Angular version 7 with a component that has a serie of divs being rendering according to the data coming from an @Input and it should be updated due the service response, nevertheless the component is not correctly updated, the loader remains loading (loading=true) until I click into the text input and then I click elsewhere.

Template:

<div class="row" *ngFor="let message of messages">
  <div>{{message.date}}</div>
  <div>{{message.body}}</div>
</div>
<div class="row" *ngIf="thread.isOpen">
  <div class="panel" >
    <form (ngSubmit)="onSubmit()" [formGroup]="messageForm">
      <textarea class="textarea" name="message" id="message" formControlName="message"></textarea>
      <button class="btn"">
      <span *ngIf="!loading; else loadingTemplate">send</span>
      <ng-template #loadingTemplate>
        <i class="fa fa-spin"></i>
      </ng-template>
    </button>
 </form>
</div>

Component:

@Input() messages;
messageForm: FormGroup;
loading: boolean = false;

ngOnInit(): void {
    this.loadFromControls();
}

loadFromControls(): void {
  this.messageForm = this.formBuilder.group({
    message: this.formBuilder.control('', [])
  });
}

onSubmit() {
  if (!this.messageForm.valid) return;
    this.loading = true;
    const message = this.messageForm.controls['message'].value;
  
    this.service.sendMessage(this.thread._id, message).subscribe(() => {
      if (this.messages) {
        this.messages.push({
            isFromExtranet: true,
            date: new Date(),
            body: message
        });
      }

      this.messageForm.controls['message'].setValue("");
      this.loading = false;
    }, (err) => this.errorMessage(err));
  }

Service

sendMessage(id: string, message: string): Observable<any> {
  return this.http.post(`/api/messages/${id}`, { message })
        .map((res) => res.json())
        .catch((error) => Observable.throw(error.json().code || 'error'));
}

I've been dealing with this a few hours and maybe I'm just missing something very basic.

3
  • We need to see how you are getting messages and passing them into the component please Commented Sep 6, 2022 at 12:59
  • Just a little tip, when you post your code, also show your @Component decorator part so we can see for example if this component is set to onPush.. Commented Sep 6, 2022 at 14:14
  • The only thing I can think of is you're using OnPush strategy, which makes this.messages.push doesn't change at all. To resolve this, try to assign this.messages to something like this.messages = [...this.messages, newMsg]; or simple remove Onpush Commented Sep 6, 2022 at 14:21

2 Answers 2

0

Can you try update the code as per below and make sure that you're getting correct value from @Input decorator.

<div *ngIf="isDataloaded>    
<div class="row" *ngFor="let message of messages">
      <div>{{message.date}}</div>
      <div>{{message.body}}</div>
    </div>
    <div class="row" *ngIf="thread.isOpen">
      <div class="panel" >
        <form (ngSubmit)="onSubmit()" [formGroup]="messageForm">
          <textarea class="textarea" name="message" id="message" formControlName="message"></textarea>
          <button class="btn"">
          <span *ngIf="!loading; else loadingTemplate">send</span>
          <ng-template #loadingTemplate>
            <i class="fa fa-spin"></i>
          </ng-template>
        </button>
     </form>
    </div>
</div> 

Component.ts

 @Input() messages;
    isDataloaded = flase;
    messageForm: FormGroup;
    loading: boolean = false;
    
    ngOnInit(): void {
        this.loadFromControls();
    }
    
    loadFromControls(): void {
      this.messageForm = this.formBuilder.group({
        message: this.formBuilder.control('', [])
      });
    }
    
    onSubmit() {
      this.loading = true;
      if (!this.messageForm.valid) return;
        const message = this.messageForm.controls['message'].value;
      
        this.service.sendMessage(this.thread._id, message).subscribe(() => {
          if (this.event.data.discussionThread.messages) {
            this.event.data.discussionThread.messages.push({
                isFromExtranet: true,
                date: new Date(),
                body: message
            });
          }
    
          this.messageForm.controls['message'].setValue("");
          this.loading = false;
        }, (err) => this.errorMessage(err));
         this.isDataloaded = true;
      }
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, but it will not work cause the div with the validation isDataloaded is wrapping the form that flags the action.
@AndreFontaine can you try with setTimeOut. I am thinking that the HTML dom is load before we get data from input
Yes I already tested with a setTimeout instead of the service and the result is the same. setTimeout(() => {this.messages.push({ date: new Date(), message }); }
0

I fixed using a BehaviorSubject, as:

loading$: BehaviorSubject<boolean> = new BehaviorSubject(false);
...
this.loading$.next(true);

instead of:

loading: boolean = false;
...
this.loading = true;

and in the template with async as:

<span *ngIf="!(loading$ | async); else loadingTemplate">

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.