3

I have some description text from an API that I am inserting as HTML into the DOM.

<div class="activity-description" [innerHTML]="description"></div>

The description is set within ngOninit();

if (this.eventDetail.description.length > 255) {
   this.description = this.eventDetail.description.substring(0, 255) + '<span class="more-description"> ...Learn More</span>';
}

I am trying to add an event listener to the "more-description" class within the ngAfterViewInit()

var el = this.elementRef.nativeElement.querySelector('.more-description');
    if (el)
        el.addEventListener('click', this.displayFullDescription());

The element is null and does not allow the event listener to be attached. How do I add this event listener to html elements that are dynamically added?

David Aguirre
  • 1,382
  • 4
  • 15
  • 29

1 Answers1

11

You can manually render view by calling cdRef.detectChanges:

constuctor(private cdRef: ChangeDetectorRef) {}

ngOnInit() {
  if (this.eventDetail.description.length > 255) {
    this.description = this.eventDetail.description.substring(0, 255) +
                      '<span class="more-description"> ...Learn More</span>';
  }
}

ngAfterViewInit() {
  this.cdRef.detectChanges();
  var el = this.elementRef.nativeElement.querySelector('.more-description');
}

Update

Perhaps you made some mistake in this code:

el.addEventListener('click', this.displayFullDescription());

I don't know what displayFullDescription function does.

Here is working example:

@Component({
  selector: 'event',
  template: `
    <div class="activity-description" [innerHTML]="description"></div>
  `,
})
export class Event {
  @Input() eventDetail: any;

  description: string;

  constructor(private elementRef: ElementRef) { }

  ngOnInit() {
    if (this.eventDetail.description.length > 255) {
       this.description = this.eventDetail.description.substring(0, 255) + '<span class="more-description"> ...Learn More</span>';
    }
  }

  displayFullDescription() {
    this.description = this.eventDetail.description;
  }

  ngAfterViewInit() {
    var el = this.elementRef.nativeElement.querySelector('.more-description');
    if(el) {
      el.addEventListener('click', this.displayFullDescription.bind(this));
    }
  }
}

Plunker Example

Note: It would be better if you store handler in class property so that you can unsubscribe later.

Exil
  • 311
  • 2
  • 11
  • 26
yurzui
  • 205,937
  • 32
  • 433
  • 399
  • this is not working. The event listener is never attached. – David Aguirre May 16 '17 at 20:31
  • 1
    So the issue is that the description is returned by a service call. So now the question is: "How do I attach an event listener to a dynamic element appended after a service call?" – David Aguirre May 16 '17 at 20:58
  • http://stackoverflow.com/questions/43457149/angular-4-what-is-the-right-way-to-wait-for-operation/43457771#43457771 – yurzui May 16 '17 at 21:01
  • Create plunker to reproduce it. As i said early you can call `cdRef.detectChanges()` to update view after initialization `description` – yurzui May 16 '17 at 21:02
  • I got around the issue with span tags in the HTML.
    ...Learn More
    – David Aguirre May 16 '17 at 22:15
  • Nice answer, just one question, why you did not call the function `displayFullDescription()` directly, why you used `this.displayFullDescription.bind(this)` instead? – SlimenTN Feb 14 '18 at 14:58
  • @SlimenTN addEventListener takes second parameter called listener https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener It should be function. If we call `displayFullDescription()` directly then the **result** of execution will be passed as a listener but we need to pass function with right context. That's why I use `bind` here – yurzui Feb 14 '18 at 15:03
  • How to pass parameter when call `el.addEventListener('click', this.displayFullDescription.bind(this));` – Sanyami Vaidya Aug 03 '18 at 13:06
  • 1
    @Sanyami Vaidya Try `el.addEventListener('click', this.displayFullDescription.bind(this, param))` or `el.addEventListener('click', () => this.displayFullDescription(param))` – yurzui Aug 03 '18 at 13:37