如何在子按钮中调用父函数

时间:2019-02-26 06:07:58

标签: html angular typescript

假设我有一个名为import Lst.Aux object Main { def main(args: Array[String]) = { } def makeList(l: Lst): List[l.Item] = { (0 until l.size map l.get).toList } } object Lst { type Aux[I] = Lst {type Item = I} } trait Lst extends Any { type Item def get(index: Int): Item } final case class StringLst(size: Integer) extends AnyVal with Lst { type Item = Char def get(index: Int) = ??? } 的组件,该组件将在应用程序的各个位置使用,所以我使它尽可能通用,就像这样:

button.component.ts

ButtonComponent

button.component.html

import { Component, ViewEncapsulation, Input, Output, EventEmitter } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Component({
  selector: 'app-button',
  templateUrl: './button.component.html',
  styleUrls: ['./button.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class ButtonComponent{

  @Input() group: FormGroup;
  @Input() type: string;
  @Input() description: string;
  @Input() class: string;
  @Input() callFunction: Function;
}

现在我的按钮是完全可定制的(理论上)。现在,我将其导入到一个名为<div [formGroup]="group"> <button type="{{ type }}" class="{{ class }}" (click)="callFunction()">{{ description }}</button> </div> 的登录组件中。我希望我的按钮实例在单击时运行此特定功能:

login.component.ts

login()

要使按钮实例可见,我将引用添加到我的登录模板中,如下所示:

//imports

/**
* This component is rendered at the start of application, it provides the UI
* & functionality for the login page.
*/
@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})

/**
* This class is used to build a login form along with initialization of validators
* as well as authenticate the user, and reroute upon success
*/
export class LoginComponent implements OnInit, AfterContentInit{

  @ViewChild('login', { read: ViewContainerRef }) login_button;


  /**
  * This property initializes the formGroup element.
  */
  userForm: FormGroup;

  /**
  * The constructor initializes Router, FormBuilder, OauthService, LoggerService, ToastrService
  * & TranslatePipe in the component.
  */
  constructor(//initializations
  ) { }

  /**
  * This is the hook called on the initialization of the component, it initializes
  * the form.
  */
  ngOnInit() {
    this.buildForm();
  }



  /**
   * This method initialized the the formGroup element. Its properties and the validators.
   *
   * @method buildForm
   * @return
   */
  buildForm() { 
    // validations
  });
  }

   /**
   * This method returns the values of the form controls.
   *
   * @return
   */
  get form() { return this.userForm.controls; }

   /**
   * This method is triggered on success, it reroutes the user to main page.
   *
   * @return
   */
  onSuccess() {
    let result = this.translate.transform("pages[login_page][responses][success]");
    this.logger.info(result);
    this.toastr.success(result);
    this.router.navigate(['main']);
  }

   /**
   * This method is triggered when user clicks log-in, it calls the aunthenication method
   * from oauth service.
   *
   * @return
   */
  login() {
    this.oauth.authenticateUser(this.form.username.value, this.form.password.value, this.onSuccess.bind(this));
  }

  ngAfterContentInit() { //here I build my login button instance after init
    this.buildLoginButton();
  }


  /**
  * This function builds the login button, imports the ButtonComponent
  *
  */
  buildLoginButton(){
    let data = {
      type: "button",
      class: "btn btn-primary px-4",
      description: this.translate.transform("pages[login_page][login_form][buttons][login]"),
      function: "login",
      group: this.userForm
      }
    const inputFactory = this.resolver.resolveComponentFactory(ButtonComponent);
    const loginButton = this.login_button.createComponent(inputFactory);
    loginButton.instance.group = data.group;
    loginButton.instance.type = data.type;
    loginButton.instance.class = data.class;
    loginButton.instance.description = data.description;
    loginButton.instance.callFunction = function(){ //I call parent function using a static method
      LoginComponent.executeMethod(data.function);
    }
  }


  static executeMethod(someMethod){ //for my login button this should return this.login()
    eval("this."+someMethod+"()");
  }

}

现在我的按钮可见了,太好了!但是现在当我单击按钮时:

  

错误TypeError:this.login不是函数       在eval时(在push ../ src / app / views / login / login.component.ts.LoginComponent.executeMethod   (login.component.ts:225)、: 1:6)       在Function.push ../ src / app / views / login / login.component.ts.LoginComponent.executeMethod中   (login.component.ts:225)       在ButtonComponent.loginButton.instance.callFunction(login.component.ts:179)       在Object.eval [作为handleEvent](ButtonComponent.html:2)       在handleEvent(core.js:10251)       在callWithDebugContext(core.js:11344)       在Object.debugHandleEvent [作为handleEvent](core.js:11047)       在dispatchEvent(core.js:7710)       在core.js:8154       在HTMLButtonElement。 (platform-b​​rowser.js:988)

如何使我的按钮在父组件中运行该函数,而不是在其自身内部查找该函数?我不想在<div #login></div> 中进行太多更改,以使其不那么通用,因为我还必须制作其他可能会运行其他功能的按钮。

有一个解决方案指出使用ButtonComponent来解决这个问题,但是由于我将按钮EventEmitter和{{1 }}

编辑完整的 login.component.html

ts

1 个答案:

答案 0 :(得分:4)

将此代码添加到button.component.ts

@Output() clickFunctionCalled = new EventEmitter<any>();
callFunction() {
    this.clickFunctionCalled.emit();   
  }

button.template.html中没有变化

在html中使用应用程序按钮组件的位置添加此代码

<app-button  (clickFunctionCalled)="callCustomClickFunction($event)"></app-button>

将其添加到login.component.ts

callCustomClickFunction() {
   console.log("custom click called in login");
   this.login();
}

基本上,从子组件发出click事件。在父组件中捕获事件并调用父组件的所需函数。 您也可以像这样直接调用父组件的函数

<app-button  (clickFunctionCalled)="login($event)"></app-button>

在使用动态组件创建器创建按钮组件时,需要执行以下操作来绑定输出事件

loginButton.instance.clickFunctionCalled.subscribe(data => {
    console.log(data);
});