Angular 8:单例服务每次在新文件上需要它时都创建新实例

问题描述 投票:1回答:2

我有一个可以正常使用的平台,该平台在服务中使用Rxjs行为主题(Observables)来保持整个应用程序的状态。直到我需要包括WebSocket来更新同一帐户中许多用户的信息为止,它的工作情况还不错。随着更新的信息传递给用户,我称行为主体来检查是否应该更新活动的供应商(用户当前正在查看的供应商),但是Observable始终返回“ null”,因为它是该供应商的新实例。可观察到的(与用户屏幕上显示的不一样)。

为了测试,我在两个不同的文件中记录了相同的可观察值:

// Supplier.service.ts

import { Injectable } from "@angular/core";
import { BehaviorSubject } from 'rxjs';
import { Supplier } from '../../models/supplier.model';
import { UserService } from './User.service';

@Injectable({providedIn: 'root'})
export class SupplierService {
  activeSupplier = new BehaviorSubject<Supplier>(null);

  constructor (
    private http: HttpClient,
    private userService: UserService,
  ) {}

{...}

getOneSupplier(supplierId: string) {
  this.http.get<Supplier>(`${BASEURL}supplier/${supplierId}`)
    .subscribe(supplier => {
        this.activeSupplier.next(supplier);
        this.activeSupplier.pipe(take(1)).subscribe(activeSupplier => {
        console.log('updater:', activeSupplier); // <----------------- here
    });
  });
}

updateSupplierList(changedSupplier) {
    this.activeSupplier.pipe(take(1)).subscribe(activeSupplier => {
      console.log('Socket changing active supplier:', activeSupplier);
        if (activeSupplier._id === changedSupplier._id) {
          this.getOneSupplier(activeSupplier._id);
      }
    });
  }

{...}

}

// Socket.service.js

import { Injectable } from '@angular/core';
import io from './SocketCopier.js';
import { UserService } from './User.service.js';
import { SupplierService } from './Supplier.service.js';

@Injectable({
providedIn: 'root',
})
export class SocketService {
socket;
subs = {};

constructor(
private userService: UserService,
private supplierService: SupplierService
) {
this.supplierService.activeSupplier.subscribe(activeSupplier => {
  console.log('socket:', activeSupplier); // <----------------- and here
});
}

loadSocket(user) {
io.then((result) => {
  if (this.socket) {
    this.socket.close();
  }

  this.socket = result('http://localhost:3000');
  this.socket.on('connect', () => {
    this.socket.emit('login', { account: user.account._id })
  });

  this.socket.on('logged', (msg) => {
    console.log(msg.text);
  });

  this.socket.on('supplierChange', (msg) => {
    this.supplierService.updateSupplierList(msg.data);
  });
});
}

}

// supplier-info.component.ts

import { Component, OnInit, OnDestroy } from '@angular/core';
import { SupplierService } from 'src/app/shared/services/Supplier.service';
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
import { Supplier } from 'src/app/models/supplier.model';
import { filter } from 'rxjs/operators';

@Component({
  selector: 'app-supplier-info',
  templateUrl: './supplier-info.component.html',
  styleUrls: ['./supplier-info.component.css'],
})
export class SupplierInfoComponent implements OnInit, OnDestroy {
  supplier: Supplier;
  subs = {};
  activeRoute: string = 'projetos';

  constructor(
    private supplierService: SupplierService, 
    private route: ActivatedRoute,
    private router: Router,
    ) { }

  ngOnInit() {
      this.supplierService.getOneSupplier(this.route.snapshot.params.supplierId);
  }

  {...}

}

代码首先调用Socket.service.ts,后者调用Supplier.service.ts,后者创建行为主体“ activeSupplier”,初始值为“ null”。

然后,Socket.service.ts在其构造函数中,订阅可观察到的“ activeSupplier”并按预期返回“ null”。

然后生成了vendor-info.component.ts,并在ngOnInit中要求提供供应商信息,并调用“ this.supplierService.getOneSupplier()”。这将更新“ activeSupplier” BehaviorSubject,该行为将记录供应商。

这是我从这些日志中得到的结果:

socket: null
updater: {socialMediaUrls: {…}, photoUrl: "", emails: Array(0), skills: Array(0), tags: Array(4), …}

Socket的observable不会再更新,因为它是“ supplierService”的新实例,并且不与Supplier-info.component.ts共享相同的“ activeSupplier”。应该更新吧?因为它订阅了相同的Observable(至少在理论上是这样)。

我在这里没看到什么?预先感谢您的所有帮助!

编辑:值得一提的是,任何对“ activeSupplier”和“ Observable”订阅的新订阅都将返回“ null”,因为它是第一个值(即使在第二个console.log和供应商之后)。

angular rxjs observable angular-services behaviorsubject
2个回答
0
投票

阅读您的注释及其中的代码,我想您可以尝试这样的事情。

首先,您将从http服务获得的活动的供应商的值保存在某个位置,可能是在开始时。像这样的东西

export class SupplierService {
  activeSupplier = new BehaviorSubject<Supplier>(null);
  activeSupplierValue: Supplier;

  constructor (
    private http: HttpClient,
    private userService: UserService,
  ) {}
...

getOneSupplier(supplierId: string) {
  this.http.get<Supplier>(`${BASEURL}supplier/${supplierId}`)
    .subscribe(supplier => {
        this.activeSupplierValue = supplier;  // save the data of the active supplier
        ......
    });
  });
}
...

}

然后将活动的供应商与从套接字收到的任何内容进行比较,如果匹配,则再次触发getOneSupplier

updateSupplierList(changedSupplier) {
   if (activeSupplier._id === changedSupplier._id) {
      this.getOneSupplier(activeSupplier._id);
   }
}

0
投票

我找到了!经过许多(MANY)调试日志后,我发现我确实在创建该服务的另一个实例。为了找到答案,我登录了Supplier.service.ts构造函数。然后,我看到两个日志都发生在不同的行中。打开这些文件(chrome inspect>源代码),我看到它们是不同的(?),所以我试图“重写” Sockets.service.ts中的导入,并且可以正常工作!

这是因为我错误地导入了它(结尾处带有'.js')。

来自此:

import { UserService } from './User.service.js';
import { SupplierService } from './Supplier.service.js';

为此:

import { UserService } from './User.service';
import { SupplierService } from './Supplier.service';

现在一切正常!

© www.soinside.com 2019 - 2024. All rights reserved.