17

My target is to send data from Angular component to service and use service methods to work on it. Example:

export class SomeComponent {
    public data: Array<any> = MyData;
    public constructor(private myService: MyService) {
      this.myService.data = this.data;
    }
}

and service:

@Injectable()
export class TablePageService {
    public data: Array<any>;
    constructor() {
        console.log(this.data);
        // undefined
    }
}

Getting data is undefined. How to make it works?

IntoTheDeep
  • 4,027
  • 15
  • 39
  • 84
  • 2
    The service constructor has already been run by the time you inject it into your component - since you don't initialize it, `data` is undefined at that time. – Joe Clay May 19 '17 at 09:56
  • Before you can call a method on an object, it has to be constructed. Therefore your constructor is called and data is undefined. Then afterwards you access the member and modify the variable, but the constructor has been already called. – Akkusativobjekt May 19 '17 at 09:57
  • How can I fix that? – IntoTheDeep May 19 '17 at 09:58
  • 1
    I would suggest you use methods to communicate between component and services. Also use subscriptions to make sure you receive the data when is available. Check documentation here, very useful: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service – SrAxi May 19 '17 at 09:58
  • This is Typescript and not JavaScript, or? – Akkusativobjekt May 19 '17 at 11:25
  • Yes, typescript. I stand correct. – IntoTheDeep May 19 '17 at 13:40

2 Answers2

32

An example if interaction between service and component could be:

Service:

@Injectable()
export class MyService {
    myMethod$: Observable<any>;
    private myMethodSubject = new Subject<any>();

    constructor() {
        this.myMethod$ = this.myMethodSubject.asObservable();
    }

    myMethod(data) {
        console.log(data); // I have data! Let's return it so subscribers can use it!
        // we can do stuff with data if we want
        this.myMethodSubject.next(data);
    }
}

Component1 (sender):

export class SomeComponent {
    public data: Array<any> = MyData;

    public constructor(private myService: MyService) {
        this.myService.myMethod(this.data);
    }
}

Component2 (receiver):

export class SomeComponent2 {
    public data: Array<any> = MyData;

    public constructor(private myService: MyService) {
        this.myService.myMethod$.subscribe((data) => {
                this.data = data; // And he have data here too!
            }
        );
    }
}

Explanation:

MyService is managing the data. You can still do stuff with data if you want, but is better to leave that to Component2.

Basically MyService receives data from Component1 and sends it to whoever is subscribed to the method myMethod().

Component1 is sending data to the MyService and that's all he does. Component2 is subscribed to the myMethod() so each time myMethod() get called, Component2 will listen and get whatever myMethod() is returning.

SrAxi
  • 19,787
  • 11
  • 46
  • 65
  • Where MyData in component2 came from? – IntoTheDeep May 22 '17 at 09:57
  • 2
    I just took it from your code: `public data: Array = MyData;`. It could also be declared as `public data = {};` for example, depends on the data type you are working with. I just wanted to keep it close to your example so it's more understandable for you. – SrAxi May 22 '17 at 10:11
  • Can I set two parameters? Let say two separate strings? Do I need two subjects and two Observables? – IntoTheDeep May 22 '17 at 10:48
  • 1
    Send a second parameter in the same method. https://www.w3schools.com/js/js_function_parameters.asp – SrAxi May 22 '17 at 10:58
  • Hi, I find your solution pretty accurate but I'm having a trouble in the receiver component, so let me ask you a question: the data returned from the subscribe must be an Array of even objects are fine? – Nad G Oct 04 '18 at 13:02
  • @NadG Hello! Can be any type of data actually. You can send a Number, String, Object, Array... – SrAxi Oct 04 '18 at 13:19
  • 1
    @SrAxi, snap, I was hoping that the problem is the type of the data xD Well, good to know that it can be of any type. Thank you for your answer! – Nad G Oct 04 '18 at 13:28
  • receiver component not getting the data – Debo Oct 25 '18 at 18:06
0

There is a small issue with the receiver component in @SrAxi s reply as it can't subscribe to the service data. Consider using BehaviorSubject instead of Subject. It worked for me!

private myMethodSubject = new BehaviorSubject<any>("");
Debo
  • 505
  • 4
  • 13
  • 24
  • 1
    `BehaviorSubject` is just a specialization of `Subject` that takes the latest value from the stream of data. The isse is probably not the type of `Subject` in your code, probably the issue is related to when you're subscribing. – SrAxi Oct 26 '18 at 14:26