Angular 路由更改后多次调用服务函数

Angular service function being called multiple times after route change

我有一个 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(); });
    }
}

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

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

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

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

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

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