Функция службы Angular вызывается несколько раз после изменения маршрута

У меня есть проект 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(); });
    }
}

Что ж, каждый раз, когда компонент инициализируется, он добавляет в документ новый прослушиватель кликов. И это никогда не удаляет слушателя.

JB Nizet 29.07.2019 22:42

вы, вероятно, создаете какую-то утечку памяти со всем этим jquery... избавьтесь от всего этого и делайте что-то угловым

bryan60 29.07.2019 22:43

Вы действительно имеете в виду, что это из-за кодов jquery?

thrashead 29.07.2019 22:45

@thrashead Вы вызвали onCopy(id) в FillData(), а FillData() вызывается в ngOnInit.

user11341611 29.07.2019 22:45

Должен ли я сделать это как (щелкнуть) = onCopy (модель? .ID) на стороне html? Это то, что вы имеете в виду?

thrashead 29.07.2019 22:47

Итак, когда вы переходите на страницу категории, вызывается onCopy(id). И this.router.navigate(['/'], { skipLocationChange: true }).then(() => { this.router.navigate([currentUrl]) }); сделать цикл зависимым от вызова onCopy(id).

user11341611 29.07.2019 22:48

Да, @thrashead, вам не следует вызывать onCopy(id) в ngOnInit()

user11341611 29.07.2019 22:49

но он вызывает функцию по щелчку. Есть ли способ удалить его при уничтожении?

thrashead 29.07.2019 22:52

Попробуйте обернуть оба сервиса (getIndex() и getCopy()) вот так this.subscription.add( this.service.getIndex().subscribe()) вместо this.subscription = this.service.getIndex().subscribe() Вот ссылка на RxJS-документация.

riorudo 29.07.2019 22:53

я попробовал это человек. это не сработало. я думаю, это из-за вызова onCopy в ngOnInit, как все говорили. Мне нужно решение для удаления прослушивателя кликов.

thrashead 29.07.2019 22:55
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Angular и React для вашего проекта веб-разработки?
Angular и React для вашего проекта веб-разработки?
Когда дело доходит до веб-разработки, выбор правильного front-end фреймворка имеет решающее значение. Angular и React - два самых популярных...
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Эпизод 23/17: Twitter Space о будущем Angular, Tiny Conf
Мы провели Twitter Space, обсудив несколько проблем, связанных с последними дополнениями в Angular. Также прошла Angular Tiny Conf с 25 докладами.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
Мое недавнее углубление в Angular
Мое недавнее углубление в Angular
Недавно я провел некоторое время, изучая фреймворк Angular, и я хотел поделиться своим опытом со всеми вами. Как человек, который любит глубоко...
Освоение Observables и Subjects в Rxjs:
Освоение Observables и Subjects в Rxjs:
Давайте начнем с основ и постепенно перейдем к более продвинутым концепциям в RxJS в Angular
1
10
1 287
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

В общем, вам следует избегать смешивания Angular и jQuery. Здесь ваша конкретная проблема вызвана тем, что вы вызываете this.FillData() в ngOnInit. Поскольку ngOnInit вызывается каждый раз, когда вы направляетесь на страницу, код в this.FillData() вызывается каждый раз, когда вы направляетесь.

Поскольку this.FillData() вызывается неоднократно, каждый раз, когда вы направляетесь на страницу, вы каждый раз подключаете свои обработчики событий в jQuery (таблица данных и клики). Поскольку вы никогда не отсоединяете обработчики событий при маршрутизации, вы в конечном итоге подключаете одно и то же событие несколько раз. Это усугубляется тем фактом, что вы прикрепляете обработчик на уровне документа и используете всплывающее окно событий, вы прикрепляете несколько обработчиков на уровне документа, и каждый раз, когда вы добавляете новый, он вызывается дополнительный раз.

Поскольку вы используете DataTables, я бы посоветовал вам полностью отказаться от кода jQuery и перевести свои обработчики на правильный подход Angular. Существует множество компонентов, подобных DataTables (например, я широко использовал ag-grid).

Если вы должен используете jQuery (по какой-либо причине), вам необходимо реорганизовать свой код, чтобы либо удалить все существующие обработчики событий при маршрутизации к/от компонента. Почти уверен, что вы могли бы просто вставить .off('click') туда.

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

Или вам нужно убедиться, что вы присоединяете обработчики событий однажды только к родительскому компоненту (поскольку вы все равно его поднимаете).

спасибо за Ваш ответ. как убрать обработчики? есть способ?

thrashead 29.07.2019 22:59

Отредактировал ответ, вы сможете просто вставить выключение перед включением.

Rich 29.07.2019 23:01

Ты мужчина. ты спас мне жизнь спасибо чувак. Я добавил $(document).off("click", "a.cpyLink"); $(document).off("click", "a.cpy-yes"); коды в функции onCopy() до того, как я вызвал службу, и все готово. еще раз спасибо :)

thrashead 29.07.2019 23:05

Другие вопросы по теме