4

Im trying to send data from one component to other using observable. Here I'm implementing observable in service like this...

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

@Injectable()
export class SelectedItemService {
    stream1$:Observable<any>;
    selectedItem:JSON;

    stream1$= new Observable(observer=> setTimeout(() => {
              observer.next(this.selectedItem);
          }, 3000);)

}

and my parent Component is initializing data to a service in onselect() like below :

import { Component } from '@angular/core';
import {Http, Headers,Response } from '@angular/http';
import {Observable} from 'rxjs/Rx';
import 'rxjs/add/operator/map';
import {SelectedItemService} from './selecteditem.service'

@Component({
    selector: 'newcomponent',
    template:`<p>

    </p>
    <h2>Your Title: {{nameValue}}</h2>
    <ul><li *ngFor="let list of lists">Hello {{ list }}</li></ul> 
    <form class="ui large form segment"> 
    <h3>Add a Link</h3> <div> 
     <label for="title">Title:</label>  
      <input [(ngModel)]="nameValue" placeholder="title" name="Title" >
      </div>   
      <label for="link">Link:</label>  <input name="link"></form>
      <div class=container *ngFor="let data of dataServer"
           [class.selected]="data === selectedItem"
           (click)="onSelect(data)"> 
         <div id="myimages">
             <a routerLink="/SecondNewCom">
                 <img src="myBaseurl/{{data.images.image3}}">
             </a>
             <router-outlet></router-outlet>
         </div>
         <div class=caption>       {{data.productName}} </div>
    </div>`,
    styleUrls: [`./app/mydoc.css`]  
})
export class NewComponent {
    nameValue: string;
    lists: string[];
    url:string;
    dataServer:JSON[];
    length:number;
    selectedItem:JSON;


    constructor(private http:Http, public myservice:SelectedItemService) {
        this.myservice=myservice;
        this.nameValue = "declaredName";
        this.url="myBaseurl";
        this.lists = ['abc', 'xyz', 'lol'];
this.http.get(this.url).map((res:Response) => res.json())
      .subscribe(
        data => { this.dataServer = data
            this.length=Object.keys(this.dataServer).length},
        err => console.error(err),
        () => console.log('done')
      );}

      onSelect(data:JSON):void{
            this.selectedItem=data;
            this.myservice.selectedItem=data;
      }
}

and child component is receiving the data from subscriber like this... but the data displayed is undefined and i see blank screen.. Where am i doing wrong...

import {Component,Input} from '@angular/core';
import {SelectedItemService} from './selecteditem.service'

@Component({
    selector:'secondcomponent',
    template:`<h1> This is second new Component</h1>
    <h1>{{UiSelectedItem}}</h1>
   `

})
export class SecondComponent{
     UiSelectedItem:JSON;

     constructor(public mservice:SelectedItemService) {
        this.mservice=mservice;
        mservice.stream1$.subscribe(value=>this.UiSelectedItem=value);
    }    
}
Sangwin Gawande
  • 7,658
  • 8
  • 48
  • 66
coder007
  • 97
  • 7

2 Answers2

0

You should use Observable.create instead of new Observable

See : RxJs docs

0

What you should be using is a Subject. If you have ever used Angular's EventEmitter, this is also a Subject. With EventEmitter we usually use it to publish events from child to parent

@Component({
  template: `
    <child (textChange)="onTextChange()"></child>
  `
})
class ParentComponent {}

class ChildComponent {
  @Output() textChange = new EventEmitter();

  onClick() {
    textChange.emit('new value');
  }
}

It's you've ever used this before, this is is the publish/subscribe pattern that you need. Someone subscribes to the event, and someone publishes it. This is where we can use Subject. As I said EventEmitter is a subclass of Subject.

For this case though, the vanilla Subject may not be good enough. The reason is that once the event is emitted, it is gone forever. If there was no one subscribed, nothing happens with it. So if it happens that you subscribe just a smidget after the event was emitted, then you get nothing. A lot of times this is unacceptable.

For this case, we can use a ReplaySubject. This type of subject allows you to keep a buffer with configurable size. So if you subscribe right after the event was emitted you will still get it.

Here's an example

import { ReplaySubject } from 'rxjs/ReplaySubject';

export class SelectedItemService {
  private _selectedItem = new ReplaySubject<string>(1); // buffer size 1

  selectedItem$ = this._selectedItem.asObservable();

  set selectedItem(item: string) {
    this._selectedItem.next(item);
  }
}

Now the component that wants to publish just needs to set the item

service.selectedItem = 'new item';

And the subscribing component

service.selectedItem$.subscribe(item => {})

See Also:


UPDATE

See Plunker

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • Im trying to send data object from parent to child... and its not a direct child... there is click event only in parent... Im confused why you have given that first code module.... n i tried to implement the rest of the code modules... and it works ocassionally... like 2 out of 10 times... rest of the times data is undefined.. :-( – coder007 Oct 06 '16 at 15:07
  • See the plunker in my update. Other than that I am not sure what you are doing wrong – Paul Samsotha Oct 06 '16 at 15:09
  • The first example is not for you to use. It was just to show an EventEmitter example – Paul Samsotha Oct 06 '16 at 15:10