2

In Angular2 I am creating a modal window which needs to be toggled on and off. During the development I stumbled upon something weird:

When I change the activate variable inside my Modal class with an external button. The view is not updating.

Printing the activate variable in the console goes without any problem. I see the variable toggle between true and false.

It looks like I am missing code which forces the view to render with the new values.

Does anyone have an idea what I might be missing here?

The code below in a Plunkr

app.ts

import {Component} from 'angular2/core';
import {Modal} from './modal';

@Component({
  selector: 'my-app',
  providers: [Modal],
  template: `
    <div>

      <button (click)="toggle()">toggle</button>

      <button (click)="showActivate()">print</button>

      <modal></modal>

    </div>
  `,
  directives: [Modal]
})
export class App {
  constructor(private modal: Modal) {

  }

  showActivate() {
    this.modal.showActivate();
  }

  toggle() {
    this.modal.toggleActivate();
  }
}

modal.ts

import {Component, Injectable} from 'angular2/core'

@Component({
  selector: 'modal',
  template: `
    <div>
      <h2>Modal: {{activate}}</h2>
    </div>
  `,
  directives: []
})

@Injectable()
export class Modal {

  activate: true;

  constructor() {
    this.activate = false;
  }

  showActivate() {
    console.log('Modal:showActivate', this.activate);
  }

  toggleActivate() {
    console.log('Modal:toggleActivate', this.activate);
    this.activate = !this.activate;
  }

}

2 Answers 2

4

Just because you inject a modal and get a modal, doesn't mean it is the modal instance you want. If you list it in providers Angular DI just creates an instance and passes it in, but this instance is not related to the <modal> tag at all

Use instead @ViewChild() to get a reference

Plunker

@Component({
  selector: 'my-app',
  template: `
    <div>

      <button (click)="toggle()">toggle</button>

      <button (click)="showActivate()">print</button>

      <modal #modal></modal>

    </div>
  `,
  directives: [Modal]
})
export class App {
  @ViewChild('modal') modal;
  constructor() {

  }

  showActivate() {
    this.modal.showActivate();
  }

  toggle() {
    this.modal.toggleActivate();
  }
}

For your example code it isn't necessary to get a direct reference at all anyway. You can use binding with @Input() and @Output(). If the component and the modal are not that closely related (if you use a global modal instance that can be utilized by the entire application a shared service with an Observable that notifies about value changes might be a better approach.

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

Comments

2

working plunker

I have changed providers to directives like,

directives: [Modal]

And I'm using @ViewChild to get access of ModalCmp.

app.ts

//our root app component
import {Component,ViewChild} from 'angular2/core';
import {Modal} from './modal';

@Component({
  selector: 'my-app',
  directives: [Modal],
  template: `
    <div>

      <button (click)="toggle()">toggle</button>

      <button (click)="showActivate()">print</button>

      <modal></modal>

    </div>
  `
})
export class App {
  @ViewChild(Modal) vc:Modal;
  constructor() {

  }

  showActivate() {
    this.vc.showActivate();
  }

  toggle() {
    this.vc.toggleActivate();
  }
}

Modal.ts

//our root app component
import {Component, Injectable} from 'angular2/core'

@Component({
  selector: 'modal',
  template: `
    <div>
      <h2>Modal: {{activate}}</h2>
    </div>
  `,
  directives: []
})

//@Injectable()
export class Modal {

  activate: true;

  constructor() {
    this.activate = false;
  }

  showActivate() {
    console.log('Modal:showActivate', this.activate);
  }

  toggleActivate() {
    this.activate = !this.activate;
    console.log('Modal:toggleActivate', this.activate);

    console.log(this.activate)
  }

}

Comments

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.