The Angular2 view is failing to display updated data from a shared service

I've been struggling to show data from my shared service, but it's not displaying. Can someone please help me out? I've been stuck on this for the past few days. I've tried NgZone and ChangeDetectorRef, but they haven't worked for me.

home.component.html

<div *ngFor="let order of orders " class="order-cards">
    <div class="order-card">
        <div class="btn-order-card">
            <button type="submit" class="btn btn-success " (click)="viewOrder(order)">View the Order </button>
        </div>
    </div>
</div>

home.component.ts

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


import { SharedService } from '../services/shared.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {

  constructor( private route: Router, private sharedService: SharedService) { }

  ngOnInit() {
  }

  viewOrder(order) {
    this.route.navigate(['../view-order'])
    this.sharedService.viewOrderValues(order);
  }
  
}

shared.service.ts

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

Injectable()

export class SharedService {
    constructor() { }
    private viewOrderSource = new Subject<any>();

    viewOrder$ = this.viewOrderSource.asObservable();

    viewOrderValues(data: any) {
        this.viewOrderSource.next(data);
        return data;
    }
}

view-order.component.ts

import { Component, OnInit } from '@angular/core';

import { SharedService } from '../services/shared.service';

@Component({
  selector: 'app-view-order',
  template: '{{orderValues}}',
  styleUrls: ['./view-order.component.scss']
})
export class ViewOrderComponent implements OnInit {
  orderValues: any;
  constructor(private sharedService: SharedService) {
  }
  ngOnInit() {
    this.sharedService.viewOrder$.subscribe((data) => {
      this.orderValues = data;
    });
  }
}

Answer №1

I believe your current method is not correct.

It would be better to utilize the routing-based Resolve approach and pass the parameter as an ID to the component, enabling you to retrieve the data upon component loading.

To implement this, modify your shared.service.ts to support ID-based search:

@Injectable()
export class SharedService {
  private orders = [];  // initialize or fetch from service, I'm not sure
  ordersChanged = new Subject<any[]>();

  constructor() { }

  addOrder(order: any) {
    this.orders.push(order);
    this.ordersChanged.next(this.getOrders());
  }

  getOrders(): any[] {
    return this.orders.slice();
  }

  getOrder(id: number) {
    // Your logic to find the order based on the ID
    return this.orders[id];
  }
}

In your home.component.html:

<div *ngFor="let order of orders; let i = index" class="order-cards">
    <div class="order-card">
        <div class="btn-order-card">
            <button 
                type="submit"
                class="btn btn-success"
                (click)="viewOrder(i)">View the Order</button>
        </div>
    </div>
</div>

And make corresponding changes in your home.component.ts:

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit, OnDestroy {
  orders: string[];
  subscription: Subscription;

  constructor(private route: Router, private sharedService: SharedService) { }

  ngOnInit() {
    this.orders = this.sharedService.getOrders();
    this.subscription = this.sharedService.ordersChanged.subscribe(orders => this.orders = orders);
  }

  viewOrder(index: number) {
    this.route.navigate(['/view-order', index])
  }

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

}

You can create an OrderResolver service:

@Injectable()
export class OrderResolver implements Resolve<any>{
    constructor(private sharedService: SharedService) { }

    resolve(
        route: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): string | Observable<string> | Promise<string> {
        const id = +route.params['id'];
        return this.sharedService.getOrder(id);
    }

}

After injecting a Router, you can handle scenarios where there is no order for the provided ID easily using the above code snippet.

In your routing module class, update the view-order path to accept an ID parameter and use a resolver to fetch the order during route loading:

  {
    path: 'view-order/:id',
    component: ViewOrderComponent,
    resolve: { order: OrderResolver }
  }

Lastly, in your ViewOrderComponent:

export class ViewOrderComponent implements OnInit {
  orderValues: any;
  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    this.orderValues = this.route.snapshot.data['order'];
  }
}

Answer №2

modification

modify the declaration of viewOrderSource to use a BehaviorSubject with an initial value of null: 

replace

private viewOrderSource = new Subject<any>(); 

with

private viewOrderSource = new BehaviorSubject<Object>(null);

inside shared-seriice.ts

Answer №3

To ensure Angular detects changes, you need to update the list by creating a copy of the data. Simply resetting the data won't trigger the change detection.

For arrays, use: this.arrayName = this.arrayName.slice(); For objects, use: var newObj = Object.assign({}, oldObj)

Answer №4

Attempt to perform the following actions:

this.sharedService.displayOrderDetails(order);
this.router.navigate(['../order-details'])

It seems like you are initiating navigation first, which prevents the function from executing and as a result, your observer is not triggered.

Answer №5

In the home.component.html file, there is a reference to a variable called "orders". However, this variable is not defined in the home.component.ts file. One way to solve this issue is by saving the data returned from your service as an instance variable and then referencing it in your HTML code.

Alternatively, you can directly bind to the observable returned by your service in the HTML file.

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

What is the best way to retrieve the value of a textbox in AngularJS?

Trying my hand at creating a basic web page using angular. I've got 2 textboxes and 2 buttons - one to set a predefined value in a textbox, and the other to add some text. Here's the code snippet: <!DOCTYPE html> <html lang="en" ng-app ...

What is the best way to target and manipulate the transform property of multiple div elements in JavaScript?

Looking at this code snippet, my goal is to have all the boxes rotate 180deg with a single click, without needing to apply different ID names: function rotateAllBoxes() { var boxes = document.getElementsByClassName("box"); for (var i = 0; i < box ...

What is the best way to display a single instance of a React component that is declared in multiple locations within the app?

Imagine I have 2 main components, A and B. Now, component C needs to be created inside both A and B. How can I guarantee that the same exact instance of C is generated in both places? Essentially, I want them to stay synchronized - any changes made to one ...

The mysterious case of the missing currentUserObj in Angular with rxjs Subject

I've encountered an issue while trying to pass data from my login component to the user-profile component using an rxjs subject. Despite calling the sendUser method in the login component and subscribing to the observable in the user-profile component ...

An application running on Node.js/Express and hosted on Digital Ocean encounters the "Cannot get /" error message

Despite searching extensively online and sifting through numerous solutions to different scenarios, I remained unable to find a fix that resolved my issue. When attempting to run my server.js file locally, everything operates smoothly. However, upon transf ...

Efficiently uploading images with AJAX when submitting a form

I am attempting to upload an image along with other variables in a form submission, and then execute my PHP code to store the image in the user's profile_picture table. I want the image upload to be integrated within the same form used for saving dat ...

Is it possible to configure Nginx mime types within a Docker container?

My docker-compose.yml file looks like this: version: "1.0" services: web: container_name: webserver image: nginx volumes: - ./nginx.conf:/etc/nginx/nginx.conf:ro - ./frontend:/frontend ports: - "8001:80&qu ...

I am unable to modify values using ngModel

I am struggling to update the value in my service.year.ts file but it seems impossible... <select name="selectedyear" [disabled]="disabledPeriod" [(ngModel)]="selectedyear" (ngModelChange)="onChangeYear()"> <option [ngValue]="selectedyear" ...

AngularJS - Setting an initial delay for ng-bind

We have a span element with the following attributes: <span role="link" ng-show="showLink()" ng-bind="textLink"></span> (Just an fyi: we implemented a fade-in, fade-out animation for this link, hence the use of ng-show instead of ng-if) The ...

Passing a variable to a modal in AngularJS

In my project, I am utilizing https://github.com/simpulton/angularjs-wizard and have made some modifications to it (specifically changed var app to $scope). It is functioning well, however, I am facing an issue where I need to pass a variable to the open f ...

Expand the initial expansion panel within an Angular Material accordion by opening the first attachment

In Angular Material expansion panels, the expanded input can be used to automatically open a specific panel when the page loads. However, in my dynamic accordion where all panels are optional, I want the first panel to be opened by default. I could manual ...

Troubleshooting issues with Firebase integration in a Node.js environment

I am currently encountering difficulties implementing Firebase in my Node.js project. Below is the code snippet that I am attempting to execute on Node. var firebase = require("firebase"); var admin = require("firebase-admin"); var serviceAccount = requi ...

What is the best way to identify which JavaScript code is triggering or managing an event?

In the development of an HTML5 application framework designed for businesses to use on their intranet and extranet sites, a SAP JEE application server is utilized. The framework incorporates the grid system known as "Semantic UI" along with various JavaScr ...

Mastering the Art of Modifying HTML with Node.js

Is it possible to manipulate HTML using Node.js? 1. First, I need to retrieve data from a database. 2. Then, I need to modify or add HTML code within Node. In essence, the goal is to fetch data and integrate it into an HTML file. The JavaScript snippet ...

What is causing my Bootstrap Controls to malfunction?

I'm trying to create a Bootstrap carousel that shows 3 items at once and includes controls to switch between them. The carousel I've made does display the three items, but for some reason, the controls are not responding when clicked. I'm un ...

Is it possible for me to reconstruct the "reducer" each time the useReducer hook is rendered?

Here is an example taken from: https://reactjs.org/docs/hooks-reference.html#usereducer const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; ...

Trouble with firing the click event using document.createElement('a') in Firefox

I wrote a function that fetches arraybuffer data from my API, generates a temporary anchor element on the webpage, and then triggers a click event to download the file. Interestingly, this function performs as expected in Chrome. @action async loadVouc ...

Customize the text for the material icon

Can I customize an icon by using the following code: import FiberNewIcon from "@mui/icons-material/FiberNew"; Is there a way to add custom text to the icon? ...

Adding to and retrieving data from an array

I am relatively new to the world of JavaScript and jQuery, and I have spent the last three days working on a script. Despite my efforts to find a solution by searching online, I have been unsuccessful so far. It seems like my search skills are lacking. My ...

Utilize AngularJS to refine and sort through data retrieved from an API

I have an Angular application that is fetching hotel data from an API. I want to filter the results based on the minimum price of the hotels being less than $50. $http.get($rootScope.baseurl + 'api/hotels/', { params: { page_ ...