0

Perhaps I have the wrong setup from the beginning, but I'm having an issue with a child component @Input decorator not updating after the parent's variable has changed. My problem is that the parent's variable is actually getting updated in another child's component that is inherited from the parent.

Sub View Component

@Component({
  selector: 'sub-view',
  templateUrl: './sub-view.component.html',
  styleUrls: ['./sub-view.component.scss']
})
export class SubViewComponent {
  @Input() links;
  ...
}

Parent Component

@Component({
  selector: 'parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent {
  roleLinks:any;

  constructor() {}
  ...
}

Parent View

<sub-view 
    [links]="roleLinks" 
></sub-view>

Child Component #1

@Component({
  selector: 'child1',
  templateUrl: './child1.component.html',
  styleUrls: ['./child1.component.scss']
})
export class Child1Component extends ParentComponent {
  constructor() {
    super();
    this.roleLinks = [
      {key:'a',val:'A'},
      {key:'b',val:'B'}
    ];
  }
  ...
}

I have Child1Component extends ParentComponent because the idea is that I'll have a Child2, Child3 etc. Each child will have a lot of shared components with Parent

So the SubView will only need to be bound to Parent and then each Child Component will be able to have it's own links

However, I cannot get the links to update in SubView Looking at other SO Q/A's, I have tried the following:

  • adding ChangeDetectionStrategy.OnPush to SubView
  • adding detectChanges() from ChangeDetectorRef to SubView
  • adding markForCheck() from ChangeDetectorRef to SubView

And neither of them worked. links is always undefined inside SubView even though I can see that when it is changed inside Child the changes are actually making it down to Parent however SubView is just not detecting the changes

It may be worth noting that I have each Child component in a nested <router-outlet> within Parent Component.

-App
  <router-outlet>
    +Page1
    +Page2
    -Parent
      +SubView
      <router-outlet>
        +Child1
        +Child2
        +...
      +OtherSubView

StackBlitz example

https://stackblitz.com/edit/angular-f2qemh

13
  • The Parent passes its roleLinks to the Subview. Bu the parent's roleLinks is an empty array. The fact that another, completely dfferent component, which has its own roleLinks array, populates its own array with two links won't have any impact on the roleLinks array of the Parent component instance. Toyota extends Car, but that doesn't mean that when a specific Toyota car has two passengers, all cars have the two same passengers. Commented Oct 16, 2019 at 17:27
  • No, not at all. You're completely misunderstanding inheritance. Commented Oct 16, 2019 at 17:30
  • Did you try to add ngIf? <sub-view *ngIf="roleLinks" [links]="roleLinks"></sub-view> Commented Oct 16, 2019 at 17:32
  • 1
    I updated it for you to demonstrate you that each component instance has its own array: stackblitz.com/edit/… Commented Oct 16, 2019 at 18:58
  • 3
    No, it isn't. Again, you're not understanding inheritance and polymorphism. this is the current object. So, when you log this.roleLinks from inside the base's ngOnInit method, and this method is in fact called on an instance of Child1, this is the Child1 instance, and this.roleLinks is the role links of the Child1 instance. This is fundamental OO stuff. If you have an instance variable (roleLinks) defined in a class, and you create 3 instances of that class, each instance has its own value of this instance variable. Commented Oct 16, 2019 at 19:10

1 Answer 1

2

So, I think the problem is that you are not assigning the roleLinks property in the parent component, but rather in the child component (where it is never used).

If you have the following template for parentComponent

<childComponent [links]="roleLinks></childComponent>

Then roleLinks will be assigned from the parent component to the child component. Class-based inheritance is irrelevant for assigning the roleLinks property on the original parent item.

Instead, you will need to assign this property directly, or, if you need state to be shared between parent and child, create an angular service with the data you need and inject it into both.

Sign up to request clarification or add additional context in comments.

4 Comments

I was hoping to avoid a shared service. I figured the inheritance would suffice. I can see that when Child updates roleLinks it is in fact updating in Parent's roleLinks They are one in the same. And on Parent component initialization, it is sending roleLinks to SubView. The problem is that Parent is sending roleLinks to SubView (which is undefined on initialization) before Child sends it up to Parent
No, they aren't the same. The only way they would be the same is if they were static. Are you using the debugger correctly? Also, even if you had wired it up to the same property, this is not the correct way to implement a two-way data binding.
I console.log(this.roleLinks) from both Parent and Child. At the end of Child init, I call Parent init again (with console.log) and it does show the values that I assigend in Child. So calling console.log(this.roleLinks) from Parent is showing the values I assigned from Child
See update for StackBlitz link. Open the console, click on Base button. See that roleLinks is undefined. Then click Child1. See that roleLinks is now populated with the same roleLinks assigned from Child1. Then click Child2. Same thing. Base roleLinks is getting populated from the roleLinks in Children that extend Parent.

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.