为什么Angular中基于jQuery令牌的集成无法正常工作?

时间:2018-07-21 22:53:23

标签: javascript jquery angular

我正在尝试将jQuery作为服务集成到Angular 6应用程序中,我关注了这篇文章:https://thecodegarden.net/jquery-in-angular-typescript-without-type-definition/#comment-2311

唯一的区别是我的解决方案使用的是InjectionToken而不是自Angular 4起已弃用的OpaqueToken

好,现在介绍一下代码本身。

jQuery服务,其中似乎发生了根本原因的问题,jqueryFactory返回undefined

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

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

export function jqueryFactory() {
  // return undefined...
  return  window['jQuery'];
}

export const JQUERY_SERVICE = { provide: JQUERY_TOKEN, useFactory: jqueryFactory };

AppModule:app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { JQUERY_SERVICE } from './jquery.service';

@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ],
  providers:    [ JQUERY_SERVICE ]
})
export class AppModule { }

AppComponent:app.component.ts

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;
  }
}

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

<h1>HelloW!</h1>
<p>
  Seems there is {{ paragraphCount }} paragraph in this component template.
</p>

最后但并非最不重要的angular.json

        "scripts": [
          "./node_modules/jquery/dist/jquery.min.js"
        ]

此处提供了此应用程序的示例:https://stackblitz.com/edit/angular2plus-jquery-token-based-eaxnzs

[编辑]

似乎根本的问题更多地是由user184994 github.com/stackblitz/core/issues/407指出的StackBlitz

可在codesanbox上找到一个工作示例:https://codesandbox.io/s/3vmzyrj4w1

1 个答案:

答案 0 :(得分:1)

** 编辑 **

我发现,通过将CDN链接的// initial call processItem($('.myList li:first')); function processItem($li) { if (!$li.length) { return; // none left } var $next = $li.next(); if (condition) { console.log('item with index: ' + $li.index() + ' is skipped'); // recursive call assumed here also processItem($next); } else { $li.click(); setTimeout(function() { // Wait 1 second untill the popup is opended popupWindow.animate({ scrollTop: $(this).height() }, $(this).height() * 10, getData); // get the data to post // use promise returned from postData to start process next item postData(data).then(function() { processItem($next) }); }, 1000); } } function postData(data) { // must return the ajax promise return $.ajax({ type: 'POST', // ... // ... }); } 标签移动到script标签中,其余的代码将起作用。有关更多信息,请参见this example

** 原始答案 **

部分问题是工厂可能在页面完全加载之前即head存在之前创建。

要解决此问题,您可以使用window['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 }; ,如下所示:

$

Here is a working stackblitz

有两点要指出:

  • 我认为Stackblitz不会查看您的Angular.json文件,因此我刚刚将指向jquery CDN的链接添加到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之外,您不需要这样做
  • 我已将生命周期函数改为index.html,否则您将在更改检测已运行后看到有关值更改的问题