having difficulties with angular subscribing to an observable

I am currently working on a service that retrieves a post from a JSON file containing an array of posts. I already have a service in place that uses HttpClient to return the contents of a JSON file. The main objective is to display the full content of the post.

Here is the service responsible for retrieving the JSON file:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root'
})
export class GetJsonFileService {

  constructor(private http: HttpClient) {}

  getJsonFile(jsonFile: string /* the file path is set by components */) {
    return this.http.get(jsonFile,{observe: 'body', responseType: 'json'});
  }
}

And here is the service designed to retrieve a specific post by its ID:

import { Injectable } from '@angular/core';
import { GetJsonFileService } from './get-json-file.service';

@Injectable({
  providedIn: 'root'
})
export class GetPostService {

  constructor(private getJsonFileservice: GetJsonFileService) {}

  getPost(id: number): object {
    let post!: object;
    this.getJsonFileservice.getJsonFile('assets/posts.json').subscribe((data: any) => {
      post = data["posts"][id];
    });
    return post;
  }

}

Lastly, we have the component responsible for displaying the post:

import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { GetPostService } from '../services/get-post.service';

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

  _post!: object;
  id!: number;

  constructor(private route: ActivatedRoute, private getPost: GetPostService) {}

  ngOnInit() {
    let id!: number;
    this.route.params.subscribe(params => {
      id = params.id;
    });
    this._post = this.getPost.getPost(id);
  }
}

When attempting to display something in the component template like: {{_post.title}}

An error occurs stating:

Errors while compiling. Reload prevented.

In Visual Studio Code, TypeScript points out:

Property 'title' does not exist on type 'object'

I have tried @msanford's solution, but there is still one issue regarding 'posts[\"posts\"][id]' in the post-view component that needs to be addressed. Unfortunately, I am unsure of how to resolve it: posts["posts"][id] TypeScript throws an error:

Element implicitly has an 'any' type because expression of type '"posts"' can't be used to index type 'Object'.
  Property 'posts' does not exist on type 'Object'

Any suggestions or ideas?

Answer №1

Your post has been identified as an object type: _post!: object; However, it appears that the property 'title' does not exist within the 'object' type.

To address this issue, consider creating an interface or class that defines the fields present in a post. For example:

interface Post {
  id: number;
  title: string;
  body: string;
  author: string;
  // add more fields as needed
}

You can then use this interface in your type declaration: _post: Post;

In addition, keep in mind that subscribing to data should be done in the component rather than the service. Adjust your code as follows:

// Service
getPost = (): Post => this.getJsonFileservice.getJsonFile<Post[]>('assets/posts.json')

Then subscribe in your Component:

ngOnInit(){
    let id: number;

    this.route.params.subscribe(
        params => id = params.id,
        error => console.error,
        complete => {
          this.getPost.getPost().subscribe(
            posts => this._post = posts["posts"][id],
            error => console.error
          );
        }
    );    
  }

Furthermore, there was previously a race condition where you could request a post before receiving the ID parameter from the router. To prevent errors, maintain the usage of the non-null-assertion operator id !: number.

Answer №2

If you're encountering a situation where you're returning the post before it's properly assigned, then you have a problem:

post = data["posts"][id];

An effective solution is to return an observable and subscribe to it whenever you need access to the value.

Be sure to carefully review the Documentation to gain a solid understanding of how observables operate.

Visit this link for more information on observables in Angular

Answer №3

When working with Angular and Typescript, you'll need to define the type of _post either as any or create a custom interface/type with the specific fields you anticipate.

Alternatively, you could implement the following approach:

export class PostViewComponent implements OnInit {

  _post!: {
      title: string
  };
  id!: number;

  constructor(private route: ActivatedRoute, private getPost: GetPostService){}

  ngOnInit(){
    var id!: number;
    this.route.params.subscribe(params=>{
      id = params.id;
    });
    this._post = this.getPost.getPost(id);
  }
}

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

Angular 7 flex layout ensures that the table fills its parent container completely without overstretching it

Hello, I'm encountering a problem with the sample found on StackBlitz. My goal is to confine the table to one page and have the remaining height filled after the header. If the table exceeds this height, I would prefer it to be hidden. However, based ...

Exception occurs when arrow function is replaced with an anonymous function

Currently, I am experimenting with the Angular Heroes Tutorial using Typescript. The code snippet below is functioning correctly while testing out the services: getHeroes() { this.heroService.getHeroes().then(heroes => this.heroes = heroes); } H ...

Navigating focus within form elements using Angular techniques

Purpose There is a form with various input elements (el1, el2 ...) el1 may or may not have initial focus when a keydown event occurs, the following actions should be taken: If none of the input elements are in focus, move focus to the first non-empty e ...

Guide on navigating to a different page using a function with router link in Angular using TypeScript

Trying my hand at Angualar and Typescript for the first time. I am working on creating a login page where users can move to another page if their credentials are correct. To achieve this, I want to use a function that is triggered by clicking a button. How ...

Exploring the Power of Nested *ngFor in Angular 2

I am struggling with passing indexes to a function where the first parameter (ii) is coming back as undefined. <div *ngFor="let tab of screen.data.tabs; let indexTab = i;"> <div *ngIf="tab.active"> <div *ngIf="tab.questions"&g ...

You cannot use Angular 5 to send a post request with a token that has been retrieved

Hello, I'm facing an issue with making a post request in Angular 5. The token I retrieve seems correct as it works fine when tested with Postman. Can someone provide me with a hint or suggestion on what could be going wrong? AuthService.ts getProfi ...

A comprehensive guide on constructing a literal object in Typescript by combining an array with an object

Recently, I came across this Typescript code snippet: type SortedList = T[] & {_brand: "sorted" }; function binarySearch<T>(xs: SortedList<T>, x: T): boolean let low = 0; let high = xs.length - 1; while (high ...

I am unfamiliar with this scenario but I can utilize Axios, async/await, and TypeScript to navigate it

Having trouble creating a workflows list from an axios response Error: Argument of type 'Promise<unknown>' is not assignable to parameter of type 'SetStateAction<WorkflowForReactFlowProps[] | null>'. Here's the Axios c ...

Comparing vue.component to using import statements inside a component

After setting up a vue2 library using vue-cli, I have numerous components included in the index.ts file as shown below: import MyComponent1 from './components/MyComponent1.vue'; import MyComponent2 from './components/MyComponent2.vue'; ...

The element is implicitly assigned an 'any' type as the expression of type 'string' is unable to be used as an index within the type '{...}'

Trying to improve my react app with TypeScript, but encountering issues when typing certain variables. Here's the error message I'm facing: TypeScript error in /Users/SignUpFields.tsx(66,9): Element implicitly has an 'any' type becaus ...

What is the best method for dividing a user interface into several arrays of keys, each grouped by type?

Given a simple structure: structure IPerson { firstName: string; lastName: string; age: number; city: string; favoriteNumber: number; isMarried: boolean; hasDriverLicense: boolean; } How do I create arrays containing keys grouped by data typ ...

Is there a way to access and troubleshoot the complete source code within .vue files?

I've been struggling for hours trying to understand why I'm unable to view the full source of my .vue files in the Chrome debugger. When I click on webpack://, I can see the files listed there like they are in my project tree, but when I try to o ...

Using TypeScript to return an empty promise with specified types

Here is my function signature: const getJobsForDate = async (selectedDate: string): Promise<Job[]> I retrieve the data from the database and return a promise. If the parameter selectedDate === "", I aim to return an empty Promise<Job[] ...

What is the process for implementing a pipe to establish data binding?

I've been trying to use a pipe for data binding in Angular, but it's not working as expected. Previously, I had this: [message]="enum.text" and now I want to replace enum.text with a custom pipe. Here's what I tried: [text]=" '' ...

Dynamically resizing a property in the DOM with Angular

Could someone help me with an issue I'm having regarding resizing items on the screen in Angular when the browser window size changes? Here is my code snippet: // TS File height: number = 2.5; objHeight:number; screenHeight:number = window.innerHeig ...

What is the best way to retrieve a data type from an array using typescript?

Can Typescript automatically declare a type that retrieves the inner type of an array? For instance: Assume the following code snippet already exists: export interface Cache { events: Event[], users: User[] } type CacheType = Event[] | User[]; ...

What is the significance of the message "JavaScript files do not have any valid rules specified"?

I am working on a React - Typescript project that was created using the following command: create-react-app my-app --scripts-version=react-scripts-ts While it compiles without any issues, I keep receiving a message or warning that says: No valid rules h ...

Error in TypeScript when using keyof instead of literal in type pattern.Beware of TypeScript error when not

let c = { [X in keyof { "foo" }]: { foo: "bar" } extends { X } ? true : false }["foo"]; let d = { foo: "bar" } extends { "foo" } ? true : false; c and d should both return true, but surprisingly, c is eval ...

When a URL is triggered via a browser notification in Angular 2, the target component ceases to function properly

Whenever I access a URL by clicking on a browser notification, the functionality of the page seems to stop working. To demonstrate this issue, I have a small project available here: https://github.com/bdwbdv/quickstart Expected behavior: after starting t ...

How do I transfer a PDF received from a third-party to my client using a REST API on the backend?

After receiving a PDF from a third party, I stored the file on S3. Upon checking the file on S3, I was able to view the PDF without any issues. However, when sending the PDF to the client and verifying it using Postman, an empty PDF is displayed. Below is ...