I have a file for configuring my OpenID Connect authentication
export const authMgr = new Oidc.UserManager({
userStore: new Oidc.WebStorageStateStore(),
authority: **appsetting.oidc**
})
I want to access my state in order to get the value of appsetting.
I did this:
import store from './store'
const appsetting = () => store.getters.appsetting
but my appsetting is always returning undefined
what I my missing?
Store:
app.js
const state = {
appsetting: appsetting,
}
export {
state
}
getters.js
const appsetting = state => state.appsetting
export {
appsetting
}
index.js
export default new Vuex.Store({
actions,
getters,
modules: {
app
},
strict: debug,
plugins: [createLogger]
})
when I print the value of store.getters, it returns this:
{
return __WEBPACK_IMPORTED_MODULE_2__store__["a" /* default */].getters;
}
No the actual store objects
Try to import 'store' with curly brackets
import {store} from '../store/index'
store.getters.appSettings
Another option is to access from the vue property
import Vue from 'vue'
Vue.store.getters.appSettings
As for 2023 accesing store with
import {store} from '../store/index'
store.getters.appSettings
wasnt working for me but after removing curly brackets like so:
import store from '../store/index'
store.getters.appSettings
It started working as intended
Related
I have read the documentation so many times https://vega.github.io/vega-lite/docs/config.html#custom-format-type. I still don't understand how to implement this in react vega. What confuses me the most is this vega object.
view = new vega.View(...);
view.expressionFunction('customFormatA', function(datum, params) {
...
return "<formatted string>";
});
What I am currently doing in React:
import React from "react";
import ReactDOM from "react-dom";
import { createClassFromSpec } from "react-vega";
const spec = {}
const BarChart = createClassFromSpec({ mode: "vega-lite", spec: spec });
export default function TestPage2({ data }) {
return <BarChart data={{ table: data }} />;
}
Is there any example of implementing a custom format type that I can learn from?
There was an error in the documentation and a pull request has been submitted.
You should use vega instead of vega.View like so:
import { expressionFunction } from 'vega';
expressionFunction('customFormatA', function(datum, params) {
return datum;
});
However, note that custom formats do not work with binning; an issue has been opened for this.
I used ComponentFactoryResolver to access all the entry component factories and then add routes of those components dynamically in Angular 7.
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
var factories = this.componentFactoryResolver['_factories']
let route: Route = {
path: MyPath,
component: factories[0].factory[1].componentType
};
this.router.resetConfig(config);
I updated my project to Angular 9 and now _factories are not available in ComponentFactoryResolver.
var factories = this.componentFactoryResolver['_factories']
It returns undefined in Angular 9. It will be great help if someone can suggest some way to access all the entry component list on the go. The problem is that I have don't any information available about the entry components from which I may recompile the components through Compiler and add their routes.
I think a simpler approach might be to import the component and use it directly in place of factories[0].factory[1].componentType. Example:
import { MyComponent } from '#app/my.component';
constructor(private componentFactoryResolver: ComponentFactoryResolver) {
}
let route: Route = {
path: MyPath,
component: MyComponent
};
this.router.resetConfig(config);
I am currently trying to unit test a container that pulls in a static JSON file of phone numbers and passes it to the component to display, however I am not sure how I should go about testing it. The code for the container is as follows:
import React from 'react';
import data from *JSON file location*
import CountryInfo from *component for the country information* ;
class CountryInfoContainer extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
numbersJson: null
};
}
async componentWillMount() {
const numbersJson = data;
this.setState({ numbersJson });
}
render() {
return (
<CountryInfo json={this.state.numbersJson} showText={this.props.showText} />
);
}
}
export default CountryInfoContainer;
I currently have my unit test to look like this
import React from 'react';
import Adapter from 'enzyme-adapter-react-16';
import { mount, configure } from 'enzyme';
import { MemoryRouter } from 'react-router-dom';
import CountryInfoContainer from './CountryInfoContainer';
configure({ adapter: new Adapter() });
describe('Successful flows', () => {
test('checks if json has null entries', () => {
const wrapper = mount(<MemoryRouter><CountryInfoContainer /></MemoryRouter >);
const data = wrapper.find(numbersJson);
// eslint-disable-next-line no-console
console.log(data.debug);
});
});
Obviously, it doesn't work now because I am not sure how to use the variable numbersJson in the container in the test file or how to check if it is null.
The variable numbersJson is not defined in the scope of your test. If I understand correctly, you are testing that when you first mount the component, that it's state contains a null value for the numbersJson key.
First of all, you need to mount your component directly without MemoryRouter:
const wrapper = mount(<CountryInfoContainer />);
Then you can write an expect() for the state:
expect(wrapper.state().numbersJson).toBeNull();
I'm developing an Angular app and I'm looking for something similar to Android Resource available in Android development.
Here is the way to get a string in Android:
String mystring = getResources().getString(R.string.mystring);
I would like to have the same in Angular.
For example if I have few HTML templates in which there are the same message about the wrong email provided...
<div class="alert alert-danger">
<strong>Error!</strong>Invalid e-mail
</div>
I would like to have the following:
<div class="alert alert-danger">
<strong>Error!</strong>{{myStrings.INVALID_EMAIL}}
</div>
...or something like this...
<div class="alert alert-danger">
<strong>Error!</strong>{{'INVALID_EMAIL' | stringGenerator}}
</div>
Do you know a way or addon I can install to reach that?
Having configuration, translations and resources separated from application's logic is very useful. Configuration would also be very helpful in other context like, for example, getting api_url useful for any rest call.
You can set up such thing using #angular/cli. Having the following application structure:
|- app
|- assets
|- i18n
- en.json
- it.json
|- json-config
- development.json
- env.json
- production.json
|- resources
- en.json
- it.json
|- environment
- environment.prod.ts
- environment.ts
|- config
- app.config.ts
Where:
app: contain all application logics
assets/i18n/*.json: contains a textual resources that can be used in any of your components. There's one of them for each language we want to cover.
E.G. en.json:
{
"TEST": {
"WELCOME" : "Welcome"
}
E.G it.json:
{
"TEST": {
"WELCOME" : "Benvenuto"
}
assets/json-config: contains configuration files to use in development mode and production mode. Also contains env.json which is a json that says which is the current development mode:
E.G. env.json:
{
"env" : "development"
}
E.G. development.json:
{
"API_URL" : "someurl",
"MYTOKEN" : "sometoken",
"DEBUGGING" : true
}
assets/resources: contains jsons files of resources per each language we want to cover. For instance, it may contain jsons initialization's for application models. It's useful if, for example, you want to fill an array of a model to be passed to an *ngFor personalized based on enviroment and/or language. Such initialization should be done inside each component which want to access a precise resource via AppConfig.getResourceByKey that will be shown later.
app.config.ts: Configuration Service that loads resources based on development mode. I will show a snippet below.
Basic Configuration:
In order to load basic configuration files as the application starts we need to do a few things.
app.module.ts:
import { NgModule, APP_INITIALIZER } from '#angular/core';
/** App Services **/
import { AppConfig } from '../config/app.config';
import { TranslationConfigModule } from './shared/modules/translation.config.module';
// Calling load to get configuration + translation
export function initResources(config: AppConfig, translate: TranslationConfigModule) {
return () => config.load(translate);
}
// Initializing Resources and Translation as soon as possible
#NgModule({
. . .
imports: [
. . .
TranslationConfigModule
],
providers: [
AppConfig, {
provide: APP_INITIALIZER,
useFactory: initResources,
deps: [AppConfig, TranslationConfigModule],
multi: true
}
],
bootstrap: [AppComponent]
})
export class AppModule { }
app.config.ts:
As said above, this service loads configuration files based on development mode and, in this case, browser language. Loading resources based on language can be very useful if you want to customize your application. For example, your italian distribution would have different routes, different behavior or simple different texts.
Every Resources, Configuration and Enviroment entry is available trough AppConfig service's methods such as getEnvByKey, getEntryByKey and getResourceByKey.
import { Inject, Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Observable } from 'rxjs/Observable';
import { get } from 'lodash';
import 'rxjs/add/operator/catch';
import { TranslationConfigModule } from '../app/shared/modules/translation.config.module';
#Injectable()
export class AppConfig {
private _configurations: any = new Object();
private _config_path = './assets/json-config/';
private _resources_path = './assets/resources/';
constructor( private http: Http) { }
// Get an Environment Entry by Key
public getEnvByKey(key: any): any {
return this._configurations.env[key];
}
// Get a Configuration Entryby Key
public getEntryByKey(key: any): any {
return this._configurations.config[key];
}
// Get a Resource Entry by Key
public getResourceByKey(key: any): any {
return get(this._configurations.resource, key);
}
// Should be self-explanatory
public load(translate: TranslationConfigModule){
return new Promise((resolve, reject) => {
// Given env.json
this.loadFile(this._config_path + 'env.json').then((envData: any) => {
this._configurations.env = envData;
// Load production or development configuration file based on before
this.loadFile(this._config_path + envData.env + '.json').then((conf: any) => {
this._configurations.config = conf;
// Load resources files based on browser language
this.loadFile(this._resources_path + translate.getBrowserLang() +'.json').then((resource: any) => {
this._configurations.resource = resource;
return resolve(true);
});
});
});
});
}
private loadFile(path: string){
return new Promise((resolve, reject) => {
this.http.get(path)
.map(res => res.json())
.catch((error: any) => {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
})
.subscribe((res_data) => {
return resolve(res_data);
})
});
}
}
translation.config.module.ts
This module sets up translation built using ngx-translate. Sets up translation depending on the browser language.
import { HttpModule, Http } from '#angular/http';
import { NgModule, ModuleWithProviders } from '#angular/core';
import { TranslateModule, TranslateLoader, TranslateService } from '#ngx-translate/core';
import { TranslateHttpLoader } from '#ngx-translate/http-loader';
import { isNull, isUndefined } from 'lodash';
export function HttpLoaderFactory(http: Http) {
return new TranslateHttpLoader(http, '../../../assets/i18n/', '.json');
}
const translationOptions = {
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [Http]
}
};
#NgModule({
imports: [TranslateModule.forRoot(translationOptions)],
exports: [TranslateModule],
providers: [TranslateService]
})
export class TranslationConfigModule {
private browserLang;
/**
* #param translate {TranslateService}
*/
constructor(private translate: TranslateService) {
// Setting up Translations
translate.addLangs(['en', 'it']);
translate.setDefaultLang('en');
this.browserLang = translate.getBrowserLang();
translate.use(this.browserLang.match(/en|it/) ? this.browserLang : 'en');
}
public getBrowserLang(){
if(isUndefined(this.browserLang) || isNull(this.browserLang)){
this.browserLang = 'en';
}
return this.browserLang;
}
}
Ok, and now? How can I use such configuration?
Any Module/Component imported into app.module.ts or any of them that is imported into another custom module that is importing translation.config.module can now automatically translate any interpolated entry based on browser language. For instance using the following snipped will generate Welcome or Benvenuto based on explained behavior:
{{ 'TEST.WELCOME' | translate }}
What If I want to get a resource to initialize a certain array that will be passed to an *ngFor?
In any component, just do that inside the constructor:
. . .
// Just some model
public navigationLinks: NavigationLinkModel[];
constructor(private _config: AppConfig) {
// PAGES.HOMEPAGE.SIDENAV.NAVIGATION contains such model data
this.navigationLinks =
this._config.getResourceByKey('PAGES.HOMEPAGE.SIDENAV.NAVIGATION');
}
Of course you can also combinate resources and configuration.
AndreaM16's answer is definitely thorough, but you sould also consider using an existing package for this instead of writing your own custom code that you need to maintain. To that end, I would recommend checking out ngx-translate (which is used somewhat under the hood in that answer), transloco and Angular's built-in i18n capabilities.
Most of those approaches are based on the magic strings, where your HTML templates and typescript code need to contain strings that (hopefully) match the keys in a JSON or XML file. This presents a serious code maintenance issue which won't be revealed at compile time, only at runtime. I would also advocate for checking out some guides on creating a type-safe translation system:
https://medium.com/angular-in-depth/angular-typed-translations-29353f0a60bc
https://medium.com/angular-in-depth/dynamic-import-of-locales-in-angular-b994d3c07197
You can also use enum file for string values.
string.ts
export enum TEST_STRING {
TEST_ONE = "this is first test string",
TEST_TWO = "this is second test string",
TEST_THREE = "this is third test string"
}
component.ts
import { TEST_STRING } from '../resources/string';
var testString = TEST_STRING.TEST_ONE;
console.log(testString); // result = this is first test string
I want to load Constant File in Angular 2(which is a Normal TypeScript File) having WebAPI EndPoints.
In Angular1.x. we used to have constants for the same.
How in Angular 2 I can Implement the Same?
I have created the .ts file.My main concern lies in how to load the file beforehand every Other class File loads.
.ts file :
export class testAPI {
getAPI = "myUrl";
}
In service file I am using the same by doing Normal Import:
constructor(private http: Http) {
//console.log(this.test);
console.log(this.testing.getAPI);
//this.test.load();
}
I am getting the Console as Undefined.(Must be because my Service class is loading before API Class).
Thanks in Advance.
UPDATES
Inspired with the solution for this particular problem created ngx-envconfig package and published it on NPM registery. It has the same functionalities as it is provided in this answer and even more.
You can have the JSON file somewhere in assets folder like: assets/config. Depending on whether the environment is dev or not you can use two .json files, one for development and one for production. So you can have development.json and production.json files, where each one will keep the appropriate API endpoints.
Basically you need to go through the following steps:
1. Setting up environment (skip this step if you have it already)
Create two files in src/environments folder:
environment.prod.ts
export const environment = {
production: true
};
environment.ts
export const environment = {
production: false
};
2. Create JSON config files
assets/config/production.json
{
"debugging": false,
"API_ENDPOINTS": {
"USER": "api/v1/user",
...
}
}
assets/config/development.json
{
"debugging": true,
"API_ENDPOINTS": {
"USER": "api/v1/user",
...
}
}
3. Create a service as follows
Note depending on the environment, the ConfigService will load the appropriate file
import { Injectable, APP_INITIALIZER } from '#angular/core';
import { Http } from '#angular/http';
import { Observable } from 'rxjs';
import { environment } from 'environments/environment'; //path to your environment files
#Injectable()
export class ConfigService {
private _config: Object
private _env: string;
constructor(private _http: Http) { }
load() {
return new Promise((resolve, reject) => {
this._env = 'development';
if (environment.production)
this._env = 'production';
console.log(this._env)
this._http.get('./assets/config/' + this._env + '.json')
.map(res => res.json())
.subscribe((data) => {
this._config = data;
resolve(true);
},
(error: any) => {
console.error(error);
return Observable.throw(error.json().error || 'Server error');
});
});
}
// Is app in the development mode?
isDevmode() {
return this._env === 'development';
}
// Gets API route based on the provided key
getApi(key: string): string {
return this._config["API_ENDPOINTS"][key];
}
// Gets a value of specified property in the configuration file
get(key: any) {
return this._config[key];
}
}
export function ConfigFactory(config: ConfigService) {
return () => config.load();
}
export function init() {
return {
provide: APP_INITIALIZER,
useFactory: ConfigFactory,
deps: [ConfigService],
multi: true
}
}
const ConfigModule = {
init: init
}
export { ConfigModule };
4. Integrate with app.module.ts
import { NgModule } from '#angular/core';
import { ConfigModule, ConfigService } from './config/config.service';
#NgModule({
imports: [
...
],
providers: [
...
ConfigService,
ConfigModule.init(),
...
]
})
export class AppModule { }
Now you can use ConfigService wherever you want get the necessary API endpoints defined in config .json files.
In Angular 4+ projects generated with the Angular CLI, you will have the environment folder out-of-the-box. Inside of it, you will find the environment.ts files from Karlen's answer. That is a working solution for configuration with one caveat: Your environment variables are captured at build time.
Why does that matter?
When you're setting up a CI/CD pipeline for your Angular app, you will generally have a build tool that builds your project (like Jenkins) and a deployment tool (like Octopus) that will grab that package (the dist folder) and deploy to the selected environment, replacing your environment variables with the correct values in the process. If you use the environment.ts files, your environment variables cannot be replaced this way because the environment.ts files do not get included in the dist folder. There is no file your deployment tool can pick up and edit.
What can we do? we can add a JSON configuration file inside of the assets folder. Those files are included by default in the dist folder we will want to deploy. When we want to use an environment variable, we simply import the settings like import config from '[relative/path/to/your/config/file.json]'.
When we do this, we will get something like the following error:
Cannot find module '../../config.json'. Consider using '--resolveJsonModule' to import module with '.json' extension
This is because the typescript compiler tries to import an exported module and cannot find one. We can fix this by adding the following JSON properties/values in our tsconfig.json file.
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
resolveJsonModule allows the typescript compiler to import, extract types from, and generate .json files.
allowSyntheticDefaultImports allows default imports from modules with no default export.
With this in place, we can run our project and we will find that our error is gone and we can use our config values without any issues.
Now, because this config file is included in the dist folder that gets deployed on the server, we can configure our deployment tool to replace the variable values with the values specific to the environment to which we want to deploy. With this in place we can build our Angular app once and deploy it anywhere.
Another added benefit is that most deployment tools like Octopus ship with native JSON support so you can configure it to replace environment variables in your JSON file quite easily. The alternative is using a regex solution to replace environment variables in a .ts file, which is comparatively more complicated and prone to mistakes.
It is possible to import JSON in TypeScript. You need to add typings:
typings.d.ts:
declare module "*.json" {
const value: any;
export default value;
}
And then import like this:
import config from "../config/config.json";
config.json:
{
"api_url": "http://localhost/dev"
}
I had same issue and in the end i give up from .ts and put it in .js :D like this:
configuration.js in root
var configuration = {
'apiHost': 'http://localhost:8900',
'enableInMemoryWebApi': false,
'authMode': 'standalone',
'wsUrl': 'ws://localhost:8900/ws'
};
module.exports = configuration;
in .ts file for ex. user.service.ts
let configuration = require('../configuration'); //in import section
#Injectable()
export class UserService {
...
getUser(id: number | string): Promise<User> {
console.log(configuration.apiHost) //will get propertye from .js file
return this.http.get(`${configuration.apiHost}/${id}`, this.headers).toPromise().then(this.extractData).catch(this.handleError);
}
}
Hope it helps
You can use Opague token to set constant values as providers
Try:
In your const file:
import { OpaqueToken } from '#angular/core';
export const CONFIG_TOKEN = new OpaqueToken('config');
export const CONFIG = {
apiUrl: 'myUrl'
};
In your AppModule set to make it a singleton provider for the app:
providers:[
//other providers,
{provide: CONFIG_TOKEN, useValue: CONFIG}
]
For injecting in constructor,
constructor( #Inject(CONFIG_TOKEN) private config)