Display elements conditionally based on the result of an asynchronous operation within an ng

Using Angular version 11.0.2

I am encountering issues with the async pipe inside an ngIf template, where my data is not being properly refreshed. To illustrate this problem, I have created a simplified example.

View code on Plunker

To reproduce the issue:

  • Click on the add button multiple times
  • Click on the toggle button
  • The data$ | async displays the defaultValue instead of the actual values from myArray (not the expected behavior)
  • Click on the add button again
  • The data$ | async is refreshed and now displays the correct myArray values (expected behavior)
  • Toggle the showMe state two times
  • The data$ | async displays the defaultValue once more (unexpected behavior)

It seems that ngIf is storing the initial values of data$ during the first ngOnInit. Why does {{data$ | async | json}} return the default value even when myArray has been updated?

How can I handle this scenario using rxjs and ngIf?

Template:

<button (click)="add()">+ add</button>
<button (click)="sub()">- sub</button>
<button (click)="toggle()">toggle</button>

myArray={{myArray.value | json}}
length={{myArray.length}}

<div *ngIf="showMe">
  Inside ngIf:<br>
  data={{data$ | async | json}}<br>
  myArray={{myArray.value | json}}
</div>

Component:

import { Component, OnInit,ChangeDetectorRef } from "@angular/core";
import { FormArray, FormBuilder } from "@angular/forms";
import { combineLatest, Observable, of } from "rxjs";
import { filter, map, startWith, tap } from 'rxjs/operators';
@Component({
  selector: "my-app",
  templateUrl: "src/app.component.html"
})
export class AppComponent implements OnInit{

  showMe = false;
  form: FormGroup;
  x: number = 0;
  data$: Observable<any>;

  constructor(
    private fb: FormBuilder,
    private cd: ChangeDetectorRef
  ) {}

  ngOnInit() {
    
    this.form = this.fb.group({
      myArray: this.fb.array(['defaultValue'])
    }) ;

    this.data$ = this.myArray.valueChanges.pipe(startWith(this.myArray.value));
  }

  add() {
    this.myArray.push(this.fb.control(this.x++));
  }

  sub() {
    this.myArray.removeAt(this.myArray.length - 1);
  }

  toggle() {
    this.showMe = !this.showMe;
  }

  get myArray(): FormArray {
    return this.form.get('myArray') as FormArray;
  }
}

Answer №1

Utilize the defer method to generate an actual value for each new subscriber.

 this.data$ = defer(() =>
      this.myArray.valueChanges.pipe(startWith(this.myArray.value))
  );

Modified Working Example

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Is it possible to implement drag and drop functionality for uploading .ply, .stl, and .obj files in an angular application?

One problem I'm facing is uploading 3D models in angular, specifically files with the extensions .ply, .stl, and .obj. The ng2-upload plugin I'm currently using for drag'n'drop doesn't support these file types. When I upload a file ...

A guide on extracting and converting strings in React to display as HTML

I am in the process of developing a simple blog app using a MERN stack. Currently, I have the functionality to create posts with just plain text. Is there a way to incorporate HTML rendering within the content of these posts? For example, a post might con ...

The scale configuration for scale: x is not valid for creating a time scale chart using chart.js

I am currently utilizing VueJS and attempting to integrate a time scale chart using Chart.js. However, I encountered the following error: Invalid scale configuration for scale: x Below is my configuration : First, I have a component named Chart.vue with ...

A more concise method for verifying if the values of several inputs are empty using jQuery

let title = $('#plustitle').val().trim(); // input type text let tags = $('#plustags').val().trim(); // input type text let story = $('#plustory').val().trim(); // textarea I want to check if any of the variables above are e ...

Transforming a collection of Javascript objects into a pure Javascript array

After JSON.stringify-ing my JavaScript object, the output looks like this: [ { "item_id": null, "parent_id": "none", "depth": 0, "left": "1", "right": 4 }, { "item_id": "1", "parent_id": ...

Retrieve the text content of the initial li element within each ul

I have numerous <ul> lists and I'm attempting to extract the text from the first li element of each list. The HTML markup is straightforward: <ul> <li>abc</li> <li>def</li> <li>ghi</li> </u ...

Issue with PrimeNG functionality in Angular4 environment

I encountered an issue while trying to implement PrimeNG into my Angular 4 project. Despite following the setup steps outlined on their website, I received an error message when attempting to import a module. Here's an example of the error: Can' ...

I am looking to utilize the data from a POST request to dynamically update the DOM through a script.js file. How can

After sending a post request, I am looking to update my database and then use an array to dynamically update the HTML content. However, I am struggling with how to pass this data to my script.js file. Here is my progress so far: SERVER let expenseAmo ...

What is causing JS to malfunction and preventing App Scripts from running `doGet()` when using either `e` or `event` as parameters?

Following a Basic Web App video last night, I meticulously followed every step until the very end where things started to go wrong. Today, I decided to start from scratch and recreate it all. Despite weeks of coding practice, I can't seem to figure ou ...

What's a quick way in Javascript to add a string to all elements in an array?

I'm working with an array = ["a", "b", "c"]; What I need to do is concatenate a string, let's say "Hello", to each value in this array. The desired output should look like this: ["Hello_a", "Hello_b", "Hello_c"] Is there a quicker way in java ...

Troubleshooting multiple element visibility problems with jQuery

Please take a look at the code snippet below. $(document).ready(function(){ $(".like-btn").hover(function() { var rowid = $(this).attr("data-rowid"); $(".reaction-box[data-rowid='" + rowid + "']").fadeIn(100, function() { $(".reaction ...

When using Angular server-side pagination with ngrx and Express in Node.js, I often encounter discrepancies in the indexing across different stacks

After successfully implementing server-side pagination in Angular, I encountered an issue where the page was set to 1 initially, but the mat-paginator component started at index 2. Despite functioning correctly when changing pages, this discrepancy puzzled ...

Learn how to creatively style buttons with dynamic effects using tailwindcss

My Desired Button: I have a Button component that can accept a variant prop. My goal is to have the button's className change dynamically based on the prop passed to it. Instead of using if/else statements for different buttons, I want to use a sing ...

Include a link in the email body without displaying the URL

My concern revolves around displaying a shortened text instead of the full link within an email. When the recipient clicks on "Open Link," they should be redirected to the URL specified. The text "Open Link" must appear in bold. My current development fram ...

Is it possible to customize the font color of a placeholder in a v-text-field component in Vue?

Recently, I added the following code snippet to my project: <v-text-field hide-details class="search-field" id="name-input" placeholder="Search by name" v-model="search"></v-text-field> I wanted to change the font color of the placeholder tex ...

What is the best way to direct attention to the HTML5 canvas element?

I'm having an issue with the HTML5 <canvas> element in Firefox 2.0.0.16 and Safari 3.1.2 on my iMac. Even testing in Firefox 3.0 on Windows did not resolve the problem. Here is the code snippet that seems to be causing the trouble: <td> ...

What is the process for verifying a particular user in AngularJS?

I'm new to AngularJS and I'm a bit confused about the concepts of GET, PUT requests. I am currently working on an app where I display a list of users on one page, and on another page, I have a form with three buttons. My main focus is on the "Con ...

What is the reason behind the error "Uncaught SyntaxError: Malformed arrow function parameter list" when using "true && () => {}"?

When the code below is executed: true && () => {} it results in an error message stating: Uncaught SyntaxError: Malformed arrow function parameter list Why does this happen ? Update: I am aware that wrapping the function in parentheses reso ...

Difficulty encountered in altering button color when the password and confirm password fields are the same in a Vue.js project?

password: '', confirmPassword: '', computed: { empty() { return this.user.password === '' || this.user.confirmPassword === ''; }, equal() { return this.user.password === this.user.confirmPass ...

Utilizing D3 for translation by incorporating data from an array within d3.js

I need assistance with drawing rectangles in an SVG where the translation data is stored in an array. Below is the code: var vis=d3.select("#usvg"); var rectData=[10,21,32,43,54,65,76,87,98,109]; vis.selectAll("rect").data(rectData).enter().append("rect ...