Search code examples
javascriptangularfrontendsingle-page-applicationsanity

Angular4 Injecting Service class - code in constructor not finished when service method called?


I'm trying to get into Angular4/5. I have a connection to a CMS service called Sanity (https://www.sanity.io/). The issue I am having is that this service is injected to a ProductsComponent class and I call methods in that service at the component's ngOnInit method. However I am getting the following error when I try to recompile using ng serve command:

ERROR in src/app/sanity.service.ts(21,14): error TS2339: Property 'fetch' does not exist on type 'object'.

Here is the component where I inject the service:

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Query } from '@angular/core/src/metadata/di';
import { SanityService } from '../sanity.service';

@Component({
    selector: 'app-product',
    templateUrl: './products.component.html',
    styleUrls: ['./products.component.css']
})
export class ProductsComponent implements OnInit {

    products: object[];

    constructor(private http: HttpClient, private sanityService: SanityService) { }

    ngOnInit() {

        this.sanityService.getProducts((res) => {
            this.products = res;
        });

    }

}

here is the service code (sanity.service.ts):

import { Injectable } from '@angular/core';
//const sanityClient = require('@sanity/client');
import * as SanityClient from '@sanity/client';

@Injectable()
export class SanityService {

    sanityClient: object;

    constructor() {
        this.sanityClient = SanityClient({
            projectId: 'someidhere',
            dataset: 'somedatabase',
            useCdn: true
        });
    }

    getProducts(callback) {
        let query = "*[_type == 'product']{ name, _id, description, price, 'imageUrl': image.asset->url }";
        this.sanityClient
            .fetch(
                query, // Query
                {} // Params (optional)
            ).then(res => {
                //console.log('5 movies: ', res)
                //this.products = res;
                callback(res);
            }).catch(err => {
                console.error('Oh no, error occured: ', err)
            });
    }



    getProductById(id, callback) {
        var query = `*[_id == '${id}']{ name, _id, description, price, 'imageUrl': image.asset->url }`;
        this.sanityClient
            .fetch(
                query, // Query
                {} // Params (optional)
            ).then(res => {
                //console.log('PRODUCT: ', res)
                //this.products = res;
                callback(res);
            }).catch(err => {
                console.error('Oh no, error occured: ', err)
            });
    }

}

My suspicion is that the object being created/set in the service's constructor is yet to finish 'loading' when the 'getProducts()' function is called and thus, the 'fetch' property does not exist error.

I'm really stumped here...can someone help me out?

Also here is my app.component.ts just in case:

import { Component } from '@angular/core';
import { SanityService } from './sanity.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [SanityService]
})
export class AppComponent {
  title = 'app';

  constructor(private sanityService: SanityService) {}
}

Solution

  • Try to type your SanityClient as any or, if you have typings included, as SanityClient. Typing as an object tells TypeScript to treat it as a plain object without any additional function, therefore this error is emitted!

    So changing sanityClient: object to sanityClient: any should allow your application to compile.