Loading JSON Without an HTTP Request

放肆的年华 提交于 2020-01-14 14:54:06

问题


I am working on a project using Angular 4, NPM, Node.js, and the Angular CLI.

I have a rather unusual need to load JSON into an Angular service (using an @Injectable) without an HTTP request, i.e. it will always be loaded locally as part of the package, and not retrieved from a server.

Everything I've found so far indicates that you either have to modify the project's typings.d.ts file or use an HTTP request to retrieve it from the /assets folder or similar, neither of which is an option for me.

What I am trying to accomplish is this. Given the following directory structure:

/app
    /services
        /my-service
            /my.service.ts
            /myJson.json

I need the my.service.ts service, which is using @Injectable, to load the JSON file myJson.json. For my particular case, there will be multiple JSON files sitting next to the my.service.ts file that will all need to be loaded.

To clarify, the following approaches will not work for me:

Using an HTTP Service to Load JSON File From Assets

URL: https://stackoverflow.com/a/43759870/1096637

Excerpt:

// Get users from the API
return this.http.get('assets/ordersummary.json')//, options)
    .map((response: Response) => {
        console.log("mock data" + response.json());
        return response.json();
    }
    )
    .catch(this.handleError);

Modifying typings.d.ts To Allow Loading JSON Files

URL: https://hackernoon.com/import-json-into-typescript-8d465beded79

Excerpt:

Solution: Using Wildcard Module Name In TypeScript version 2 +, we can use wildcard character in module name. In your TS definition file, e.g. typings.d.ts, you can add this line:

declare module "*.json" {
    const value: any;
    export default value;
}

Then, your code will work like charm!

// TypeScript
// app.ts
import * as data from './example.json';
const word = (<any>data).name;
console.log(word); // output 'testing'

The Question

Does anyone else have any ideas for getting these files loaded into my service without the need for either of these approaches?


回答1:


You will get an error if you call json directly, but a simple workaround is to declare typings for all json files.

typings.d.ts

declare module "*.json" {
   const value: any;
   export default value;
}

comp.ts

import * as data from './data.json';



回答2:


The solution I found to this was using RequireJS, which was available to me via the Angular CLI framework.

I had to declare require as a variable globally:

declare var require: any;

And then I could use require.context to get all of the files in a folder I created to hold on the types at ../types.

Please find below the entire completed service that loads all of the JSON files (each of which is a type) into the service variable types.

The result is an object of types, where the key for the type is the file name, and the related value is the JSON from the file.

Example Result loading files type1.json, type2.json, and type3.json from the folder ../types:

{
    type1: {
        class: "myClass1",
        property1: "myProperty1"
    },
    type2: {
        class: "myClass2",
        property1: "myProperty2"
    },
    type3: {
        class: "myClass3",
        property1: "myProperty3"
    }
}

The Final Service File

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

declare var require: any;

@Injectable()
export class TypeService {

    constructor(){
        this.init()
    };

    types: any;

    init: Function = () => {

        // Get all of the types of branding available in the types folder
        this.types = (context => {

            // Get the keys from the context returned by require
            let keys = context.keys();

            // Get the values from the context using the keys
            let values = keys.map(context);

            // Reduce the keys array to create the types object
            return keys.reduce(
                (types, key, i) => {

                    // Update the key name by removing "./" from the begining and ".json" from the end.
                    key = key.replace(/^\.\/([^\.]+)\.json/, (a, b)=> { return b; });

                    // Set the object to the types array using the new key and the value at the current index
                    types[key] = values[i].data; 

                    // Return the new types array
                    return types; 
                }, {}
            );
        })(require.context('../types', true, /.json/));
    }
}



回答3:


You can directly access variables in services from their object that is defined in the constructor.

...So say your constructor loads the service like this

constructor(private someService:SomeService){}

You can just do someService.theJsonObject to access it.

Just be careful not to do this before it gets loaded by the service function that loads it. You'd then get a null value.


You can assign variables to your service files the same way you do in component files.

Just declare them in the service

public JsonObject:any;

And (easiest way) is to let the function that called your service assign the JSON object for you.

So say you called the service like this

this.serviceObject.function().subscribe
(
  resp =>
  {
    this.serviceObject.JsonObject = resp;
  }
);

After this is done once, other components can access that JSON content using someService.theJsonObject as discussed earlier.


In your case I think all you need to do is embed your JSON object in your code. Maybe you can use const. That's not bad code or anything.



来源:https://stackoverflow.com/questions/44313054/loading-json-without-an-http-request

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!