【问题标题】:Angular service function being called multiple times after route change路由更改后多次调用角度服务功能
【发布时间】:2019-12-07 05:18:51
【问题描述】:

我有一个 Angular 8 项目。它具有复制数据的服务功能。当我复制数据并转到另一个页面时,如果我再次回到同一页面并再次复制数据,它会复制数据两次。如果我再做一次,它会多次调用服务函数并多次复制数据。

我尝试了许多不同的方法,但它仍然会多次复制数据。希望你能明白我的要求。我正在等待您的答案和解决方案。

这是我的 app.module.ts 代码;

import { APP_BASE_HREF } from '@angular/common';
import { NgModule } from '@angular/core';
import { ModuleWithProviders } from '@angular/compiler/src/core';
import { BrowserModule } from '@angular/platform-browser';
import { ReactiveFormsModule } from '@angular/forms';
import { AppRoutingModule } from './app-routing.module';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app';

import { CategoryComponent } from './views/category';

import { CategoryService } from './services/category';

@NgModule({
    declarations: [
        AppComponent,
        CategoryComponent
    ],
    imports: [
        BrowserModule,
        AppRoutingModule,
        ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }),
        HttpClientModule
    ],
    providers: [{ provide: APP_BASE_HREF, useValue: '/AngularProject/' }, CategoryService ],
    bootstrap: [AppComponent]
})
export class AppModule { }

这是我的服务代码;

import { Injectable } from "@angular/core";
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ICategory } from '../models/ICategory';

@Injectable({ providedIn: 'root' })
export class CategoryService {
    private linkIndex: string = "Ajax/Category/Index";
    private linkCopy: string = "Ajax/Category/Copy";

        constructor(private http: HttpClient) {
    }

    getIndex(): Observable<Array<ICategory>> {
        return this.http.get<Array<ICategory>>(this.linkIndex);
    }

    getCopy(id: string): Observable<boolean> {
        let params = new HttpParams().set("id", id);
        return this.http.get<boolean>(this.linkCopy, { params: params });
    }
}

这是我的 CategoryComponent 代码;

import { Component, OnDestroy, OnInit } from "@angular/core";
import { Subscription } from "rxjs";
import { Router } from "@angular/router";
import { CategoryService } from "../../services/category";
import * as $ from "jquery";

@Component({
    templateUrl: './index.html'
})

export class CategoryComponent implements OnInit, OnDestroy {
    errorMsg: string;
    CategoryList: any;

    callTable: boolean;

    private subscription: Subscription = new Subscription();

    constructor(private service: CategoryService, private router: Router) {
    }

    ngOnInit() {
        this.callTable = true;
        this.FillData();
    }

    FillData() {
        if (this.callTable == true) {
            this.subscription = this.service.getIndex().subscribe((answer) => {
                this.CategoryList = answer;
                this.callTable = false;

                setTimeout(() => {
                    $(".data-table").dataTable({
                        "bJQueryUI": true,
                        "sPaginationType": "full_numbers",
                        "sDom": '<""l>t<"F"fp>'
                    });

                    $(document).on("click", "a.cpyLink", function () {
                        $(this).addClass("active-cpy");
                        $("a.cpy-yes").attr("data-id", $(this).attr("data-id"));
                    });

                    $(document).on("click", "a.cpy-yes", () => {
                        let id: string = $("a.cpy-yes").attr("data-id");
                        this.onCopy(id);
                    });
                }, 1);
            }, resError => this.errorMsg = resError, () => { this.subscription.unsubscribe(); });
        }
    }

    ngOnDestroy(): void {
        this.subscription.unsubscribe();
    }

    onCopy(id) {
        this.subscription = this.service.getCopy(id).subscribe((answer) => {
            if (answer == true) {
                let currentUrl = this.router.url;
                this.router.navigate(['/'], { skipLocationChange: true }).then(() => { this.router.navigate([currentUrl]) });
            }
        }, resError => this.errorMsg = resError, () => { this.subscription.unsubscribe(); });
    }
}

【问题讨论】:

  • 嗯,每次初始化组件时,它都会在文档上添加一个新的点击监听器。而且它永远不会移除监听器。
  • 您可能正在使用所有 jquery 造成某种内存泄漏...摆脱它并以有角度的方式做事
  • 你真的是说因为jquery代码?
  • @thrashead 你在 FillData() 中调用了 onCopy(id) 并且在 ngOnInit 中调用了 FillData()。
  • 我应该在 html 端像 (click)=onCopy(model?.ID) 那样做吗?这就是你的意思?

标签: angular angular-services angular8


【解决方案1】:

一般来说,您应该避免混合使用 Angular 和 jQuery。在这里,您的具体问题是由于您在 ngOnInit 中调用 this.FillData() 而引起的。由于每次路由到页面时都会调用 ngOnInit,因此每次路由时都会调用 this.FillData() 中的代码。

由于this.FillData() 被重复调用,每次您路由到页面时,您每次都在jQuery(数据表和onclicks)中附加您的事件处理程序。由于您在路由时从不分离事件处理程序,因此您最终会多次附加相同的事件。更糟糕的是,您在文档级别附加处理程序并使用event bubbling,您在文档级别附加多个处理程序,每次添加新的处理程序时,都会被调用一次.

由于您使用的是 DataTables,我建议您完全放弃 jQuery 代码并将您的处理程序转换为正确的 Angular 方法。那里有很多类似 DataTables 的组件(例如,我广泛使用了 ag-grid)。

如果您必须使用 jQuery(无论出于何种原因),那么您需要重构您的代码,以便在路由到/从组件时删除任何现有的事件处理程序。很确定你可以在里面贴上.off('click')

$(document).off("click", "a.cpy-yes").on("click", "a.cpy-yes"....

或者您需要确保仅在父组件中附加事件处理程序一次(因为无论如何您都在冒泡)。

【讨论】:

  • 感谢您的回答。我怎样才能删除处理程序?有办法吗?
  • 编辑了答案,你应该可以在 on 之前插入一个 off。
  • 你就是那个男人。你救了我的命,谢谢伙计。我添加了 $(document).off("click", "a.cpyLink"); $(document).off("click", "a.cpy-yes");在我调用服务之前 onCopy() 函数中的代码并完成了。再次感谢:)
猜你喜欢
  • 2018-10-12
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-03
  • 2022-01-18
  • 2017-09-12
  • 1970-01-01
相关资源
最近更新 更多