I have an angular 8 project. It has a service function that copies data. When i copied a data and go to another page, if i come back to the same page again and copy the data again it copies data twice. If i do it again it calls service function multiple times and copies data many many times.
I tried many different ways but it still copies data multiple times. Hope you can understand what i ask. I'm waiting for your answers and solutions.
Here's my app.module.ts code;
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 { }
and here's my service codes;
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 });
}
}
and here is my CategoryComponent codes;
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(); });
}
}
In general, you should avoid mixing Angular and jQuery. Here, your specific problem is caused because you call this.FillData()
in ngOnInit. Since ngOnInit calls every time you route to the page, the code in this.FillData()
gets called every time you route.
Since this.FillData()
is called repeatedly, every time you route to the page, you are attaching your event handlers in jQuery (datatable, and the onclicks) each time. Since you are never detaching the event handlers while routing away, you end up attaching the same event multiple times. This is made worse by the fact that you are attaching the handler at the Document level and using event bubbling, you are attaching the multiple handlers at the Document level, and each time you add a new one, it is being called an additional time.
Since you're using DataTables, I would suggest that you drop the jQuery code entirely and transition your handlers to the proper Angular approach. There are plenty of DataTables-like components out there (I've used ag-grid extensively, for example).
If you must use jQuery (for whatever reason), then you need to refactor your code to either remove any existing event handlers when routing to/from the component. Pretty sure you could just stick an .off('click')
in there.
$(document).off("click", "a.cpy-yes").on("click", "a.cpy-yes"....
Or you need to ensure that you only attach the event handlers once in the parent component (since you're bubbling it down anyways).