phú phạm
phú phạm

Reputation: 57

Array when push in child components not update follow data parent pass into child in Angular Behavior

Here is my child compoent. Still listen change data from parent, but in my code, ArrayObjectParser not listen change follow it. So any idea in here? pls help me.

import { Component, OnInit, Inject, ViewChild, Input } from '@angular/core';
import { FormTemplateModel, PageBuilderModel, SectionLayoutModel, EntityMappings } from '../../models/dynamic-form.model'
import { BehaviorSubject } from 'rxjs';
import { skipWhile, take } from 'rxjs/operators';
@Component({
  selector: 'm-entity-mappping',
  templateUrl: './entity-mappping.component.html',
  styleUrls: ['./entity-mappping.component.scss']
})
export class EntityMapppingComponent implements OnInit {

  private _obsers: any[] = [];

  @ViewChild('inputControl') nameInput: any;

  @Input()
  set data(value) {
    this.viewData.TemplateData$.next(value);
  };

  get data() {
    return this.viewData.TemplateData$.getValue();
  }

  constructor() { }

  viewModel: any = {
    DynamicPreview: new FormTemplateModel()
  }

  viewData: any = {
    TemplateData$: new BehaviorSubject<FormTemplateModel>(null),
    FormEntityData: new Array<EntityMappings>()
  };

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

  ngOnDestroy() {
    for (let obs of this._obsers) {
      obs.unsubscribe();
    }
  }
  
  parserDataToObjectEntity(data: FormTemplateModel) {
    const ArrayObjectParser = [];
    data.LayoutBuilder.forEach((element: PageBuilderModel) => { //Still working right here
      element.SectionLayouts.forEach((section:SectionLayoutModel) => {
        if (section.Type == "Container") {
          section.FieldLayouts.forEach((field:SectionLayoutModel) => { //Breaking right here

            let object : EntityMappings  = {
              Id: field.Id,
              Title: field.Title,
              EntityProperty: ""
            }            
            ArrayObjectParser.push({ ...object });
          })
        }
        else {
          let object = {
            Id: section.Id,
            Title: section.Title,
            EntityProperty: ""
          }
          ArrayObjectParser.push({ ...object });
        }
      })
    }); 
    console.log(ArrayObjectParser);
    return ArrayObjectParser;
  }


  private bindSubscribes() {

    this._obsers.push(
      this.viewData.TemplateData$.subscribe((value: FormTemplateModel) => {
        this.parserDataToObjectEntity(value);
      })
    );
  };


}

My purpose is to convert data from the parent sent down to another array.

I want every time the parent changes data, my data will be changed, but my code is ineffective when using used as such.

Maybe it's because I used the wrong foreach?

Example data i come

{
  "Id": "",
  "Name": {
    "vi": "Name"
  },
  "LayoutBuilder": [
    {
      "Id": "Page1",
      "Title": {
        "vi": "ten page",
        "en": "page name"
      },
      "Order": 1,
      "SectionLayouts": [
        {
          "Id": "Page1_Section1",
          "Order": 1,
          "Title": {
            "vi": "Phan"
          },
          "Type": "Container",
          "FieldLayouts": [
            {
              "Id": "Page1_Section1_Field1",
              "Order": 1,
              "Title": {
                "vi": "Cau hoi"
              },
              "Type": "Input",
              "Required": false,
              "SubType": "Text"
            }
          ]
        }
      ]
    }
  ]
}

and then FormEntityData is become ArrayObjectParser like here

    "EntityMappings":[
        {
            "Id":"Page1_Section1_Control1",
            "Title":{"vi":"Ten field", "en":"Field Name"},
            "EntityProperty":"Hovaten"
        },
        {
            "Id":"Page1_Section1_Control2",
            "Title":{"vi":"Ten field", "en":"Field Name"},
            "EntityProperty":"Email"
        }
    ],

Upvotes: 2

Views: 2942

Answers (1)

Adrian Brand
Adrian Brand

Reputation: 21658

Input properties only listen to the reference of an object changing, not the data itself. If you want the data pushed down to the child component each time you will need to create a new array.

<child [data]="data"></child>

if you do this.data.push(val) this will not trigger the input property to recognise a new array as it is still the same reference to an array. For input properties to trigger you need to change data to be a reference to a new array with this.data = [...this.data, val] as data is now a new object and the input property will trigger.

Here is a StackBlitz that creates a new array https://stackblitz.com/edit/angular-ivy-mqvdf6?file=src%2Fapp%2Fapp.component.ts

Here is one that pushed data to the array https://stackblitz.com/edit/angular-ivy-pfcms1?file=src%2Fapp%2Fapp.component.ts

Notice how the first one triggers the setter property on each click but the second one doesn't.

Upvotes: 3

Related Questions