【问题标题】:Making moment injectable in angular2使 angular2 中的矩可注入
【发布时间】:2017-02-08 08:58:56
【问题描述】:

我想在我的应用程序中创造出可注入的时刻。
我刚开始学习 ng2,在文档中找不到这种用法。
这是我在app.module.ts 中的内容:

import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {HttpModule} from '@angular/http';
import {AppComponent} from './app.component';
import * as moment from 'moment';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [{provide: 'moment', useValue: moment}],
  bootstrap: [AppComponent]
})
export class AppModule {
}

这里是组件:

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.sass']
})


export class AppComponent {
  title = 'app works!';

  constructor(private moment) {
    this.title += this.moment;
  }
}

有这个错误:

Uncaught Error: Can't resolve all parameters for AppComponent:

这应该如何正确完成?

更新模块

const moment = new OpaqueToken('moment');

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    HttpModule
  ],
  providers: [{provide: moment, useValue: moment}],
  bootstrap: [AppComponent]
})

export class AppModule {
}

更新的组件

import { Component } from '@angular/core';
import * as moment from 'moment';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.sass']
})


export class AppComponent {
  title = 'app works!';

  constructor(private moment: moment) {
    this.title += this.moment()
  }
}

constructor(private moment: moment) 这一行有一个错误提示:Cannot find name 'moment'.

【问题讨论】:

  • 你经历过this answer吗?
  • 不相关。我不想通过导入使用它。我希望能够在任何课程中注入它
  • 你在使用angular-cli吗?
  • 是的,我正在使用 cli
  • 为什么要通过构造函数注入呢?是什么原因?

标签: angularjs angular


【解决方案1】:

您需要使用OpaqueToken,这将允许您创建基于字符串的令牌。我只是建议您更改 moment 的名称以避免与库的 moment 变量发生冲突。

// You can place this is some file, so that you can export it.
export const Moment = new OpaqueToken('moment');

然后你可以使用

providers: [{provide: MomentStatic, useClass: moment}],

您可以通过this article了解更多详情

使用依赖时,将其包含在组件构造函数中。

constructor(private moment: MomentStatic)

【讨论】:

  • 我遇到了同样的错误。我可能错过了注射部分。您能否将其添加到您的答案中(在构造函数中注入时刻)?
  • 这在 A2 中很明显
  • 这正是我所做的,但很少有问题和问题。我已经像这样导入了时刻(在组件文件中):import * as moment from 'moment'; 但我收到此错误:Cannot find name 'moment'. 在这一行:constructor(private moment: moment)(请参阅更新的问题以查看完整的组件(更新中)
  • 你在system.config.js中添加了map
  • 我正在使用 angular-cli。不需要对 systemjs 配置进行任何更改。时刻在全球范围内可用。
【解决方案2】:

Moment 不必注入,它是一个您可以“直接使用”的库。将其导入您的打字稿文件就足够了,现在您可以使用 moment 的功能了。

【讨论】:

  • 我想让它可注射。这就是这个问题的想法。
  • 好吧,我就是不明白你为什么要这么做
  • Moment 可以直接使用,不需要注入。它不是 Angular 2 服务。您可以做的是创建 Angular 2 服务并在其中包含 moment 的方法,或者您需要的方法。然后你可以将该服务注入到你的组件中。
  • 我想让它可注射。这就是这个问题的想法
  • 您可能希望使第三方库可注入,以便在测试组件时传入存根。这是注入它的原因之一。
【解决方案3】:

Moment 本身并不是 Angular2 的可注入对象。但是它可以被包裹在一个里面。

Plunker Demo

moment.service.ts

import { Injectable } from '@angular/core';
import * as m from 'moment';
@Injectable()
export class MomentService {
    moment = m;
}

app.module.ts

import { MomentService } from './moment.service';

@NgModule({
    providers: [MomentService]
    ...

app.component.ts

import { MomentService } from './moment.service';

export class AppComponent {
    constructor(private ms: MomentService){
        console.log('Moment:' + this.ms.moment("20111031", "YYYYMMDD").toString());
    }
}

不完美,但有效。

【讨论】:

  • 这是处理这个问题的好方法。但我希望有一种方法可以在没有包装服务的情况下做到这一点。与我们在 ng1 中使用常量的方式相同。
  • @vlio20 这实际上是 Angular 2 做全局变量的方式,通过可注入的服务公共属性/变量。查看我的ng2-simple-global 服务,readme.md 中有一个 plunker 链接。 moment 这里是全局变量
【解决方案4】:

如果您正在加载 moment.js 以便它在全球范围内可用,那么如何将它与一个服务包装起来,然后您可以将其注入整个应用程序?

import {Moment} from '../../node_modules/moment';

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

declare var moment: any;

@Injectable()
export class MomentService {
    constructor() { }

    get(): Moment {
        return moment;
    }
}

通过这种方式,您在编码时获得 TS IntelliSense(至少我在 VSCode 中这样做),并且您也可以轻松处理模拟时刻以进行测试。

【讨论】:

    【解决方案5】:

    我找到的最佳解决方法是创建一个包装服务,但也使用 getter 直接在服务本身上公开一些最常用的方法:

    import { Injectable } from '@angular/core';
    import * as moment from 'moment';
    
    /**
     * A wrapper for the moment library
     */
    @Injectable()
    export class MomentService {
      /**
       * Creates and returns a new moment object with the current date/time
       */
      public moment() { return moment(); }
    
      // expose moment properties directly on the service
      public get utc() { return moment.utc; }
      public get version() { return moment.version; }
      public get unix() { return moment.unix; }
      public get isMoment() { return moment.isMoment; }
      public get isDate() { return moment.isDate; }
      public get isDuration() { return moment.isDuration; }
      public get now() { return moment.now; }
    }
    

    【讨论】:

      【解决方案6】:

      现在不确定这是否有帮助,但您需要与以下类似(未经测试)的东西才能使其在您的服务中工作。

      import { Inject } from '@angular/core';
      
      constructor(@Inject(moment) private moment) {
          this.title += this.moment()
        }
      

      关键位是 @Inject

      【讨论】:

        猜你喜欢
        • 2017-01-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-20
        • 1970-01-01
        • 1970-01-01
        • 2023-03-29
        相关资源
        最近更新 更多