lacolaco / ng-dynamic

dynamic contents projection in Angular

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Binded events

zarpilla opened this issue · comments

Hi,
Direct angular events are not binded, for example:

export class DynamicCmpDemoComponent {
  template = `
  <article>
    <h1>Awesome Document</h1>
    <div>
      <p (click)="doClick()">{{text}}</p>
      <my-button></my-button>
    </div>
  </article>
  `;
  text = 'foo';
  doClick() {
    console.log('click');
  }
}

Throws an exception when clicking in the paragraph.
There is a way to do this without child components?

Can you copy your @component decorator details, please? It totally depends on the context you've defined in dynamicComponent directive.

Here the complete class:


import { Component } from '@angular/core';

@Component({
  selector: 'dynamic-cmp-demo',
  template: `
    <h2>dynamic-cmp-demo</h2>
    <div *dynamicComponent="content; context: {text: text};"></div>
    
  `,
})
export class DynamicCmpDemoComponent {
  content: string;

  text = 'foo';

  ngOnInit() {
    fetchAwesomeDocument().then(content => {
      this.content = content;
    });
  }

  doClick() {
    console.log('click');
  }

}

export function fetchAwesomeDocument() {
  return Promise.resolve(`<article>
    <h1>Awesome Document</h1>
    <div>
      <p (click)="doClick()">{{text}}</p>
    </div>
  </article>`);
}

and the error:

_.html:4 ERROR TypeError: co.doClick is not a function
    at Object.eval [as handleEvent] (_.html:4)
    at handleEvent (main.js:12303)
    at callWithDebugContext (main.js:13595)
    at Object.debugHandleEvent [as handleEvent] (main.js:13183)
    at dispatchEvent (main.js:9203)
    at main.js:9795
    at HTMLParagraphElement.<anonymous> (main.js:19043)
    at ZoneDelegate.invokeTask (main.js:61793)
    at Object.onInvokeTask (main.js:4530)
    at ZoneDelegate.invokeTask (main.js:61792)

The error happens too if the template is not obtained by a promise.

The interesting part is behind "context: {text: text}". The context declares what can be used in your dynamic template where the map key (left hand side) can be used in your template and the value is property/function in your component. Your context definition only declares "text", but you would like to use "onClick" as well.
In general you have following options:

  1. declare each property / function by yourself - in your example it will be
    context: {text: text, onClick: onClick}

  2. export everything from "this"
    context: {comp: this}
    You can now use {{comp.text}} or comp.doClick in your template.

  3. using shortcut "this", but there are some pitfalls
    context: this
    Properties (not functions) like "text" should be stored in a additional object or the properties won't be updated in the template if you changed it in the component (issue that cannot be solved)

@Component({
  selector: 'dynamic-cmp-demo',
  template: `
    <h2>dynamic-cmp-demo</h2>
    <div *dynamicComponent="content; context: this;"></div>
  `,
})
export class DynamicCmpDemoComponent {
 content: 'A dynamic template . Value of text is  <a (click)="doClick">{{prop.text}}</a>';
 prop = {
   text: 'foo'
 }
 // ...

Ohhh, great!
Thank you very much!