Sending asynchronous data to a child component in Angular 2

Having trouble with passing asynchronous data to a child component. I am attempting to create a dynamic form generator, but I encounter an issue when trying to fetch JSON data via an Observable and then passing it to the child component.

Service:

generateSearchFields2(): Observable<any> {
        return this.http
            .get(this.API + 'searchFields')
            .map((res:Response) => {
                res.json().data as any;
                for (var i = 0; i < res.json().data.length; i++) {
                    var searchField = res.json().data[i];
                    switch (searchField.component) {
                        case "TextboxQuestion": 

                            let TXQ: TextboxQuestion = new TextboxQuestion({
                                key: searchField.key,
                                label: searchField.label,
                                value: searchField.value,
                                required: searchField.required,
                                order: searchField.order
                            });
                            this.searchFieldModels.push(TXQ);
                            console.log("TXQ: ", TXQ, this.searchFieldModels);
                            break;
                        case "DropdownQuestion": 

                            let DDQ: DropdownQuestion = new DropdownQuestion({
                                key: searchField.key,
                                label: searchField.label,
                                required: searchField.required,
                                options: searchField.options,
                                order: searchField.order
                            });
                            this.searchFieldModels.push(DDQ);
                            console.log("TXQ: ", DDQ, this.searchFieldModels);
                            break;
                        default:
                            alert("DEFAULT");
                            break;
                    }
                }
                return this.searchFieldModels.sort((a, b) => a.order - b.order);
            })
            .catch(this.handleError);
    }

Parent Component:

generateSearchFields2() {
    this.service.generateSearchFields2()
      .subscribe(res => this.searchFields = res)
  }

I am passing a variable using the INPUT directive in the parent template to the child: [searchFields]="searchFields"

The issue arises in the child component, where the searchField has an undefined value. In this child component, I pass the value to another service to create form controls, but I also encounter undefined there. The data discrepancy begins here, in the child component:

@Input() searchFields: SearchBase<any>[] = [];

ngOnInit() { 
    this.form = this.qcs.toFormGroup(this.searchFields);
    console.log("ONINIT DYNAMIC FORM COMPONENT: ", this.searchFields);
  }

Any suggestions on how to pass an asynchronous variable without losing data in the process?

Answer №1

To optimize your code, consider turning @Input() searchFields into a setter method.

private _searchFields: SearchBase<any>[] = [];
@Input() set searchFields(value SearchBase<any>[]) {
  if(value != null) {
    this.form = this.qcs.toFormGroup(this.searchFields);
    console.log("ONINIT DYNAMIC FORM COMPONENT: ", this.searchFields);
  }
}

get searchFields() : SearchBase<any>[] {
  return this.searchFields;
}

Another option is to utilize ngOnChanges(), a method that gets called whenever an input is updated. However, using a setter is typically more user-friendly, unless the code execution relies on multiple inputs being set.

Answer №2

When the ngOnInit event is triggered, the data received from the parent component is not yet bound. This means that the searchFields variable is currently undefined. To access it, you should utilize the NgAfterViewInit component lifecycle event.

@Input() searchFields: SearchBase<any>[] = [];

ngAfterViewInit() {   
    this.form = this.qcs.toFormGroup(this.searchFields);
    console.log("ONINIT DYNAMIC FORM COMPONENT: ", this.searchFields);
}

For further information, you can refer to the Angular2 Component Lifecycle events

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

Sorting an array of objects keys according to the position of keys in another array

I have two arrays: one with the correct order of keys and values, and another array coming from a backend in an unsorted format. let arr1 = ['name', 'age', 'occupation', 'address'] let arr2 = [{'age': 20, ...

Securing API data: Utilizing encryption techniques in express and nuxtjs to deter scraping efforts

I'm looking for a secure way to encrypt my API data in order to prevent users from viewing it in the network tab or as plain text within objects like window.__nuxt__. Currently, I am following these steps: Encrypting data on the back-end using a sec ...

What is the best method for globally configuring the Angular moment timezone?

I integrated angular moment js into my angular application. I am looking to display the date and time based on the time zone of the user accessing the app. However, I am facing difficulty in applying the time zone globally throughout my application. https ...

How can I trigger a CSS animation to replay each time a button is clicked, without relying on a timeout function?

I am having trouble getting a button to trigger an animation. Currently, the animation only plays once when the page is refreshed and doesn't repeat on subsequent clicks of the button. function initiateAnimation(el){ document.getElementById("anima ...

npm not only loads the packages specified in my package.json file

Currently, I am working on a small project utilizing npm, bower, and grunt. Upon executing "npm install" on my personal computer, it seems to be loading an excessive amount of peculiar items (refer to attached screenshot). However, when performing the same ...

Using an HTML element to pass a variable into a replace function

I am looking to highlight a 'SearchString' by replacing it with <span style="background-color: yellow">SearchString</span> within a targetString. The SearchString varies, so I am wondering how I can make this happen. This is what I ...

In Angular 2, how does the "this" keyword from the subscribe method reference the class?

I am using a subscription for Observable, and when it finishes I need it to call a function from this class. The issue is that the "this" keyword refers to the subscription and not to the class scope. Here is the code snippet: export class GoogleMapCompo ...

Link JSON filters to specific JSON nodes on the map

I have data representing nodes and links for a force directed graph. The links can have different numbers of connections between them, such as one, two, or three links: {"nodes": [{"id": "Michael Scott", "type": "boss"} ,{"id": "Jim Halpert", "t ...

jQuery's :last selector allows you to target the last

I need assistance with my jQuery code $('#share_module:last').css("background-color","red"); Unfortunately, it is only affecting the first #share_module Here is an example of the HTML structure: <div id = "share_module" class = "id of the ...

Leveraging image values for selecting an image from a collection and showcasing it (Javascript)

I have a collection of images that I want to enlarge upon clicking. Here is what I currently have: <div class="gallery"> <div> <img src="content/imggallery/img1.jpg" class="oldimg" value="0"> </div> ...

Encountering issues with data binding functionality within the stepper component

Within my web application, I have implemented 2 input fields known as Course name (utilizing an Autocomplete component) and Price (utilizing an input component). Previously, upon selecting a specific Course name, the corresponding Price would be displayed ...

Having trouble with Angular 2 Routing and loading components?

I am facing an issue with Angular 2 where it is searching for my component in app/app/aboutus.component, but I cannot pinpoint the source of the problem. Here is my app.component.ts code: import { Component } from '@angular/core'; import { ROUT ...

Calculating the product of numbers within an HTML table based on designated column headers using IONIC instructions

Issue: In my HTML table, there are three columns labeled as Price, Quantity, and Total. Numbers are entered under each column. Objective: My goal is to automatically calculate the value in the Total column by multiplying the values in the Price and Quanti ...

I have a brief snippet of JavaScript code that demonstrates how to access properties

Is there a way to make the following javascript code more concise? It creates an object with the element's id as key and the element itself as value. const createWrapper = elem => { return {[elem.id]: elem} } Example: createWrapper({id:&apos ...

Creating a new list by grouping elements from an existing list

I have successfully received data from my API in the following format: [ {grade: "Grade A", id: 1, ifsGrade: "A1XX", ifsType: "01XX", points: 22, type: "Type_1"}, {grade: "Grade B", id: 2, ifsGrade: &quo ...

Complete guide on modifying CSS with Selenium (Includes downloadable Source Code)

I am looking to switch the css styling of a website using Python and Selenium. My initial step was to retrieve the current CSS value. Now, I aim to alter this css value. The Python code output is as follows: 0px 0px 0px 270px How can I change it from 0 ...

Creating a dynamic image binding feature in Angular 8

I am working with an object array that requires me to dynamically add an image icon based on the type of credit card. Typescript file icon: any; savedCreditCard = [ { cardExpiryDateFormat: "05/xx", cardNumberLast: "00xx", cardId: "x ...

Is JsonEditor capable of editing JSON Schemas effectively?

For a while now, I have been impressed by the functionality of JSON-editor and have been using it to edit documents based on a specific JSON schema. But why stop there? Many users utilize JSON-Editor to make changes to JSON documents according to the corr ...

Effortless glide while dragging sliders with JavaScript

In the code below, an Object is looped through to display the object key in HTML as a sliding bar. jQuery(function($) { $('#threshold').change(updateThreshold); function updateThreshold () { var thresholdIndex = parseInt($(&apos ...