Search code examples
angulartypescriptrxjsangular-servicesangular-components

Sharing data between component using Angular service for Ajax Datatables


I am new in Angular filed! So far I have liked but facing some difficulty in this following case. I want to send data from one component to another component once the user clicks a specific cell with href tag in the Datatables. Therefore I have created following .ts file

service.ts

import { Injectable } from '@angular/core';
import { HttpClient,HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { BehaviorSubject } from 'rxjs';

@Injectable()
export class MyService {

   private protDataSource = new BehaviorSubject<any>({
       currentprotData:null
   });
  currentprotData= this.protDataSource.asObservable();

  constructor(
    private http: HttpClient

  ) {}

  sendProtData(currentprotData:any){
    console.log(currentprotData)
   this.protDataSource.next(currentprotData);
  }
get(url){
   return this.http.get(url)
      .pipe(
          map(responce=>responce),
         catchError(this.handleError)
    )

    }
}

sender.ts

            import { Component, OnInit, OnDestroy, ViewChild, Renderer } from '@angular/core';
            import { ActivatedRoute, Router } from '@angular/router';
            import { DataTableDirective } from 'angular-datatables';
            import { HttpClient,HttpErrorResponse } from '@angular/common/http';
            import { Subject } from 'rxjs';
            import { MyService } from '../qmpkb/qmpkb.service';

            declare var jquery: any;



            @Component({
              selector: 'app-sender-page',
              templateUrl: './sender.component.html',
              styleUrls: ['./sender.component.css'],
              providers:[MyService]
            })
            export class SenderComponent implements OnInit,OnDestroy {
              dtOptions: DataTables.Settings = {};
              dtTrigger: Subject<any> = new Subject();
              private routeSub:any;
              errorStr:Boolean;


              @ViewChild(DataTableDirective)
              datatableElement: DataTableDirective;

              constructor(
                private route: ActivatedRoute,
                private http: HttpClient,
                private renderer: Renderer,
                private router: Router,
                private _myserve:MyService
              ) { }

              ngOnInit(): void {
                    //let destPath='fileapi/resultFile/jsonData/resultJson/'+this.queryResPath
                    let destPath='assets/json/fake.json'
                    this.dtOptions = {
                        pagingType: 'full_numbers',
                        ajax: destPath,
                        processing: true,
                        serverSide: false,
                        columns: [
                            { 
                                title: 'Prot Seq',
                                render: function (data: any, type: any, row: any, meta) {
                                    if (row["Prot Seq"].trim().length > 0 ){
                                        var array =(row["Prot Seq"].trim()).split('<br>');
                                        array.forEach(function(element, index) {
                                            array[index] ='<a target="_blank"   href="/seqfeatures" routerLinkActive="active" seq-link-id=' + element+'>'+element+'</a>';
                                        });
                                        return array.join("<br>");
                                    } else {
                                        return 'No';
                                    }
                                }
                            }
                        ]
                    };



              }

              ngAfterViewInit(): void {
                this.renderer.listenGlobal('document', 'click', (event) => {
                    if (event.target.hasAttribute("seq-link-id")) {
                          this._qmpkb.get(url).subscribe((response: any)=>{
                            this._myserve.sendProtData(response);
                          }, error=>{
                            this.errorStr = error;
                          })
                    }
                })

              }


              ngOnDestroy(){
                  this.routeSub.unsubscribe();
                  this.dtTrigger.unsubscribe();
              }
            }

receiver.ts

    import { Component, OnInit, OnDestroy } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpClient,HttpErrorResponse } from '@angular/common/http';
import { MyService } from '../qmpkb/qmpkb.service';
declare var require: any

@Component({
  selector: 'app-prot-view',
  templateUrl: './prot-view.component.html',
  styleUrls: ['./prot-view.component.css'],
  providers:[MyService]
})
export class ProtViewComponent implements OnInit,OnDestroy  {
  message:string
  constructor(
    private route: ActivatedRoute,
    private http: HttpClient,
    private router: Router,
    private _myserve:MyService,
    ) { }

  ngOnInit() {
           this._myserve.currentprotData.subscribe(currentprotData=>{
           this.message=currentprotData
    })

  }




  ngAfterViewInit(): void {
          console.log(this.message)
  }
  ngOnDestroy(){
  }
}

My service can recive data but reciver always retrun null. I am curius to know what is going wrong here! I really apprecite your help and advice!

Updated As DeborahK suggested to include part of project on stackblitz! You can check how I am trying to build this project!

stackblitz


Solution

  • There are few problems.Easy way is if you are subscribing to sendProtData().subscribe in receiver.ts that's wrong. You need to subscribe to BehaviorSubject and sendProtData() has no return type as well.

    Make protDataSource as public and subscribe to it.

    public protDataSource = new BehaviorSubject<any>({
       currentprotData:null
    });
    

    and then in receiver.ts:

    ngOnInit() {
           this._myserve.protDataSource.subscribe(currentprotData=>{
           this.message=currentprotData
    })
    

    This so do the trick.

    UPDATE:

    Check this working demo

    I fixed below things to make it work:

    1. You should not inject service using provider:[] @Component. It creates a new instance of service for each component. . You dont need that. You need both component to share same service instance to share the data. So, inject in @NgModule in app.module.ts

    2. In the demo code, there was no <app-receiver></app-receiver>. I added that as well so as to initiate the component.

    I hope it helped :) . Thanks for creating a demo