2

Abstract class:

export abstract class LanguageChangeAware {

    private sub: Subscription;
    protected language: string;

    protected constructor(protected eventService: EventService) {
        this.sub = eventService.getLang().subscribe(lang => {
            this.language = lang;
            this.load();
        });

        this.load();
    }

    protected ngOnDestroy(): void {
        this.sub.unsubscribe();
    }

    protected abstract load();
}

Component NewsPage implements LanguageChangeAware abstract class:

export class NewsPage extends LanguageChangeAware {

    public news: Array<NewsItem>;

    constructor(public newsService: NewsService, protected eventService: EventService) {
        super(eventService);
    }

    protected load() {
        console.log('NewsPage - load() - ', this.newsService); // <- undefined

        this.newsService.getNewsItemsList().then(data => {
            this.news = data;
        });
    }
}

My problem is that in the load() implementation of the NewsPage component, the injected dependency NewsService is undefined.


One possible solution, suggested by user Antoine Boisier-Michaud, was to make the subscription inside the ngOnInit method.

Updated version of LanguageChangeAware:

export abstract class LanguageChangeAware implements OnInit, OnDestroy {

    private sub: Subscription;
    protected language: string;

    protected constructor(protected eventService: EventService) {
    }

    public ngOnInit(): void {
        this.sub = this.eventService.getLang().subscribe(lang => {
            this.language = lang;
            this.load();
        });

        this.load();
    }

    public ngOnDestroy(): void {
        this.sub.unsubscribe();
    }

    protected abstract load();

}
francosang
  • 23
  • 7
  • I believe you have to do your subscription inside an ngOnInit method. – Antoine Boisier-Michaud Dec 01 '18 at 19:18
  • `super` is called before any assignments. https://www.typescriptlang.org/play/index.html#src=export%20class%20NewsPage%20extends%20LanguageChangeAware%20%7B%0D%0A%0D%0A%20%20%20%20constructor(public%20newsService%3A%20NewsService%2C%20protected%20eventService%3A%20EventService)%20%7B%0D%0A%20%20%20%20%20%20%20%20super(eventService)%3B%0D%0A%20%20%20%20%7D%0D%0A%7D – yurzui Dec 01 '18 at 19:28
  • @yurzui that seems logic, I did not realised that. Useful insight. – francosang Dec 01 '18 at 19:41
  • 1
    @AntoineBoisier-Michaud tried your suggestion. It worked as expected. Thank you. – francosang Dec 01 '18 at 19:42

1 Answers1

1

The constructor should be used for initializing class members and for dependency injection. If you have initialization stuff you need to do, you should use the ngOnInit method. When ngOnInit is called, you know all the dependencies have been resolved.

export abstract class LanguageChangeAware implements OnInit {

    private sub: Subscription;
    protected language: string;

    constructor(protected eventService: EventService) { }

    protected ngOnInit(): void {
        this.sub = eventService.getLang().subscribe(lang => {
            this.language = lang;
            this.load();
        });

        this.load();
    }

    protected ngOnDestroy(): void {
        this.sub.unsubscribe();
    }

    protected abstract load();
}

You can read angular's documentation on lifecycles if you want to learn more about OnInit and other lifecycle hooks.

You can also read this article which discusses when to use OnInit and the constructor more specifically.

Antoine Boisier-Michaud
  • 1,232
  • 2
  • 13
  • 24