1

Often, one wants to use different sets of values depending on user's choice. For example different ways of saying the same thing depending on the selected language, or different color of the same type depending on the selected theme. I'm curently trying to do the latter, so I made several JSON files with the same keys but different values. This is the 'green_theme' JSON:

{
  "darker_color": "#1a3300",
  "lighter_color": "#4f9900",
  "error_color": "#b42805"
}

and now I want components to take the color codes that they need from an injected service like so:

<div [style.color]="themeService.getColorCodeByKey('darker_color')">example</div>

This is how I tried implementing the service:

@Injectable()
export class ThemeService {
    private readonly RED_SKIN_SOURCE = "assets/themes/red_skin.json"
    private readonly GREEN_SKIN_SOURCE = "assets/themes/green_skin.json" 
    private readonly YELLOW_SKIN_SOURCE = "assets/themes/green_skin.json"
    public skinData: {[key: string]: string} = {};

constructor(private http:Http) {
    this.setSkin(ThemeService.Skin.Green);
}

getColorCodeByKey(key: string): string {
    return this.skinData[key];
}

public setSkin(skin: ThemeService.Skin) {
    let observable: Observable<Response>;
    switch(skin) {
        case ThemeService.Skin.Red: {
            observable =  this.http.get(this.RED_SKIN_SOURCE);
            break;
        }
        case ThemeService.Skin.Yellow: {
            observable =  this.http.get(this.YELLOW_SKIN_SOURCE);
            break;
        }
        case ThemeService.Skin.Green: {
            observable =  this.http.get(this.GREEN_SKIN_SOURCE);
            break;
        }
    }

    observable.map((res: Response) => res.json().forEach(element => {
        this.skinData[element.key] = element;
    }));
  }
}
export namespace ThemeService {
    export enum Skin {
        Red, 
        Green,
        Yellow
    }
}

But it seems like the setSkin method leaves skinData empty? How to do this correctly? Am I mapping the Observable too soon? Or is this just not how .json() works?

ALTERNATIVELY If you had a better idea how to implement this key-value-like service, I'm not against giving up on JSON.. I was even thinking of implementing it my own way with my own format and parser

3
  • Why did you make json files for these settings, if you just store them locally in your source file? Wouldn't it be much easier to just create a ts file where instantiate them? (You hard code them either way) Commented Aug 15, 2018 at 9:56
  • I thought json files were a nice way to do it. And more importantly I was thinking of enabling users to make their own skins that would get uploaded to a database and than sent to the frontend as JSON files, so the 'local' was actually a lousy keyword to use. .ts files would be an option if I really only wanted to use local files. Commented Aug 15, 2018 at 10:02
  • try printing res and res.json() into console to see what it gets? It looks like the res.json().forEach might not work cause it doesn't return an enumerable object. Commented Aug 23, 2018 at 19:38

2 Answers 2

5
+50

To fix current solution you need to subscribe to observable:

observable.subscribe((res: any) => { this.skinData = res; });

HttpClient in Angular parses responses to json by default(unlike fetch) and will return you parsed skinData, you can use it right away.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot. This actually solves the problem.. except it needs to be skinData = res.json() except just res. The bounty goes to you
4

I liked your way of storing data in json, but instead of creating different json files for different colours, you can just make a common file, it will be easy to maintain

For example:

"green" : {
  "darker_color": "#1a3300",
  "lighter_color": "#4f9900",
  "error_color": "#b42805"
},
"yellow" : {
  "darker_color": "#1a3300",
  "lighter_color": "#4f9900",
  "error_color": "#b42805"
},
"red": {
  "darker_color": "#1a3300",
  "lighter_color": "#4f9900",
  "error_color": "#b42805"
}

So when you tried to get data from json file in service, you can do like this,

 const COLOR_SOURCE_PATH = 'assets/YOUR_FILE_PATH';
 public setSkin(skin: ThemeService.Skin) {
       let observable: Observable<Response>;   
       this._httpClient.get(this.COLOR_SOURCE_PATH)
        .subscribe((res: Response) => {
            this.skinData = res[skin];
        }));
      }
   }



 export namespace ThemeService {
    export enum Skin {
        red, 
        green,
        yellow
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.