4

I want to show and hide an element by using a button that's located in another component.

So I have a Dashboard with an amount of chambers in it and a header.

HTML of DashboardComponent with app-header and app-chamber:

 <app-header></app-header>
    <div class="container">
      <div class="row">
        <app-chamber [kamers]="kamers"></app-chamber>
      </div>
    </div>

I have this HTML wth the *ngIf in my ChamberComponent:

<div class="col-sm-6 col-md-4 col-lg-3 cardcol" *ngFor="let kamer of kamers; let i = index">
      <md-card class="chamber wit" *ngIf="kamer.patient == null">
         <p *ngIf="showId">{{kamer.id}}</p>
      </md-card>
</div>

In the HeaderComponent I have a button that needs to show and hide the element :

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {

  @Input() aList;

  dashboardComponent:DashboardComponent;

  chamberComponent:ChamberComponent;

  constructor(dashboardComponent: DashboardComponent, chamberComponent:ChamberComponent) {
    this.dashboardComponent = dashboardComponent;
    this.chamberComponent = chamberComponent;

  }

  ngOnInit() {

  }

// THIS GETS CALLED BY A BUTTON CLICK
  toggleId(){
    this.chamberComponent.toggleId();
  }

}

then my ChamberComponent code:

@Component({
  selector: 'app-chamber',
  templateUrl: './chamber.component.html',
  styleUrls: ['./chamber.component.css']
})
      export class ChamberComponent implements OnInit {

      @Input() kamers;
      showId:boolean;

      constructor() {
        this.showId=false;
      }

      ngOnInit() {

      }

      toggleId = () => {
          this.showId = !this.showId;
      }

    }

So when I click the button, the value changes (I've logged this in the console) but the view isn't updated..

When I put a button in my ChamberComponent that calls the toggleId() function the view does reveice an update and the element is shown or hidden.

But I need to toggle it from a button on my header.

Sytham
  • 824
  • 3
  • 11
  • 25
  • Possible duplicate of [Angular 2 Show and Hide an element](http://stackoverflow.com/questions/35163009/angular-2-show-and-hide-an-element) – SeleM Dec 26 '16 at 16:42
  • The duplicate was about 'this' in a callback scope. However my code should work according to that example. this.showId not working.. – Sytham Dec 26 '16 at 16:46
  • If it's not shown or hidden at all, and you have no other content there, are you sure the condition `*ngIf="kamer.patient == null"` is fulfilled? – AT82 Dec 26 '16 at 16:49
  • Yes I am seeing the element md-card. If I set the boolean showId to true then the id will show up on reload, If I set the boolean showId to false then the id is not showing when I reload the page, but nothing gets updated dynamically when I call the function toggleId – Sytham Dec 26 '16 at 16:51
  • Could it be that when I call the function of the component from another comonent, this is not working? Because when I call the toggleId() function from within the html of the component itself it is working. However I need to call that function from inside another component – Sytham Dec 26 '16 at 16:56
  • 1
    This is the problem, and this should very much be added to the question as it is very relevant information! So put all related code in the post please! :) – AT82 Dec 26 '16 at 16:59
  • 1
    I've updated the question, thanks! – Sytham Dec 26 '16 at 17:14

1 Answers1

12

Plunker

There was a small mismatch between the @Input() kamers and the template *ngIf="kamer.patient == null".

  • Just change the input to kamer.

Template HTML

<md-card class="chamber wit" *ngIf="kamer.patient === null">
   <p *ngIf="showId">{{kamer.id}}</p>
</md-card>

<button (click)="toggleId()">Toggle</button>

Component

@Component({
  selector: 'material-app',
  templateUrl: 'app.component.html'
})
export class AppComponent {

  kamer = {
    patient: null,
    id: '1'
  };
  showId = false;

  ngOnInit() {

  }

  toggleId() {
    this.showId = !this.showId;
  }

}

Update (1) - Plunker (1)

Use @ViewChild

To reference a child component's functions use ViewChild

  • Place @ViewChild('child') child; in the parent component
  • In the parent template reference child functions like this: <button (click)="child.toggleId()">Toggle</button>

Parent Component

@Component({
  selector: 'material-app',
  template: `
    <material-child #child></material-child>
    <button (click)="child.toggleId()">Toggle</button>
  `
})
export class AppComponent {

  @ViewChild('child') child;

}

Child Template

<md-card class="chamber wit" *ngIf="kamer.patient === null">
   <p *ngIf="showId">{{kamer.id}}</p>
</md-card>

Child Component

@Component({
  selector: 'material-child',
  templateUrl: 'app.component.html'
})
export class ChildComponent {

  kamer = {
    patient: null,
    id: '1'
  };
  showId = false;

  ngOnInit() {

  }

  toggleId() {
    this.showId = !this.showId;
  }

}

Update (2) - Plunker (2)

Use @Output() + EventEmitter

To extend the previous setup to use a sibling component you can

  • Have the sibling emit an event using an EventEmitter
  • Listen to the emitted event in the parent component, and call the child function needed using ViewChild

Sibling Component

@Component({
  selector: 'material-sibling',
  template: `
    <button (click)="toggle.emit()">Toggle</button>
  `
})
export class SiblingComponent {
  @Output() toggle = new EventEmitter();
}

Parent Component

@Component({
  selector: 'material-app',
  template: `
    <material-child #child></material-child>
    <material-sibling (toggle)="child.toggleId()"></material-sibling>
  `
})
export class AppComponent {

  @ViewChild('child') child;

}

Child Template

<md-card class="chamber wit" *ngIf="kamer.patient === null">
   <p *ngIf="showId">{{kamer.id}}</p>
</md-card>

Child Component

@Component({
  selector: 'material-child',
  templateUrl: 'app.component.html'
})
export class ChildComponent {

  kamer = {
    patient: null,
    id: '1'
  };
  showId = false;

  ngOnInit() {

  }

  toggleId() {
    this.showId = !this.showId;
  }

}
adriancarriger
  • 2,970
  • 3
  • 19
  • 26
  • Thanks for your time, I've updated the question with more info. So basically if I follow your advise, I have 2 childs (app-chamber and app-header) of the DashboardComponent. Now your example shows how to call a function of the child from the parent. I need to call a function from a child to another child. – Sytham Dec 26 '16 at 17:18
  • Maybe the best/easiest solution is to just put the header in the dashboard html and do it like you said? – Sytham Dec 26 '16 at 17:24
  • Okay, I think I've got it for the sibling setup.. let me know if you need anything else, thanks! – adriancarriger Dec 26 '16 at 17:37
  • You sir, are a hero! – Sytham Dec 26 '16 at 20:40
  • Thanks, glad it helped! – adriancarriger Dec 26 '16 at 21:47