1
votes

My parent angular component has a nested child component. That child component is a list of buttons. When one button is clicked a value is passed to the child component. That child component is then updated accordingly to an id. I have implemented some change detection to the child. When child register an update comming from the parent, it runs the ngOnChanges hook. Here i call my backend and data returns

My code is working fine, but it seems like a hack. As you can see in the following code, I detach the changeDetection object. In the ngOnChanges - in the subscribe section I reattach the cd again. I dont like

Can you guys give me some pointers on this?

@Component({
  selector: 'app-challenge',
  templateUrl: './challenge.component.html',
  styleUrls: ['./challenge.component.css']
})
export class ChallengeComponent implements OnInit {
  @Input() focusedChallenge: string;

  eventId = {};
  challenge: Challenge;
  userSelection;

  constructor(
    public snackBar: MatSnackBar,
    private eventService: EventService,
    private activeRoute: ActivatedRoute,
    private cd: ChangeDetectorRef
  ) {  
this.cd.detach()
}

  ngOnInit() {
    this.eventId = this.activeRoute.snapshot.params.id;
  }

  ngOnChanges() {
    this.eventService.getChallenge(this.focusedChallenge)
      .subscribe(
        res => {
          this.cd.reattach();
          console.log(res)
          this.challenge = res
        },
        err => { console.log(err) }
      )
      challengeSelected.currentValue.toUpperCase();
  }

Update in response to answer

It does actually give me the result that I want with ngOnChanges(changes: SimpleChanges). But it gives we an error still. Saying that it is undefined.

enter image description here

The options array is a nested array on Challenge

The object returned from db

{_id: "5b86dc5bfb6fc03893e55001", shortEventId: "d2d3", organization: "Brædstrup", name: "1. december", winner: "", …}
born: "1. decemberplus andet"
endDate: "2018-10-06T23:59:00.000Z"
id: "5b86dc5bfb6fc03893e55001"
name: "1. december"
options: Array(4)
0: {name: "Matas", isCorrect: true, description: "Matas er den førende skib", image: "https://cityxpstorage.blob.core.windows.net/images/Matas.png", id: null}
1: {name: "Føtex", isCorrect: false, description: "Føtex er en dejlig butik", image: "https://cityxpstorage.blob.core.windows.net/images/Føtex.png", id: null, …}
2: {name: "Kvickly", isCorrect: false, description: "Kvickly er en dejlig butik", image: "https://cityxpstorage.blob.core.windows.net/images/Matas.png", id: null, …}
3: {name: "MC Jørgensen", isCorrect: false, description: "MC Jørgensen er en dejlig butik", image: "https://cityxpstorage.blob.core.windows.net/images/Matas.png", id: null}
length: 4
__proto__: Array(0)
organization: "Brædstrup"
shortEventId: "d2d3"
startDate: "2018-10-06T00:00:00.000Z"
winner: ""
_id: "5b86dc5bfb6fc03893e55001"
__proto__: Object
1
You shouldn't need to do anything with the ChangeDetectorRef. Any time that focusedChallenge is changed, it should fire ngOnChanges - user184994
The problem is that my view is updated first - but is has no values to attach. It gives me a [object] is undefined error. So it seems that I need to detach the view first in order to suppres errors. - K N
You can just handle the case of it being undefined, by performing an if check on it. You can use something like if (suchAndSuch != null), or if it's in the template, you can use suchAndSuch?.myProp, where the ? will prevent it from trying to read myProp is suchAndSuch is null or undefined - user184994
Could you give me an example? Where should I make the check? - K N
Which is the variable is undefined? Can you post the actual error message please? - user184994

1 Answers

1
votes

Since you are using string type input, you don't need to capture any ChangeDetection. So better you remove the ChangeDetectorRef and let the angular fire the ngOnChanges method whenever the @Input value is getting changed.

Your code should be as -

@Component({
  selector: 'app-challenge',
  templateUrl: './challenge.component.html',
  styleUrls: ['./challenge.component.css']
})
export class ChallengeComponent implements OnInit {
  @Input() focusedChallenge: string;

  eventId = {};
  challenge: Challenge;
  userSelection;

  constructor(
    public snackBar: MatSnackBar,
    private eventService: EventService,
    private activeRoute: ActivatedRoute
  ) {  
}

  ngOnInit() {
    this.eventId = this.activeRoute.snapshot.params.id;
  }

ngOnChanges(changes: SimpleChanges) {

    let newFocusedChallenge  = changes["focusedChallenge"].currentValue;

    this.eventService.getChallenge(newFocusedChallenge)
      .subscribe(
        res => {
          console.log(res)
          this.challenge = res;
          //challengeSelected.currentValue.toUpperCase(); //not sure if is required
        },
        err => { console.log(err) }
      )
  }
}