1

There is chance of possible duplicate but my scenario is bit different.

I want to perform click event for my dynamic component.

here is my structure :

     <razor>
          <mvc-partial>
            <dynamic-html> // buttonPress(){console.log("Function called in dynamicHtml)
                          // Output() to call function in razor.ts
            </dynamic-html>
          </mvc-partial>
      <razor>

RenderingViewDynamic.ts file

import {
    Component,
    Directive,
    NgModule,
    Input,
    Output,
    EventEmitter,
    ViewContainerRef,
    Compiler,
    ComponentFactory,
    ModuleWithComponentFactories,
    ComponentRef,
    ReflectiveInjector, OnInit, OnDestroy, ViewChild
} from '@angular/core';

import { RouterModule } from '@angular/router';
import { CommonModule } from '@angular/common';
import { Http } from "@angular/http";
import 'rxjs/add/operator/map';

export function createComponentFactory(compiler: Compiler, metadata: Component): Promise<ComponentFactory<any> | undefined>{   
    console.log(compiler)
    console.log(metadata)
    class DynamicComponent {
        @Output() buttonType: EventEmitter<string> = new EventEmitter<string>()

        // button click operation
        buttonPress() {
            this.buttonType.emit();
        }
    };
    const decoratedCmp = Component(metadata)(DynamicComponent);

    @NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp] })
    class DynamicHtmlModule { }

    return compiler.compileModuleAndAllComponentsAsync(DynamicHtmlModule)
        .then((moduleWithComponentFactory: ModuleWithComponentFactories<any>) => {
            console.log(decoratedCmp)
            console.log(moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp))
            return moduleWithComponentFactory.componentFactories.find(x => x.componentType === decoratedCmp);
        });
}

@Component({
    selector: 'mvc-partial',
    template: `<div #dynamicHtml></div>`
})
//@Directive({ selector: 'mvc-partial' })
export class RenderingViewDynamic implements OnInit {
    @ViewChild('dynamicHtml', { read: ViewContainerRef }) target: ViewContainerRef;
    html: string = '<p></p>';
    @Input() url: string;
    cmpRef: ComponentRef<any>;

    constructor(private vcRef: ViewContainerRef, private compiler: Compiler, private http: Http) { }

    ngOnInit() {
        this.http.get(this.url)
            .map(res => res.text())
            .subscribe(
            (html) => {
                this.html = html;
                if (!html) return;

                if (this.cmpRef) {
                    this.cmpRef.destroy();
                }

                const compMetadata = new Component({
                    selector: 'dynamic-html',
                    template: this.html,
                });

                createComponentFactory(this.compiler,compMetadata)
                    .then(factory => {
                        //const injector = ReflectiveInjector.fromResolvedProviders([], this.vcRef.parentInjector);
                        this.cmpRef = this.target.createComponent(factory!);
                    });
            },
            err => console.log(err),
            () => console.log('MvcPartial complete')
            );

    }

    ngOnDestroy() {
        if (this.cmpRef) {
            this.cmpRef.destroy();
        }
    }  

}

razor.component.html

<mvc-partial [url]="'/View/Index'" (buttonType)="click()"></mvc-partial>

razor.component.ts

click(){ console.log("In razor") }

My question is, button is in my dynamic-html want to bind it event to function in razor.ts.

like <dynamic-html>-<mvc-partial>-<razor> how could I achieve it?

update: Trying to communicate with service

class DynamicComponent {
        constructor(private appService: AppService) { }

        buttonPress() {
            this.appService.onButtonClickAction.emit()
        }
    };
    const decoratedCmp = Component(metadata)(DynamicComponent);

    @NgModule({ imports: [CommonModule, RouterModule], declarations: [decoratedCmp], providers: [AppService] })

Error pops: Can't resolve all parameters for DynamicComponent: (?).

enter image description here

Above Error solved by adding @Inject(forwardRef(() => AppService)

constructor( @Inject(forwardRef(() =>  AppService)) private appService: AppService) { } 
9
  • You can't use @Output() or @Input() with dynamically added components. See the commented-out code in the first code block in my answer in stackoverflow.com/questions/36325212/… to see how to communicate with dynamically added components. A shared service can be used as well. Commented Aug 24, 2017 at 10:30
  • @GünterZöchbauer stackoverflow.com/questions/40725620/… how it going to help me ? Commented Aug 24, 2017 at 10:37
  • To add a click handler to dynamically added HTML Commented Aug 24, 2017 at 10:47
  • but my question is about DynamicComponent having button I'm handling it in DynamicComponent. buttonPress() { this.buttonType.emit(); } check my question. buttonType() is the one in razor.ts need to call. as your first comment it may possible aka shared service but duplication not justify. Commented Aug 24, 2017 at 10:53
  • I see. I thought that was added after it was marked as duplicate. Sorry, for the mistake. Commented Aug 24, 2017 at 10:56

1 Answer 1

0

You can bubble up the click event from your child to your parent by using EventEmitter:

clickEmitter = new EventEmitter();

clickEmitter.emit();

<your-child-component (clickEmitter)="functionInParent()"></your-child-component>

Edit: If you want to reach your child component as per your comment: <dynamic-html>-<mvc-partial>-<razor> you can reference the components using the hashtag (#) and name of the hashtag or by the component name

@ViewChild(MvcPartialComponent) mvcPartialComponent: MvcPartialComponent;

<mvc-partial #mvc-partial></mvc-partial>
@ViewChild('mvc-partial') mvcPartialComponent: MvcPartialComponent;

etc etc.

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

9 Comments

unable to do it for the above scenario. cause flow is <dynamic-html>-<mvc-partial>-<razor> button is in dynamic-html and function should be called in razor
Then you can just set a reference on the components and call the function directly. See my updated answer
yea. but the thing is my button is in dynamic-html I'm handling it in respective DynamicComponent so reference of MvcPartialComponent could n't work out. Parentrazor-Childmvc-partial-subChild(DynamicComponent)dynamic-html
You can just create a named and check if it's defined <my-component #MyComponent>. i really don't see what the problem is.
Let me try.If you see my RenderingViewDynamic I'm getting Index.cshtml from mvc which contains <button (click)="buttonPress"> assigning to this.html and creating a DynamicComponent.ts as selector: 'dynamic-html',template: this.html class DynamicComponent buttonPress(){ console.log("In dynamic")}. now inside buttonPress() I need to communicate with razor.ts
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.