简体   繁体   English

Angular 5-扩展了所有组件中的服务提供商注入

[英]Angular 5 - Service provider injection in all components with extends

I'm kinda new with Angular and I'm trying to build my app around it, but I'm having some troubles when injecting services in my Components. 我对Angular有点陌生,我试图围绕它构建我的应用程序,但是在向我的组件中注入服务时遇到了一些麻烦。

I've added a 3rd party module with a service provider for translations in multiple languages on the fly, as it is kinda "hard" to do it manually, and a cookie service provider. 我添加了一个第三方服务模块和一个服务提供商,该服务提供商可以即时进行多种语言的翻译,因为手动操作有点“困难”,还提供了一个cookie服务提供商。 The main problem is that the translation is made during template compilation, so to achieve that for my component I have to use a code like this: 主要问题是翻译是在模板编译期间进行的,因此要实现对我的组件的转换,我必须使用如下代码:

<!-- language: typescript -->
import { Component, OnInit } from '@angular/core';

import { TranslateService } from '@ngx-translate/core';
import { CookieService } from 'ngx-cookie-service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  language: string;

  constructor(
    private translateService: TranslateService,
    private cookieService: CookieService) { }

  ngOnInit() {
    this.language = this.cookieService.get('lang') || 'en';
    this.translator.use(this.language);
  }

}

The main problem is that I have to pass those service providers everytime in the constructor function in every component, which is very repetitive. 主要问题是我必须每次在每个组件的构造函数中传递那些服务提供者,这非常重复。 To prevent that, I've tried to create an abstract class then extend it in my components as a base component. 为避免这种情况,我尝试创建一个abstract class然后将其作为基本组件扩展到我的组件中。 Something like this: 像这样:

<!-- language: typescript -->

import { Injectable, OnInit } from '@angular/core';

import { TranslateService } from '@ngx-translate/core';
import { CookieService } from 'ngx-cookie-service';

@Injectable()
export abstract class DefaultComponent implements OnInit {

  language: string;

  constructor(private translator: TranslateService, private cookieService: CookieService) {
    this.language = this.cookieService.get('lang') || 'es';
    this.translator.use(this.language);
  }

  ngOnInit() {
    // 
  }

}

<!-- language: typescript -->
import { Component } from '@angular/core';

import { DefaultComponent } from '../default.component';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent extends DefaultComponent {

  ngOnInit() {
    // Everything here replaces the ngOnInit from parent
  }

}

This solution works for many of my components, but I have one component called PostsComponent that uses a specific service provider to handle Posts . 该解决方案适用于我的许多组件,但是我有一个名为PostsComponent组件,该组件使用特定的服务提供商来处理Posts This is the code: 这是代码:

<!-- language: typescript -->
import { Component } from '@angular/core';

import { DefaultComponent } from '../default.component';

import { Post } from '../../models/post';
import { PostService } from '../../services/post/post.service';

@Component({
  selector: 'app-posts',
  templateUrl: './posts.component.html',
  styleUrls: ['./posts.component.css'],
  providers: [ PostService ]
})
export class PostsComponent extends DefaultComponent {

  posts: Post[];

  constructor(private postService: PostService) { }

  ngOnInit() {
    this.getPosts();
  }

  getPosts(): void {
    this.postService.getPosts().subscribe(posts => this.posts = posts);
  }

}

If I use the constructor function for that component to use service provider, the parent constructor is overriden. 如果我为该组件使用构造函数以使用服务提供程序,则将重写父构造函数。 To prevent that, I should call to super() function in the constructor function, but I will have to send the TranslateService and CookieService to that function in order to make it work everything. 为了避免这种情况,我应该在构造函数中调用super()函数,但是我必须将TranslateServiceCookieService发送到该函数,以使其能够正常工作。 As I said in the beginning, this is repetitive and I do not like that so much. 正如我在开始时所说的,这是重复性的,我不太喜欢。

How can I achieve to load those common services for every component and still allowing to use specific services for specific components? 如何实现为每个组件加载那些通用服务,同时仍然允许对特定组件使用特定服务? I don't think setting up those common services as global variables is a good practice. 我认为将这些通用服务设置为全局变量不是一个好习惯。 Correct me if I'm wrong. 如果我错了纠正我。

Thanks for your time. 谢谢你的时间。

In order for child class to have additional dependencies, it should list parent's dependencies as well and pass them to super : 为了使子类具有其他依赖项,它还应该列出父项的依赖项并将它们传递给super

export class PostsComponent extends DefaultComponent {
  ...
  constructor(
    translator: TranslateService,
    cookieService: CookieService,
    private postService: PostService
  ) {
    super(translator, cookieService);
  }
  ...
}

Parent's dependencies should have no visibility modifier because they are already assigned to instance in parent constructor. 父级的依赖项应该没有可见性修饰符,因为它们已在父级构造函数中分配给实例。

In case there are many dependencies, parent class can be refactored to use Injector in constructor to get them, Injector will be the only dependency that needs to be passed to super . 如果存在许多依赖关系,则可以将父类重构为在构造函数中使用Injector来获取它们, Injector将是唯一需要传递给super依赖关系。 If there is a possibility that list of parent's dependencies will be extended in future, it may be reasonable to use Injector right away. 如果将来有可能扩展父级依赖项列表,则立即使用Injector是合理的。

There is no other good way around. 没有其他好的方法。 This boilerplate code is the price for trouble-free Angular experience. 此样板代码是无故障Angular体验的价格。 Any other way can currently be considered a hack. 目前可以将任何其他方式视为骇客。

There is always a chance that a list of parent dependencies is too big. 父项依赖项列表总是有可能太大。 In this case there will always be boilerplate code because a component should contain business logic for switching languages, while it's role is presentation logic (notice that language choice in ngOnInit makes it impossible to switch languages without component tree recompilation, which is potential design flaw). 在这种情况下,总会有样板代码,因为组件应包含用于切换语言的业务逻辑,而其角色是表示逻辑(请注意, ngOnInit中的语言选择使得在不重新编译组件树的情况下无法切换语言,这是潜在的设计缺陷) 。 It is preferable to merge TranslateService and CookieService into custom service that will be responsible for switching languages. 最好将TranslateServiceCookieService合并到负责切换语言的自定义服务中。 This is an application of composition over inheritance principle. 这是在继承原则上应用组合的一种方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM