Angular 2.3. Inheritance of components and dependence on injection

How can I share dependency injection between child and parent components with the new Angular.

eg. I want to move the AlertService to the parent component and leave the TraingCompanyService in the derived component

Current component

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

Reorganized Components (V1)

Super need to be called before calling this in the constructor of the derived class

 @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); } } } } 

Reorganized Components (V2)

The TrainingCompanyEditComponent class incorrectly extends the base class BaseAdminEditComponent, types have separate private property warning declarations'

 @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); } } } } 

Reorganized Components (V3)

It works, just wondering if this is the best method.

 @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, eg 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); } } } } 
+5
source share
3 answers

I finally developed a template that works, it is important not to use the private (suger syntax template) that Radim mentions in the constructors.

I made the warning service a protected property in the base class.

And it's important to associate the base event handler with this handlerSaveError.bind(this)

The final working code is here.

Base class

 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); } } } 

Component Instance Class

 @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 } } 
+4
source

Just set the constructor parameter access modifier in the derived class at the same level as in the base class. i.e.

Base class

 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); } } } 

Derived class

 @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 } } 
+4
source

Defining a constructor with such modifier keywords

 export class TrainingCompanyEditComponent extends BaseAdminEditComponent implements OnInit, OnDestroy { constructor( private alert: AlertService, private trainingCompanyService: TrainingCompanyService ) { } ... 

is just syntactic sugar for more verbose:

 export class TrainingCompanyEditComponent extends BaseAdminEditComponent implements OnInit, OnDestroy { private alert: AlertService, private trainingCompanyService: TrainingCompanyService constructor( alert: AlertService, trainingCompanyService: TrainingCompanyService ) { this.alert = alert; // assign incoming value to member this.trainingCompanyService = trainingCompanyService; } ... 

So this is in the background. And we can do this task only after the super was called. Therefore, we must change the call using this.alert (member access) in alert (passing the incoming value)

  constructor( private alert: AlertService, private trainingCompanyService: TrainingCompanyService ) { //super(this.alert); super(alert); // this.alert was not assign yet // next ? // the this.alert will be assigned for us... } 

Play with this adjusted definition here.

+2
source

Source: https://habr.com/ru/post/1262551/


All Articles