【问题标题】:Sharing data between component using Angular service for Ajax Datatables使用 Ajax 数据表的 Angular 服务在组件之间共享数据
【发布时间】:2019-07-10 04:52:58
【问题描述】:

我是 Angular 的新手!到目前为止,我很喜欢,但在以下案例中遇到了一些困难。一旦用户单击数据表中带有 href 标记的特定单元格,我想将数据从一个组件发送到另一个组件。因此我创建了以下 .ts 文件

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)
    )

    }
}

发件人.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(){
  }
}

我的服务可以接收数据,但接收器总是返回 null。我很想知道这里出了什么问题!非常感谢您的帮助和建议!

更新 正如 DeborahK 建议的那样,将部分项目包含在 stackblitz 上!你可以看看我是如何构建这个项目的!

stackblitz

【问题讨论】:

  • map(responce=&gt;responce) 是做什么的?
  • @friddo 我以后会从后端收到一些HTTP响应数据,思维导图可能有助于获取JSON数据!只是按照一些例子来做到这一点!

标签: angular typescript rxjs angular-services angular-components


【解决方案1】:

问题很少。简单的方法是,如果您在receiver.ts 中订阅sendProtData().subscribe,那就错了。您需要订阅BehaviorSubject,而sendProtData() 也有无返回类型

protDataSource设为公开并订阅。

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

然后在 receiver.ts

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

这样就行了。

更新:

Check this working demo

我修复了以下问题以使其正常工作:

  1. 您不应使用 provider:[] @Component 注入服务。 It creates a new instance of service for each component. 。你不需要那个。您需要两个组件共享相同的服务实例来共享数据。所以,在app.module.ts中注入@NgModule

  2. 在演示代码中,没有&lt;app-receiver&gt;&lt;/app-receiver&gt;。我也添加了它以启动组件。

我希望它有所帮助:)。感谢您创建演示

【讨论】:

  • 感谢您的建议!我已经尝试过您的解决方案,但仍在接收端,得到以下对象 => currentprotData:null。发件人仍会获得该数据!我只是想知道这是否是因为 sender.ts 的 ngAfterViewInit()。任何修复它的建议!
  • @Paul85 你能确认this._myserve.sendProtData(response); 正在被调用吗?在初始化MyService 类中的BehaviorSubject 时设置空值。因此,可能会保留该价值,而不是您期望的新价值。请检查并让我知道。您还可以尝试在 BahviorSubject 的初始化时设置一些值,看看您是否在 receiver 中得到了该值
  • @Vivek 我认为this._myserve.sendProtData(response) 被调用是因为如果我在sevice.ts 中的sendProtData 内执行console.log(currentprotData)console.log(this.protDataSource),总是得到我从send.ts 发送的值但不知何故,它的接收器之后没有收到该数据!即使我已经用一些值初始化了BahviorSubject,在这种情况下,只能在receiver 结束时获得该初始化值!
  • 什么叫sendProtData
  • @Paul85 : 你试过直接订阅public protDataSource 而不是currentprotData 吗?
【解决方案2】:

尝试移动您的 console.log:

改为:

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

  }

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

试试这个:

  ngOnInit() {
           this._myserve.sendProtData.subscribe(currentprotData=>{
           this.message=currentprotData;
           console.log(this.message);
    })
  }

【讨论】:

  • 我也尝试过,但仍然为空。即使我需要在接收方的 ngAfterViewInit () 中的某个时间点使用该变量!无论如何,我已经编辑了我的代码,因为我意识到我不能在接收方使用 'this._myserve.sendProtData.subscribe' 但需要使用 this._myserve.currentprotData.subscribe(currentprotData=>{.
  • 仅供参考……Angular 的最佳实践是在需要数据的组件中通常使用subscribe
  • 感谢您的建议,通常我会这样做,但在这种情况下,如果我这样做,总是会收到错误 Property 'subscribe' does not exist on type '(currentprotData: any) =&gt; void'. this._myserve.sendProtData.subscribe
  • 有什么方法可以将问题样本(不是整个应用程序)放入 stackblitz 以便我们查看?
  • 我会尽快做的
猜你喜欢
  • 2017-11-06
  • 2021-05-03
  • 2018-10-12
  • 2020-06-18
  • 1970-01-01
  • 1970-01-01
  • 2019-03-05
相关资源
最近更新 更多