【问题标题】:How to transform an AngularJS 1 service into an Angular 2 service?如何将 AngularJS 1 服务转换为 Angular 2 服务?
【发布时间】:2017-08-15 14:52:43
【问题描述】:

我正在尝试在 Angular 2 环境中重用用纯 JavaScript 编写的 AngularJS 1 服务中的一些工作代码。

例如,服务看起来像以下示例:

(function () {
    angular.module('myapp.mysubmodule').factory('myappMysubmoduleNormalService', ['someOtherService',
        function (someOtherService) {
            var internalState = {
                someNumber: 0
            };
            var service = {};

            service.someFunction = function () {
                internalState.someNumber++;
            };

            someOtherService.getValues().forEach(function (v) {
                service[v] = function () {
                    console.log(v + internalState.someNumber);
                };
            });

            return service;
        }]);
})();

我找到了各种如何将 AngularJS 1 服务转换为 Angular 2 服务的示例(例如 this one),所有这些都有一个共同点,即我必须导出一个类,而不是服务工厂。

这个应该大致如下:

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

@Injectable()
export class myappMysubmoduleNormalService {
    someFunction: function () {
        // ?
    }
}

现在,问题是如何合并内部状态和动态添加的属性。 这真的是在构造函数中完成所有这些的方法吗,即在初始化时填充类的每个实例,如下所示:

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

@Injectable()
export class myappMysubmoduleNormalService {
    constructor() {
        var internalState = {
            someNumber: 0
        };
        var service = {};

        this.someFunction = function () {
            internalState.someNumber++;
        };

        this.getValues().forEach(function (v) {
            service[v] = function () {
                console.log(v + internalState.someNumber);
            };
        });
    }
}

或者还有其他方法吗?以上可能有效(除了缺少依赖注入,我仍然需要了解如何在 Angular 2 中执行此操作)。但是,我想知道这是否是一个好方法,因为我没有遇到任何在其构造函数中进行大量成员初始化的示例。

【问题讨论】:

  • 您的问题不是关于如何以角度创建服务,您的问题是“我应该如何管理角度状态?”。有很多选项供您选择。
  • @ChrisG:嗯,也许问题是如何在 Angular 中创建有状态服务(其 API 仍然与其 AngularJS 1 等效,因为我想避免更改我依赖的服务中的代码我也停下来)。
  • 你可以在 JS 中做任何你想做的事情。我认为您的问题之所以出现是因为您使用的是 TypeScript,并且它正在强制声明您的属性,这不是您现在处理它的方式。 IMO 最好在您的对象上声明属性(这就是您首先需要 TS 的原因),但是您可以通过转换为 any(不推荐)来绕过 TS 编译器。
  • @ChrisG:哦,我没有使用 TypeScript。我正在使用纯 JavaScript。许多 Angular 2 示例都使用 TypeScript;事实上,太多了,以至于我有时甚至不确定哪些部分是 Angular 2 特有的,哪些是 TypeScript 特有的。
  • 如果您使用的是 JS,那么一切都应该按预期工作。您可以在构造函数中利用 DI

标签: javascript angular


【解决方案1】:

您可以在 Angular 中使用与 factory providers 相同的方法:

  export function someServiceFactory(someOtherService) {
    var internalState = {
      someNumber: 0
    };
    var service = {};

    service.someFunction = function () {
      internalState.someNumber++;
    };

    someOtherService.getValues().forEach(function (v) {
      service[v] = function () {
        console.log(v + internalState.someNumber);
      };
    });

    return service;
  };

@NgModule({
  providers: [
    {
      token: 'myappMysubmoduleNormalService',
      useFactory: someServiceFactory,
      deps: ['someOtherService']
    }
  ]
})

在 Angular 和 AngularJS 中,工厂函数返回的值都会被缓存。

【讨论】:

  • 这看起来很有希望 - 但是有什么理由我必须导出工厂函数,而不是仅仅为 useFactory 属性内联声明它?为了避免包含多个服务的源文件过长,因为我必须在 providers 数组中列出所有这些服务?
  • 嗯,Chrome 还抱怨“意外的令牌导出”。经过进一步研究,似乎these keywords are not yet supported by browsers。虽然链接的问题建议使用转译器的解决方案,但有没有任何方法可以在没有任何此类额外工具的情况下解决该问题?
  • AOT编译需要定义函数otside descriptor。如果不需要AOT,可以内联。不需要导出
  • 最后,我从 AngularJS 1.x 重新实现了服务注入逻辑,并为一些 Angular 2 服务创建了包装器,以模仿 AngularJS 1.x 服务,例如 $q、$http 和 $超时。这样,我不必更改现有代码库中的任何内容。
【解决方案2】:

服务只是一个可以注入组件的类。它将在命名为提供者的范围内创建一个单例。

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

@Injectable()
export class myappMysubmoduleNormalService implements OnInit {
internalState: number;

 constructor() {}

ngOnInit(){

    this.internalState = 0;
}

incrementSomeNumber() {
  this.internalState++;
  console.log(this.internalState};
}


}

我意识到这不是为多个函数记录不同的内部状态,但你明白了。

将此注册为 app.module 中的提供者(如果您想要应用范围的单例)

当你导入一个组件然后注入到构造函数中时

constructor(private _myservice : myappMysubmoduleNormalService) {}

您现在可以使用 _myservice 方法

myNumber : number = 0 ;

componentFunction() {
     _myservice.incrementSomeNumber();
     this.myNumber = _myservice.internalState;
}

当然,您可以让服务方法返回递增的数字(或数据或数据的承诺)

这很粗略,但给了你想法。很少有代码属于构造函数。应该注入一个服务。组件构造函数中显示的内容是引用服务的获取私有变量的简写。该服务将是提供它的范围内的单例。 (可以在范围内被覆盖,但这对我来说似乎是一种代码味道)

传回一个值:

服务中

 incrementSomeNumber(): number {
 this._internalState++;
  console.log(this._internalState};
 return this._internalState;
 }

在组件中: 我的号码:号码;

componentFunction() {
    this.mynumber = _myservice.incrementSomeNumber();
}

不确定您要完成什么,但只是想展示从服务获取信息的示例。对我来说,最常见的服务使用是数据服务,所以代码会稍微复杂一些,因为它是异步的。

【讨论】:

  • 在这个解决方案中,internalState 似乎对外部可见。这是我想避免的。
  • 查看对原始答案的补充,显示传回一个值而不是公开服务的属性。
猜你喜欢
  • 2021-06-22
  • 1970-01-01
  • 1970-01-01
  • 2017-11-14
  • 1970-01-01
  • 2013-11-07
  • 1970-01-01
  • 2017-08-24
  • 2012-12-05
相关资源
最近更新 更多