Exploring the use of Observables in Angular 2 services

Ensuring the seamless transfer of data between components is crucial in Angular development. One common way to achieve this is by utilizing observables. Let's take a look at how observables are implemented in a service:

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);)

}

In the parent component, data initialization happens within the onSelect() method:

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>
    <!-- Rest of the parent component template goes here --> 

Meanwhile, the child component should receive data from the subscriber. However, if the displayed data appears as undefined and results in a blank screen, we need to troubleshoot accordingly.

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) {
        // Subscribe to the observable for data retrieval
        mservice.stream1$.subscribe(value=>this.UiSelectedItem=value);
    }    
}

Answer №1

One essential tool to utilize is the Subject. If you're familiar with Angular's EventEmitter, you'll recognize that it functions similarly to a Subject. Typically, we use EventEmitter to relay events from child components to parent components.

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

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

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

If you have experience in using this pattern before, you understand the concept of publish/subscribe involved. Essentially, one entity subscribes to an event while another publishes it. This is where a Subject comes into play. It's worth noting that EventEmitter is a specific type of Subject.

In certain scenarios, relying solely on a vanilla Subject may not suffice. The issue arises when an event is emitted and no one is actively subscribed to it, resulting in missed notifications. To address this, consider using a ReplaySubject, which allows you to maintain a buffer with a customizable size to capture emitted events regardless of the timing of subscriptions.

Here's an implementation 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);
  }
}

To publish an item, simply set it within the service:

service.selectedItem = 'new item';

For components subscribing to this data:

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

Explore Further:


UPDATE

Demonstration available on Plunker

Answer №2

It is recommended to employ the Observable.create method in place of using new Observable

For more information, refer to: RxJs documentation

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Opting for a .catch over a try/catch block

Instead of using a traditional try/catch to manage errors when initiating requests like the example below: let body; try { const response = await sendRequest( "POST", "/api/AccountApi/RefundGetStatus", JSON.stringify(refundPara ...

Enforce directory organization and file naming conventions within a git repository by leveraging eslint

How can I enforce a specific naming structure for folders and subfolders? I not only want to control the styling of the names (kebab, camel), but also the actual names of the folders and files themselves. For example, consider the following paths: ./src/ ...

Struggling to grasp the syntax of RxJS filter

Trying to wrap my head around a filter expression in an Ionic/Angular project. Here's the code snippet: private userId$ = this.authService.currentUserAuth$.pipe( filter(user => !!user), map((user) => user.uid) ); The authservice is of ...

Unlock the contents of a directory using a .htaccess file

My directory setup looks something like this: www.examplelink.com/angular/dist/my-app. I need to reach this directory when going to the link : www.examplelink.com/angular. What would be the best way to achieve this using htaccess? ...

The promise chain from the ngbModal.open function is being bypassed

I'm currently working on implementing data editing within a component. My task involves checking if any of the data fields have been altered, and if so, prompting a confirmation pop-up to appear. If the user confirms the change, the data will then be ...

The argument passed to the AsyncPipe is not valid: '[object Object]'

Provided as shown below: public currentDBUserBS$: any; constructor(private afDb: AngularFireDatabase){} fetchUser(uid){ this.afDb.object(`users/${uid}`).valueChanges().subscribe((dUser) => { if (dUser) { this.currentDBUserBS$ = dUser; ...

Please eliminate the notification stating "The baseHref option is deprecated, instead use the baseHref option directly in the browser builder."

After updating my project to Angular version 11, I encountered an error when trying to run it: "Option baseHref is deprecated, use baseHref option in the browser builder itself". I attempted to add baseHref: "/certs/" in angular.json, but the error persis ...

Observing the completion of a subscriber function

Is there a more streamlined way to determine if the subscriber has finished executing or return something and catch it up-stream? Consider the following code snippets: this._subscriptions.push(this._client .getCommandStream(this._command) // R ...

When clicking, clear the selected items and avoid the function from repeatedly executing

I am currently facing issues with implementing mat-select-autocomplete in my project. Firstly, I have noticed that the function's (selectionChange)="getSelectedOptions($event)" is triggered every time I click on mat-select-autocomplete. Is there a wa ...

Encountering a new challenge in Angular: The error "InvalidPipeArgument: '' for pipe 'AsyncPipe'

Whenever I try to fetch data from the server, these errors keep popping up. This code was written by someone else and I would like to improve upon it. Could anyone suggest the best approach to handle this situation? Are there any coding patterns that sho ...

Tips for ensuring your controls function properly and seamlessly when switching to another page

I utilized the instructions from this post to implement a slider. However, I encountered an issue with the controller when navigating to subsequent pages. While the controller functions correctly on the initial page, it duplicates the same values on the fo ...

The container is not adjusting to the screen size correctly and the flex-direction: row is not functioning as

Struggling with setting up a basic layout in Angular for my application. While I have experience with Angular, the actual HTML/CSS design is new to me. No matter what I try, I can't seem to get this container to take up the whole screen width. Variou ...

How can you debug a Node.js CLI tool using WebStorm?

Struggling to develop a CLI tool using TypeScript within WebStorm as my IDE. No matter what I try, debugging just won't work for me. My journey in Node.js CLI programming started with this tutorial. Successfully transpiling the TS source with npx tsc, ...

Transitioning from angular 7 to the latest version 12

Upgrading from Angular 7 to 12 has presented a series of issues for me. The main problem seems to be with Angular Material. I am looking for a solution to this. ./src/app/material.module.ts:13:89-110 - Encounter Error: 'MatAutocompleteModule' ( ...

The Angular custom modal service is malfunctioning as the component is not getting the necessary updates

As I develop a service in Angular to display components inside a modal, I have encountered an issue. After injecting the component content into the modal and adding it to the page's HTML, the functionality within the component seems to be affected. F ...

Tips for integrating jsPDF with Angular 2

Encountering Error: jsPDF is not defined, while implementing the code below: import { Component, OnInit, Inject } from '@angular/core'; import 'jspdf'; declare let jsPDF; @Component({ .... providers: [ { provide: 'Window&a ...

What purpose does the class serve in typescript?

This is a unique version of app.component.ts in the Angular Tour of Hero tutorial. import { Component } from '@angular/core'; export class Superhero{ name : string; id : number; } const SUPERHEROES : Superhero[] = [ {name : 'Wonder ...

Angular: The type '"periodic-background-sync"' cannot be assigned to type 'PermissionName'

I am trying to enable background sync, but I keep encountering an error when I try to enter the code. Why can't it be found? Do I need to update something? This is my code: if ('periodicSync' in worker) { const status = await navigato ...

"Exploring Angular 9: A guide to retrieving form data with an array of objects [Revised as of July 29th, 2020

I am encountering an issue with my Angular 9 form code. I am getting the error "ERROR TypeError: Cannot read property 'mobile_number' of undefined" and I need help in resolving this problem. <form (ngSubmit)="processForm()"> & ...

Exploring the method of retrieving nested JSON objects in Angular

When my API sends back a JSON response, my Angular application is able to capture it using an Interface. The structure of the JSON response appears as follows: { "release_date":"2012-03-14", "genre_relation": ...