Javascript 为什么Angular中基于jQuery令牌的集成不起作用?

Javascript 为什么Angular中基于jQuery令牌的集成不起作用?,javascript,jquery,angular,Javascript,Jquery,Angular,我正在尝试将jQuery作为服务集成到Angular 6应用程序中,我遵循了以下文章: 唯一的区别是,我的解决方案使用InjectionToken,而不是自Angular 4以来就被弃用的OpaqueToken 好,现在谈谈代码本身 在jQuery服务中,如果问题的根本原因似乎发生了,jqueryFactory将返回未定义的: AppModule:app.module.ts AppComponent:app.component.ts 及其相关模板:app.component.html 此处提供了

我正在尝试将jQuery作为服务集成到Angular 6应用程序中,我遵循了以下文章:

唯一的区别是,我的解决方案使用InjectionToken,而不是自Angular 4以来就被弃用的OpaqueToken

好,现在谈谈代码本身

在jQuery服务中,如果问题的根本原因似乎发生了,jqueryFactory将返回未定义的:

AppModule:app.module.ts

AppComponent:app.component.ts

及其相关模板:app.component.html

此处提供了此应用程序的示例:

[编辑]

正如user184994 github.com/StackBlitz/core/issues/407所指出的,潜在的问题似乎更多地是关于StackBlitz的

codesanbox上提供了一个工作示例:

**编辑**

我发现,通过将CDN链接的script标记移动到head标记中,剩下的代码就可以工作了。查看更多信息

**原始答案**


部分问题是工厂可能在页面完全加载之前创建,即在窗口['jQuery']存在之前

为了避免这种情况,您可以使用useValue而不是useFactory,并让您的服务充当一个工厂。我的意思是:

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

export const JQUERY_TOKEN = new InjectionToken('jQuery');

export function jqueryFactory() {
  return getJquery();
}

function getJquery() {
  return window['jQuery'];
}

export const JQUERY_SERVICE = { provide: JQUERY_TOKEN, useValue: jqueryFactory };
然后在组件中,您可以初始化$,如下所示:

export class AppComponent implements OnInit  {

  constructor(@Inject(JQUERY_TOKEN) private $factory: any) { }

  public paragraphCount = 0;
  public $: any;


  public ngOnInit() {
    this.$ = this.$factory();
    this.paragraphCount = this.$('p').length;
  }

}
有几件事需要指出:

我认为Stackblitz不会查看您的Angular.json文件,所以我只是在index.html中添加了一个指向jquery CDN的链接。在Stackblitz之外,你不应该这样做 我已经将lifecycle函数改为ngOnInit,否则您将看到在已经运行更改检测之后值更改的问题
部分问题是工厂可能在页面完全加载之前创建,即在窗口['jQuery']存在之前。你有什么理由想在服务中使用它吗?@user184994我认为当涉及到单元测试时,依赖性可以在需要时被模仿。这是有道理的。您可以随时更改服务,使其具有功能。哪一个依次返回窗口['jQuery']?这样的话,它只会在你们们正在阅读的时候从窗口读取ready@user184994这正是我所想的about@user184994似乎jQuery甚至没有正确导入…=/windows对象中没有任何内容,即使加载了所有内容。我将在github上向Stackblitz提交问题通知单。@EhouarnPerret看起来他们已经知道@user184994 true=/正在签出codesandbox并查看它是否支持它。似乎使用codesandbox可以解决问题:谢谢您的帮助!
import { Component, Inject, AfterViewInit } from '@angular/core';
import { JQUERY_TOKEN } from './jquery.service';

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

  constructor(@Inject(JQUERY_TOKEN) private $: any) { }

  public paragraphCount = 0;

  public ngAfterViewInit(): void {
    this.paragraphCount = this.$('p').length;
  }
}
<h1>HelloW!</h1>
<p>
  Seems there is {{ paragraphCount }} paragraph in this component template.
</p>
        "scripts": [
          "./node_modules/jquery/dist/jquery.min.js"
        ]
import { InjectionToken } from '@angular/core';

export const JQUERY_TOKEN = new InjectionToken('jQuery');

export function jqueryFactory() {
  return getJquery();
}

function getJquery() {
  return window['jQuery'];
}

export const JQUERY_SERVICE = { provide: JQUERY_TOKEN, useValue: jqueryFactory };
export class AppComponent implements OnInit  {

  constructor(@Inject(JQUERY_TOKEN) private $factory: any) { }

  public paragraphCount = 0;
  public $: any;


  public ngOnInit() {
    this.$ = this.$factory();
    this.paragraphCount = this.$('p').length;
  }

}