Angular 2.3组件继承和依赖注入

Dav*_*wys 8 typescript angular

如何使用新的Angular 2.3组件继承在子组件和父组件之间共享依赖项注入.

例如,我想将AlertService向下移动到父组件中,并将TraingCompanyService保留在派生组件中

当前组件

@Component({
    selector: 'wk-training-company-edit',
    template: require('./edit.html')
})
export class TrainingCompanyEditComponent implements OnInit, OnDestroy {

    constructor(
                private alert: AlertService,
                private trainingCompanyService: TrainingCompanyService
                ) {

    }
}
Run Code Online (Sandbox Code Playgroud)

重构组件(V1)

必须在派生类的构造函数中调用它之前调用Super

@Component({
    selector: 'wk-training-company-edit',
    template: require('./edit.html')
})
export class TrainingCompanyEditComponent extends BaseAdminEditComponent implements OnInit, OnDestroy {

    constructor(
                private alert: AlertService,
                private trainingCompanyService: TrainingCompanyService
                ) {

        // Error: Super must be called before calling this in the constructor of the derived class
        super(this.alert);
    }
}

export class BaseAdminEditComponent {

    constructor(private alert: AlertService) {
    }

    protected handleSaveError(error: any) {

        if (error.message) {
            if (error.errors && _.isArray(error.errors) && error.errors.length > 0) {
                this.alert.error(_.join(error.errors, '\n'), error.message);
            }
            else {
                this.alert.error(error.message);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

重构组件(V2)

类TrainingCompanyEditComponent错误地扩展基类BaseAdminEditComponent,类型具有私有属性'alert'的单独声明

@Component({
    selector: 'wk-training-company-edit',
    template: require('./edit.html')
})
export class TrainingCompanyEditComponent extends BaseAdminEditComponent implements OnInit, OnDestroy {

    // Class TrainingCompanyEditComponent incorrectly extends base class BaseAdminEditComponent, types have seperate declarations of private property 'alert'
    constructor(
                private alert: AlertService,
                private trainingCompanyService: TrainingCompanyService
                ) {

        // alert instead of this.alert
        super(alert);
    }
}

export class BaseAdminEditComponent {

    constructor(private alert: AlertService) {
    }

    protected handleSaveError(error: any) {

        if (error.message) {
            if (error.errors && _.isArray(error.errors) && error.errors.length > 0) {
                this.alert.error(_.join(error.errors, '\n'), error.message);
            }
            else {
                this.alert.error(error.message);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

重构组件(V3)

这很有效,只是想知道它是否是最好的技术

@Component({
    selector: 'wk-training-company-edit',
    template: require('./edit.html')
})
export class TrainingCompanyEditComponent extends BaseAdminEditComponent implements OnInit, OnDestroy {

    // Class TrainingCompanyEditComponent incorrectly extends base class BaseAdminEditComponent, types have seperate declarations of private property 'alert'
    constructor(
                private alert: AlertService,
                private trainingCompanyService: TrainingCompanyService
                ) {

        // alert instead of this.alert
        super(alert);
    }
}

export class BaseAdminEditComponent {

    // Create a private variable with a different name, e.g. alert2
    private alert2: AlertService;

    constructor(alert: AlertService) {
        this.alert2 = alert;
    }

    protected handleSaveError(error: any) {

        if (error.message) {
            if (error.errors && _.isArray(error.errors) && error.errors.length > 0) {
                this.alert2.error(_.join(error.errors, '\n'), error.message);
            }
            else {
                this.alert2.error(error.message);
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

小智 9

只需将派生类中构造函数参数的访问修饰符设置为与基类中相同的级别.即

基类

import * as _ from "lodash";

import {AlertService} from '../common/alert/alert.service';

export class BaseAdminEditComponent {

    constructor(protected alert: AlertService) { }

    protected handleSaveError(error: any) {

        if (error.message) {
            if (error.errors && _.isArray(error.errors)) {
                console.error(error.errors);
            }
            this.alert.error(error.message);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

派生类

@Component({
    selector: 'wk-training-company-edit',
    template: require('./edit.html')
})
export class TrainingCompanyEditComponent extends BaseAdminEditComponent {

    trainingCompany: TrainingCompany;

    trainingCompanyId: number;

    constructor(
        protected alert: AlertService,
        private validation: ValidationService,
        private trainingCompanyService: TrainingCompanyService) {

        super(alert);

        // Other Constructor Code Here
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这增加了什么?未在接受的答案中涵盖? (3认同)

Dav*_*wys 8

我终于找到了有效的模式,重要的是不要使用Radim在构造函数中提到的私有(语法模式).

我使警报服务成为基类的受保护属性.

将基本事件处理程序绑定到此是很重要的 handlerSaveError.bind(this)

最终的工作代码在这里.

基类

import * as _ from "lodash";

import {AlertService} from '../common/alert/alert.service';

export class BaseAdminEditComponent {

    protected alert: AlertService;

    constructor(alert: AlertService) {
        this.alert = alert;
    }

    protected handleSaveError(error: any) {

        if (error.message) {
            if (error.errors && _.isArray(error.errors)) {
                console.error(error.errors);
            }
            this.alert.error(error.message);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

组件实例类

@Component({
    selector: 'wk-training-company-edit',
    template: require('./edit.html')
})
export class TrainingCompanyEditComponent extends BaseAdminEditComponent {

    trainingCompany: TrainingCompany;

    trainingCompanyId: number;

    constructor(alert: AlertService, // Don't use private property
                private validation: ValidationService,
                private trainingCompanyService: TrainingCompanyService) {

        super(alert);

        // Other Constructor Code Here
    }

    onSave($event) {

        console.log('Save TrainingCompany');

        this.trainingCompany = TrainingCompany.fromJson(this.form.value);

        console.log(JSON.stringify(this.trainingCompany, null, 2));

        var isNew = _.isNil(this.trainingCompany.id);

        this.trainingCompanyService
            .upsert$(this.trainingCompany)
            .subscribe((response: EntityResponse<TrainingCompany>) => {

                try {
                    this.alert.success('TrainingCompany updated');

                    this.modelChange.fire('training-company', isNew ? 'new' : 'update', this.trainingCompany);
                }
                catch (e) {
                    console.error(e);
                    throw e;
                }
            }, this.handleSaveError.bind(this)); // Common Error Handler from base class. NOTE: bind(this) is required

    }
}
Run Code Online (Sandbox Code Playgroud)