简体   繁体   English

简单的Javascript作为Angular 2服务

[英]Plain Javascript as Angular 2 service

I need to add a hosted third-party JavaScript file in an Angular 2 component. 我需要在Angular 2组件中添加托管的第三方JavaScript文件。 This file is updated anytime a change is made in the associated third-party vendors proprietary system, so I cannot simply pull down a copy, include it locally, and import it into the project. 在相关的第三方供应商专有系统中进行更改时,此文件会随时更新,因此我不能简单地下载副本,将其包含在本地,然后将其导入项目中。

Typically I would include this file at a top level in a script tag, and then simply use declare <windowvar>: any to get access to it. 通常我会将此文件包含在脚本标记的顶层,然后只需使用declare <windowvar>: any来访问它。 However in this case, since the component itself is trying to load the script, I cannot declare the window variable because it does not exist on the window object at the time the component is loaded, which generates an error. 但是在这种情况下,由于组件本身正在尝试加载脚本,因此我无法声明窗口变量,因为它在加载组件时不存在于窗口对象上,这会产生错误。

I can load the script by manually adding a script tag, and that works, however I need access to the window variable it creates in order to use it properly. 我可以通过手动添加脚本标记来加载脚本,这样可行,但是我需要访问它创建的窗口变量才能正确使用它。 And I cannot simply use an interval to look for it because typescript throws a fit that <windowvariable> does not exist on object window . 而且我不能简单地使用一个间隔来查找它,因为typescript会抛出一个<windowvariable> does not exist on object window的拟合。

Is there any way I can 1) Load the hosted JavaScript file inside the component, and 2) Get access to the window variable created by the loaded JavaScript file? 我有什么方法可以1)在托管组件中加载托管的JavaScript文件,2)获取由加载的JavaScript文件创建的窗口变量的访问权限?

Update 1: Based on the comments, the previous solution will be not help you. 更新1:根据评论,以前的解决方案将无法帮助您。

You can do that by using OpaqueToken in Angular2 你可以在Angular2中使用OpaqueToken来做到这一点

1 . 1 Create a Token that is used to find an instance as below in a separate ts file. 在单独的ts文件中创建用于在下面查找实例的令牌。

import { OpaqueToken } from '@angular/core'

export let name_of_The_Token = new OpaqueToken('name_Of_The_Window_Object');

2. In your App.module , you need to import and declare a variable that is the name of your window object which makes the Token as a angular2 service so that you can use properties, methods in that javascript file across your components. 2.App.module中 ,您需要导入并声明一个变量该变量是窗口对象的名称,它使Token成为angular2服务,以便您可以在组件中使用该javascript文件中的属性和方法。

import { name_of_The_Token } from '/* file_Path */';
declare let name_Of_The_Window_Object : any;  //below your import statements

Step 3: Inject it to providers array of your module. 第3步:将其注入模块的提供者数组。

{ provide : name_of_The_Token , useValue : name_Of_The_Window_Object }

Guidance to use this token in components 在组件中使用此令牌的指南

  1. Import the token just like any other service and @Inject from angular-core 像任何其他服务一样导入令牌,并从angular-core导入@Inject

      import { name_of_The_Token } from '/* file_Path */'; import { Inject } from '@angular/core'; 
  2. In constructor of the component 在组件的构造函数中

      constructor(@Inject( name_of_The_Token ) private _serviceObject : any ) 
  3. Any where in your component you can use the variables and methods of your javascript file as 组件中的任何位置都可以使用javascript文件的变量和方法

      this._serviceObject.method1() this._serviceObject.variable1 ..... 

Note : One drawback is that you will not get intellisense . 注意 :一个缺点是你不会得到intellisense

Overcoming it: If you are looking for intellisense you need to wrap the methods and variables inside an interface and use it in the type**(instead of any)** of your token as 克服它:如果你正在寻找intellisense,你需要将方法和变量包装在一个接口中 ,并在你的令牌的类型**(而不是任何)**中使用它

export interface myCustom {
      method1(args): return_Type;
      method2(args): void;
      .....
   }

LIVE DEMO of ToasterService ToasterService的现场演示

Effectively, you're trying to pick up a "global module" javascript library from a CDN. 实际上,您正在尝试从CDN中选择一个“全局模块”javascript库。 (I assume the 3rd-party lib is not in CommonJS, AMD, UMD, or other module format, since it is accessed through a sole global variable.) (我假设第三方lib不是CommonJS,AMD,UMD或其他模块格式,因为它是通过唯一的全局变量访问的。)

So the first question is where is the corresponding .d.ts file? 那么第一个问题是相应的.d.ts文件在哪里? It contains the names and interfaces that inform Typescript of the 'shape' of the library, as well as declaring that global variable will exist. 它包含通知Typescript的库的“形状”的名称和接口,以及声明全局变量将存在的名称和接口。 If your 3rd-party doesn't provide it you'll need to write it yourself. 如果您的第三方不提供,您需要自己编写。 It will contain not just the declaration of the global var, like 它不仅包含全局变量的声明,例如

declare var theGlobalVarInQuestion: IInterfaceOfStuffInsideLibrary;

but also the declaration of said Interface, and its properties and their types, all the way down. 而且所述接口的声明,它的属性和它们的类型,一直向下。 Like this: https://github.com/catamphetamine/libphonenumber-js/blob/master/index.d.ts 像这样: https//github.com/catamphetamine/libphonenumber-js/blob/master/index.d.ts

You can include the .d.ts file in /node_modules/@types/nameOfSaidLibrary but you'd need to check it into your source repo (with possible .gitignore gymnastics) especially because a npm prune will remove it. 您可以在/ node_modules / @ types / nameOfSaidLibrary中包含.d.ts文件,但是您需要将其检入源回购(可能的.gitignore体操),特别是因为npm prune将删除它。 Or if you put it elsewhere, modify the tsconfig.json typeroots property to look in both that place in addition to its usual /node_modules/@types/ folder. 或者如果你把它放在别处,修改tsconfig.json typeroots属性,除了它的通常的/ node_modules / @ types /文件夹之外,还要查看那个地方。

Just to be clear, the .d.ts file doesn't (and shouldn't) actually create the variable; 为了清楚起见,.d.ts文件不会(也不应该)实际创建变量; it just states that it will be there so the Typescript compiler won't complain. 它只是声明它会在那里,所以Typescript编译器不会抱怨。 Whether or not it is there at runtime is decided by however you're loading the js. 无论它是否在运行时都是由你加载js决定的。

If you're not loading it via script tag in the index.html, then either a Typescript import statement in the consuming component can do so (given the right config of SystemJS or whatever you're using) or the consuming component can dynamically create and append a new script tag to the index.html. 如果你没有通过index.html中的script标签加载它,那么消费组件中的Typescript import语句可以这样做(给定SystemJS的正确配置或你正在使用的任何东西),或者消费组件可以动态创建并将新脚本标记附加到index.html。 Just make sure your module loader isn't trying to download and immediately bundle it with the rest of your app at buildtime. 只需确保您的模块加载程序没有尝试下载,并立即将其与构建时的其余应用程序捆绑在一起。 It sounds like you want the lib to be downloaded anew each time at runtime. 听起来您希望每次在运行时重新下载lib。

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

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