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

Creating detailed documentation comments for TypeScript within Visual Studio

When using C# with ReSharper and StyleCop, I am able to automatically generate basic documentation comments for methods. This includes sections such as: /// <summary> /// The login. /// </summary> /// <param name="returnUrl" ...

The sanitizer variable becomes null when accessed outside of the NgOnInit function in Angular using TypeScript

At first, I added DomSanitizer to the component: import { DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; Next, a class was created and included in the constructor: export class BlocklyComponent implements OnInit { primar ...

The geolocation feature is operational in the browser test, but it is not functioning properly on the

I am currently creating an application that requires accessing the user's location at a specific point in time. To achieve this, I have utilized the ionic native geolocation feature which communicates with the Google API for reverse geocoding. Everyt ...

Tips for transmitting data from Dart to Typescript Cloud functions, encountering the UNAUTHENTICATED error code

Snippet of Dart code with token passed to sendToDevice: Future<void> _sendNotification() async { CloudFunctions functions = CloudFunctions.instance; HttpsCallable callable = functions.getHttpsCallable(functionName: "sendToDevice"); callable.c ...

Customizing Angular 2's Webpack environment setup dynamically

Currently, I have set up Webpack to compile my Angular project. Within my project, there is an important file called env.js: module.exports.ENV = { API_URL: "http://localhost:5001/", ... }; In the webpack.common.js file, I am referencing this file l ...

I am trying to replace the buttons with a dropdown menu for changing graphs, but unfortunately my function does not seem to work with the <select> element. It works perfectly fine with buttons though

I am currently working on my html and ts code, aiming to implement a dropdown feature for switching between different graphs via the chartType function. The issue I am facing is that an error keeps popping up stating that chartType is not recognized as a ...

Caution: The `id` property did not match. Server: "fc-dom-171" Client: "fc-dom-2" while utilizing FullCalendar in a Next.js environment

Issue Background In my current project, I am utilizing FullCalendar v5.11.0, NextJS v12.0.7, React v17.0.2, and Typescript v4.3.5. To set up a basic calendar based on the FullCalendar documentation, I created a component called Calendar. Inside this comp ...

How do I retype an interface from a dependency?

It's difficult to put into words, so I have created a repository for reference: https://github.com/galenyuan/how-to-retyping My goal is to achieve the following: import Vue from 'vue' declare module 'vuex/types/vue' { interfac ...

Finding Nested Key Paths in TypeScript for Objects and Arrays

I am in search of a unique method to create a TypeScript type that can take an object type and retrieve all the nested key paths, including properties within arrays as well. I want to exclude any default array properties such as "push" or "pop." While I ha ...

Angular5+ Error: Unable to retrieve summary for RouterOutlet directive due to illegal state

When attempting to build my Angular App using ng build --prod --aot, I consistently encounter the following error: ERROR in : Illegal state: Could not load the summary for directive RouterOutlet in C:/Path-To-Project/node_modules/@angular/Router/router.d. ...

Different ways to prevent invalid entries in an input field with type datetime-local

<input type="datetime-local" step="1"> Is there a way to prevent invalid date input? For example, entering a date like "11:11:1111" in the format "mm-dd-yyyy". How can this be addressed using Moment.js? ...

Dealing with 401 Unauthorized error and CORS issues in Angular POST requests to a .NET Core Web Api

My front-end and back-end projects are separate, using Angular for the front-end and .NET Core WEB Api for the back-end. I have successfully set up CORS and windows AD authentication. While GET calls work fine, I am experiencing issues with POST requests. ...

Is there a program available that can efficiently convert or translate JSON objects into TypeScript types or interfaces?

Can anyone recommend a tool that can easily convert a JSON object into a TypeScript type or interface? An example input would be something like this: I'm hoping to paste the JSON object into the tool and receive an output structure similar to: expor ...

How can I retrieve the /api/auth/me resource serverside using the NextJS AppRouter?

I am looking to implement app router in my Next.js project and have encountered an issue. In order for my app to function properly, I need to make a call to /api/auth/me which will return either a user object or null if the user is not logged in. To achiev ...

Tips for creating TypeScript Google Cloud Functions using webpack

I'm currently facing a challenge while coding a Google Cloud Function using TypeScript. The concept involves having handler functions defined for various Cloud Functions in separate files within the source repository, along with some code that is shar ...

Using nodemailer to send an email with a dynamic variable that holds the HTML content

I am attempting to send a variable containing HTML code from a Vue component using the POST method. My technology stack includes TypeScript, Nuxt.js, Node.js, and Vue.js. const order_list = document.querySelector('table') as HTMLInputElement | n ...

What is the process for creating a new Object based on an interface in Typescript?

I am dealing with an interface that looks like this: interface Response { items: { productId: string; productName: string; price: number; }[] } interface APIResponse { items: { productId: string; produc ...

Arrange a collection of objects by two criteria: the end time, followed by the status in accordance with the specified array order if the end times are equal

Is this the best method to arrange data by using infinity? I gave it a try but it doesn't quite meet my requirements. data = [{ "status": "Accepted", "endTime": "" }, { "status": "New", ...

Installation of ag-grid was unsuccessful

Having trouble with this command and error message, any suggestions on how to resolve it? npm install --save ag-grid-community ag-grid-angular https://www.ag-grid.com/angular-grid/getting-started/ ...

Sending every piece of information to the URL may not be the most efficient approach, in my opinion

Lately, I have incorporated NodeJS into my Angular project and here is how I am currently implementing it: Node : app.get('/register/:username/:password', function(req, res){ db.collection('users').insertOne({ username: req ...