AndreaM16
AndreaM16

Reputation: 3985

Class's Set throws Cannot invoke an expression whose type lacks a call signature using BehaviorSubject and Observable

as stated in the title, I'm getting the following error when trying to set a new Item:

Cannot invoke an expression whose type lacks a call signature. Type 'ItemModel' has no compatible call signatures.

I'm using BehaviorSubject and Subject to share a set Item between two different states. Essentially, I want to set a chosen Item and then, when going to its details page, get it.

Here's my item.model.ts, let's suppose it has only an id property:

export class ItemModel {
    public id: string;
    constructor( id: string ) {
        this.id = id;
    }
}

Here's my item.service.ts use to get and set an Item:

import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';

import { ItemModel } from './item.model';

@Injectable()
export class ItemService {

    public _item = new BehaviorSubject<ItemModel>(null);
    item$ = this._item.asObservable();

    public set item(item: ItemModel) {
        this._item.next(item);
    }

    public get item() : ItemModel {
        return this._item.getValue();
    }

}

My item.component.ts would set a given Item:

import { Component } from '@angular/core';
import { Router } from '@angular/router';

import { ItemService } from '../item.service';

@Component({
    selector: 'app-item',
    templateUrl: './item.html',
    styleUrls: ['./item.scss'],
    providers: [ItemService]
})

export class ItemComponent {

    constructor(private _router: Router, private _itemService : ItemService) { }

    goToDetails(item : ItemModel){
       this._itemService.item(item); //Throws the error
       this._router.navigate(['/details', item.id]);
    }

}

And on details.page.ts I want to get that Item:

 import { Component } from '@angular/core';
 import { Subscription } from 'rxjs/Subscription';
 import { ItemService } from './item.service';
 import { ItemModel } from './item.model';

 @Component({
     selector: 'app-details-page',
     templateUrl: './details.page.html',
     styleUrls: ['./details.page.scss'],
     providers: [ItemService]
 })

 export class DetailsPage {

     private _item = ItemModel;
     private subscription : Subscription;

     constructor( private _itemService: ItemService ) { }

     ngOnInit() {

         this.subscription = this._itemService.item$
             .subscribe(item => console.log(item));

     }

 }

What I tried so far on the invocation of the setter:

What Am I doing wrong? How can I make sure that ItemModel has a compatible signature?

EDIT

With @n00dl3 's help I was able to get rid of this error. But, unluckily, when logging inside details.page.ts's ngOnInit I get null. When I log inside the setter it shows the correct output.

Upvotes: 4

Views: 2238

Answers (1)

n00dl3
n00dl3

Reputation: 21564

itemService.item is a setter so you should not call it like a function, but like a property :

this._itemService.item = item;

from MDN :

Defining a setter on new objects in object initializers This will define a pseudo-property current of object language that, when assigned a value, will update log with that value:

var language = {
  set current(name) {
    this.log.push(name);
  },
  log: []
}

language.current = 'EN';
console.log(language.log); // ['EN']

language.current = 'FA';
console.log(language.log); // ['EN', 'FA']

For your null vs item problem :

It is because you should not declare your service inside component, but inside an NgModule (so you should remove it from your components providers):

@NgModule({
  imports:[CommonModule],
  declarations:[SomeComponent],
  providers:[ItemService]
})
export class myModule{}

when you declare a service inside component's providers, it is only available to that component, dirrectives applied to it and its children. (More details in this question.) So it means you are currently not talking to the same service instance in DetailsPage and in ItemComponent.

Upvotes: 5

Related Questions