Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update .json file without rebuilding in angular cli?

I'm using angular cli to build a website which contains multiple languages. I use ng2-translate for the translations.

I import a languages.json file defined in angular-cli.json:

"assets": [
    "assets",
    "fonts",
    "languages.json"
  ],

In my controller, I retrieve the data using require:

this.languages = require('../../../../languages.json');

Loading the json file works. After deploying, I tried to change (add or remove) some languages in the languages.json, but the changes does not get shown in the website even though the json file is updated in dist. The only way I could update the website is by changing the original json file, making another build of the app and deploy again. Is there a way to make a change in the website by only updating the json file in dist?

For clarification, languages.json contains an array of language codes, which defines the languages shown in the language selector of the website. I hoped to use this config to change the languages shown in the website without rebuilding the app.

Here is my package.json :

{
"name": "myApp",
"version": "1.0.0",
"license": "MIT",
"scripts": {
  "ng": "ng",
  "start": "ng serve",
  "dev": "ng serve --environment=dev",
  "acc": "ng serve --environment=acc",
  "prod": "ng serve --environment=prod",
  "build:dev": "ng build --environment=dev",
  "build:acc": "ng build --environment=acc",
  "build:prod": "ng build --environment=prod",
  "build": "ng build",
  "test": "ng test",
  "lint": "ng lint",
  "e2e": "ng e2e"
},
"private": true,
"dependencies": {
  "@angular/animations": "^4.0.2",
  "@angular/common": "^4.0.0",
  "@angular/compiler": "^4.0.0",
  "@angular/compiler-cli": "^4.0.0",
  "@angular/core": "^4.0.0",
  "@angular/forms": "^4.0.0",
  "@angular/http": "^4.0.0",
  "@angular/platform-browser": "^4.0.0",
  "@angular/platform-browser-dynamic": "^4.0.0",
  "@angular/platform-server": "^4.0.0",
  "@angular/router": "^4.0.0",
  "angular2-localstorage": "git+https://github.com/zoomsphere/angular2-localstorage.git#master",
  "core-js": "^2.4.1",
  "foundation-sites": "^6.3.1",
  "ng2-translate": "^5.0.0",
  "rxjs": "^5.1.0",
  "zone.js": "^0.8.5"
},
"devDependencies": {
  "@angular/cli": "1.0.0",
  "@types/jasmine": "2.5.46",
  "@types/node": "~7.0.12",
  "codelyzer": "~3.0.0-beta.4",
  "jasmine-core": "~2.5.2",
  "jasmine-spec-reporter": "~3.2.0",
  "karma": "~1.5.0",
  "karma-chrome-launcher": "~2.0.0",
  "karma-cli": "~1.0.1",
  "karma-jasmine": "~1.1.0",
  "karma-jasmine-html-reporter": "^0.2.2",
  "karma-coverage-istanbul-reporter": "^1.0.0",
  "protractor": "~5.1.0",
  "ts-node": "~3.0.2",
  "tslint": "~4.5.1",
  "typescript": "^2.2.2"
}
like image 676
Tom Shen Avatar asked Apr 27 '17 08:04

Tom Shen


People also ask

Can I update JSON file in angular?

You can't change the content of JSON file directly through angular, you need the Backend in order to reflect the change on that JSON file.

What is config JSON file in angular?

The angular. json file at the root level of an Angular workspace provides workspace-wide and project-specific configuration defaults. These are used for build and development tools provided by the Angular CLI. Path values given in the configuration are relative to the root workspace directory.


2 Answers

It seems I have exactly the same issue right now and I used this tutorial : https://aclottan.wordpress.com/2016/12/30/load-configuration-from-external-file/

If I understand well, your need is to have an "external" variable you can modify without having to change app code and rebuild ?

If so, here what I did, applied to your exemple :

  • Keep your languages.json file in "assets" folder to make it available in dist folder.

In this demo i will use this for exemple :

{
  "languages": ["en", "fr"]
}
  • Add a languageFile property in environment files (environments.ts and environments.prod.ts) pointing to languages.json :

environment.ts :

export const environment = {
    production: false,
    languageFile: 'assets/languages.json'
};

environment.prod.ts :

export const environment = {
    production: true,
    languageFile: 'assets/languages.json'
};
  • Create a class that represent what you have in your JSON file languages.json

For exemple:

export class Configuration {
  languages: string[];
}
  • Create a service that will load this configuration :
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Configuration } from './configuration';

@Injectable()
export class ConfigService {
  private config: Configuration;

  constructor(private http: Http) {
  }

  load(url: string) {
    return new Promise((resolve) => {
      this.http.get(url).map(res => res.json())
        .subscribe(config => {
          this.config = config;
          resolve();
        });
    });
  }

  getConfiguration(): Configuration {
    return this.config;
  }

}
  • In your main module, usually AppModule, add following imports :
import { APP_INITIALIZER } from '@angular/core';
import { HttpModule } from '@angular/http';
import { ConfigService } from './config.service';
import { environment } from '../environments/environment';
  • Still your main module, add a load function (outside of the module) :
export function ConfigLoader(configService: ConfigService) {  
  return () => configService.load(environment.languageFile); 
}
  • Still in your main module, add the 2 following providers :
providers: [
    ConfigService,
    {
      provide   : APP_INITIALIZER,
      useFactory: ConfigLoader,
      deps      : [ConfigService],
      multi     : true
    },
    ....
]
  • You should now be able to use ConfigService to load languages.

Here an exemple in a component.

@Injectable()
export class MyComponent {

    languages: string[];

    constructor(private configService: ConfigService) {}

    ngOnInit() {
        this.languages = this.configService.getConfiguration().languages;
    }
}

In my case, it seems that I have to reload the server to take in account modification.

Hope it will help :)

PS : sorry for eventual english or technical mistakes in this message (I wrote it quickly during lunchtime)

like image 164
Renaud A Avatar answered Sep 28 '22 20:09

Renaud A


When you use require() the compiler will actually "inline" the JSON file in the main.bundle.js and will not use the file in assets

Seems like what you need is to use an http service to retrieve the JSON file instead of using require()

like image 37
Ahmed Musallam Avatar answered Sep 28 '22 19:09

Ahmed Musallam