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:
-
declare each property / function by yourself - in your example it will be
context: {text: text, onClick: onClick}
-
export everything from "this"
context: {comp: this}
You can now use {{comp.text}} or comp.doClick in your template. -
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!