0

I've have a problem when using subjects in Angular 2. I get the following error when running the app:

Type '{}' is not assignable to type 'UserDevice[]'.)

  • I have a component with a list of userDevices.
  • And a service which provides the userDevices.

// Service

export class UserDeviceLocalService {

    udSubject = new ReplaySubject();
    tmpUserDevices: UserDevice[] = [];

    constructor() {
    }

    createUserDevices(userDevice){
    this.tmpUserDevices.push(userDevice);

    // localStorage.setItem('userdevices', JSON.stringify(this.tmpUserDevices));
    this.udSubject.next(this.tmpUserDevices);
    }
 }

// component

export class UserDeviceMenuComponent implements OnInit {

userDevices: UserDevice[];

constructor(private userDeviceLocalService: UserDeviceLocalService) {
}

ngOnInit() {
    this.userDeviceLocalService.udSubject.subscribe(userDevices => this.userDevices = userDevices);
}
RSSD
  • 63
  • 1
  • 13

3 Answers3

1

maybe this line need change

this.udSubject.next(userDevice);

to

this.udSubject.next(tmpUserDevices);

because userDevice is a object, not array of object

Tiep Phan
  • 12,386
  • 3
  • 38
  • 41
  • Yes you're right. I have done this for testing only. I have edited my code, still getting the error – RSSD Feb 08 '17 at 12:46
1
createUserDevices(userDevice){
    this.tmpUserDevices.push(userDevice);
    this.udSubject.next(this.tmpUserDevices);
    }

Also:

export class UserDeviceLocalService {
    udSubject = new ReplaySubject<UserDevice[]>();
    ...
}

and make sure you unsubscribe the observable when the component destroyed to avoid memory leak.

export class UserDeviceMenuComponent implements OnInit {

userDevices: UserDevice[];
supscription: Subscription;

constructor(private userDeviceLocalService: UserDeviceLocalService) {
}

ngOnInit() {
    this.subscription = this.userDeviceLocalService.udSubject.subscribe(userDevices => this.userDevices = userDevices);
}

ngOnDestroy() {
 this.subscription.unsubscribe();   
}

Or use async pipe which handles the unsubscription for you.

Tuong Le
  • 18,533
  • 11
  • 50
  • 44
0

You should specify type when declaring/instantiating your Subject field:

udSubject = new ReplaySubject<UserDevice[]>();

In your example, what you probably need is new ReplaySubject<UserDevice[]>(1); so only the last value is replayed.

In such case you could also use BehaviorSubject instead of ReplaySubject and eliminate tmpUserDevices:

export class UserDeviceLocalService {

    udSubject = new BehaviorSubject<UserDevice[]>([]);

    createUserDevices(userDevice: UserDevice) {
        let devices = this.udSubject.value;

        // maybe clone array first?
        devices = devices.slice();

        devices.push(userDevice);

        // localStorage.setItem('userdevices', JSON.stringify(devices));
        this.udSubject.next(devices);
    }
}

And don't forget to un-subscribe subscription(s) on ngOnDestroy().

This article explains some aspects of TypeScript type system:

http://blog.angular-university.io/typescript-2-type-system-how-does-it-really-work-when-are-two-types-compatible-its-actually-quite-different-than-other-type-systems/

Vilmantas Baranauskas
  • 6,596
  • 3
  • 38
  • 50