Global variable in angular2 whose value can be changed - javascript

I have injected one service while bootstrapping to use global variables:
bootstrap(AppComponent, [ GloablService ]);
global.service.ts
import {Http} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import {Observer} from 'rxjs/Observer';
import 'rxjs/add/operator/share';
export class GlobalService {
baseUrl:string;
constructor() {
this.baseUrl='http://localhost:8080';
}
setBaseUrl(url:string) {
this.baseUrl=url;
}
getBaseUrl() {
return this.baseUrl;
}
}
Now I have bootstrapped this service along with my root component and i am able to access the variable successfully.
But whenever I change the value of the variable in nested components the change is not reflected globally.
I tried to use observables too but no use.
any suggestions?

Don't add providers: [ GloablService ] on any component, otherwise the components will get a different instance. Only provide it once at bootstrap() like you did, or only at the root component AppComponent.

Related

process.env.varible undefined in nest.js

I am using nest.js and I want to import object defined in auth.parameters.ts file. File is defined as below. It appears environmental variable is not visible unless below variable is declared in class.
export const obj = {
somevar : process.env.CUSTOM_VAR,
};
In my other classes I would like to import the file with import {SecurityParameters } from '../auth/auth.parameters'
and access the variable with console.log(SecurityParameters.somevar).
I can access the variable directly using process.env.CUSTOM_VAR or
I get undefined if I use somevar : process.env.CUSTOM_VAR in other file.
As you're using Nest's ConfigModule, then unless you're creating a custom config file you shouldn't be doing anything with process.env. Instead, you should be injecting Nest's ConfigService where you need the environment variables and using this.configService.get('CUSTOM_VARIABLE') (or whatever value you need). To get started with this, you need to import the config module
import { Module } from '#nestjs/common';
import { ConfigModule } from '#nestjs/config';
#Module({
imports: [ConfigModule.forRoot()],
})
export class AppModule {}
You can pass { isGlobal: true } to the forRoot() call to make the ConfigService injectable anywhere in your application.
If you want a different approach where you can use the process.env object instead, you can add this as the first two lines of your main.ts
import { config } from 'dotenv';
config();
Nest calls this (or something similar) under the hood in the ConfigService, but that doesn't make it immediately available.

Emit method of EventEmitter not emitting values to subscribers

So I am trying to connect two components through a service, LoaderComponent and AppComponent with LoaderService, so that when app fetches data a loader shows up. But when I try to use an EventEmitter to emit changes to the components they don't get the changes but when the service subscribes
to itself, it can get the changes
LoaderService.ts
import { EventEmitter, Injectable } from '#angular/core';
#Injectable()
class LoaderService {
#Output change: EventEmitter<number> = new EventEmitter<number>();
private state: number = 0;
constructor() {
this.change.subscribe(state => console.log(state));
this.setState(1)
}
setState(state: number) {
this.state = state;
this.change.emit(this.state);
}
}
// Shows state when but outside of the service event is not detected, also tried EventEmitter from from events
I expect to get events from the LoaderService to subscribers
You need to use LoaderService in some component for angular to create it, if we do not use the service any where angular will automatically discard it. Inject LoaderService in app component like below:
constructor(private _loadService: LoaderService) {} and then you will see the console.log().
Also, it is recommended to use either Subject or Behavior Subject from Rxjs instead of Output in a service.
First thing, EventEmitters and Outputs don't belong in a service.
I will refactor to use subjects and also protect your subject by making it private and exposing a public observable, this limits how your subject state can be modified, this is not required but is generally considered good practice:
import { Injectable } from '#angular/core';
import {Subject} from 'rxjs/Subject';
import {Observable} from 'rxjs/Observable';
#Injectable()
class LoaderService {
private change: Subject<number> = new Subject<number>();
change$: Observable<number> = this.change.asObservable();
private state: number = 0;
constructor() {
this.change$.subscribe(state => console.log(state));
this.setState(1)
}
setState(state: number) {
this.state = state;
this.change.next(this.state);
}
}
Second, this is likely an issue with how you provide your service. If you have an app component template like:
<loader-component></loader-component>
<loader-component></loader-component>
with 2 loader components side by side, and the loader component has a providers array like:
providers: [LoaderService]
then these 2 loaders are receiving different copies of the same service as they each provide and inject their own, so they will not see each other's events.
To remedy this, you provide instead in the app component (and not in the loader component) so they have the same copy of the service, because then the parent is providing the service that each of them inject. If you were to provide in both app component and loader component, they would all receive a different copy.
If you provide at root (module level) then every component that injects the service (and doesn't provide it's own) will receive the same copy of that service.
The appropriate place to provide a service is dependent on your app's needs and the function of the particular service.

Angular: call function from other component

I'm trying to make two angular components and I want to call a function from the first component in the second component. When I try this I get following error message: Cannot red property 'functionName' of undefined. How can this be solved?
Here a link of an example: https://stackblitz.com/edit/angular-rre4gb
That's because the component you want to call its function, is not instantiated.
for component communication you can use a service instead:
Service
#Injectable()
export class MyService {
myCustomFunction(){
}
}
Component
in your component:
#Component({
selector: 'my-component',
providers: [ MyService ]
})
export class MyComponent {
// inject your service to make it available
constructor(private service: MyService){}
doStuff(){
// call function which is located in your service
this.service.myCustomFunction();
}
}
As others have stated, I would prefer a shared service with a Subject among these components.
service:
#Injectable()
export class SharedService {
mySubject = new Subject();
}
WorldComponent (subscriber):
export class WorldComponent {
constructor(private sharedService: SharedService){
this.sharedService.mySubject.subscribe((data)=>{
this.worldFunction();
})
}
HelloComponent(publisher):
public helloFunction() {
alert('Hello');
this.sharedService.mySubject.next(true);
}
You can find the updated example here: https://stackblitz.com/edit/angular-rnvmkq?file=app%2Fworld.component.ts
The best way to share information between multiple components is generally through a service.
Create a separate file: file.service.ts
Provide the service in the app.module.ts file
Inject the service into each component. Then you'll have access to the variables in both components
See this: https://angular.io/tutorial/toh-pt4
the reason of the error is that the hello component is not imported, but instead of calling a component from another, you should use a service in between, as other answers already suggested.

No provider for service error in angular2, why do I need to inject it in it's parent component?

I have a pages.service.ts
import { Injectable } from '#angular/core';
import { ApiService } from '../../apiService/api.service';
import { Playlists } from '../shared/playlists.model';
#Injectable()
export class PagesService {
private currentPlaylists: Subject<Playlists> = new BehaviorSubject<Playlists>(new Playlists());
constructor(private service: ApiService) {
}
}
This pages service needs another service called ApiService, I inject the way as shown above, it works.
I bootstrap ApiService in main.ts
import { ApiService } from './apiService/api.service';
import { AppComponent } from './app.component';
bootstrap(AppComponent,[
disableDeprecatedForms(),
provideForms(),
HTTP_PROVIDERS,
ROUTER_PROVIDERS,
ApiService
]).catch((err: any) => console.error(err));;
But When I try to inject the PagesService to another component, it gives me error, No Provider for PagesService.
I write that component like this.
import { Component, ViewChild, ElementRef, Input, Output, EventEmitter } from '#angular/core';
import { CORE_DIRECTIVES } from '#angular/common';
import { MODAL_DIRECTVES, BS_VIEW_PROVIDERS } from 'ng2-bootstrap/ng2-bootstrap';
import { ApiService } from '../../apiService/api.service';
import { PagesService } from '../../pages/shared/pages.service';
#Component({
selector: 'assign-playlist-modal',
exportAs: 'assignModal',
providers: [ PagesService ],
directives: [MODAL_DIRECTVES, CORE_DIRECTIVES, FORM_DIRECTIVES, REACTIVE_FORM_DIRECTIVES ],
viewProviders: [BS_VIEW_PROVIDERS],
styleUrls: ['app/channel/shared/assignPlaylist.css'],
templateUrl: 'app/channel/modals/assignPlaylistModal.html'
})
export class AssignPlaylistModalComponent {
constructor(private apiService: ApiService, private pageService: PagesService, fb: FormBuilder) {
}
}
Update: this is my file structure
channel/
--channel.component.ts
--shared/
----assignPlaylist.modal.ts
----addPlaylist.modal.ts
pages/
--shared/
----pages.service.ts
--pages.component.ts
Channel component is the parent of addPlaylist, addPlaylist is the parent of assignPlaylist. This structure will not work
ChannelComponent
|
AddPlaylistComponent
|
AssignPlaylistComponent ----PagesService----ApiService
I found one solution but don't know why I need to do that,
I add the provider 'PagesService' to ChannelComponent, and also the AssignPlaylistComponent, it will work, no errors.
Even this will work
ChannelComponent ----PagesService-------------
|
AddPlaylistComponent
|
AssignPlaylistComponent ----ApiService---------------
However, I just want to use PagesService in AssignPlaylistComponent, so I think it not make sense to import PagesService in channelcomponent.ts and make a providers array in it.
It is a bit strange, but only components can configure dependency injection in Angular (well, and bootstrap()). I.e., only components can specify providers.
Each component in the component tree will get an associated "injector" if the component has a providers array specified. We can think of this like an injector tree, that is (normally much) sparser than the component tree. When a dependency needs to be resolved (by a component OR a service), this injector tree is consulted. The first injector that can satisfy the dependency does so. The injector tree is walked up, toward the root component/injector.
So, in order for your PagesService to inject a ApiService dependency, that ApiService object first has to be registered with an injector. I.e., in a component's providers array. This registration must occur somewhere at or above the component where you want to use/inject the ApiService .
Your service should then be able to inject the registered ApiService object, because it will find it in the injector tree.
See also Angular 2 - Including a provider in a service.

Angular2: Service with Model - "no provider for model"

What I'm trying to do is create a service that uses a model to show an alert. The alert-model should be necessary nowhere else but in that service but I am not able to make this work. My service:
import {Injectable, Inject} from "angular2/core";
import {AlertModel} from "../models/alert.model";
#Injectable()
export class AlertService {
constructor(#Inject(AlertModel) alertModel: AlertModel) {
}
public alert(){
this.alertModel.message = 'success';
//...
}
}
But I keep getting this error:
Uncaught (in promise): No provider for AlertModel! (UserComponent -> AlertService -> AlertModel)
I'm new to angular and I do not understand this. What am I missing? Thanks in advance!
You need to provide the AlertModel somewhere
bootstrap(AppComponent, [AlertModel])
or in the root component (preferred):
#Component({
selector: 'my-app',
providers: [AlertModel],
...
})
Ensure AlertModel has the #Injectable() decorator and all its constructor parameters are provided as well (if it has any)
#Inject(AlertModel) is redundant if the type of the constructor parameter is already AlertModel. #Inject() is only necessary if the type differs or if AlertModel doesn't have the #Injectable() decorator.
constructor(#Inject(AlertModel) alertModel: AlertModel) {
You have this error since there is no provider for the AlertModel class visible from the UserComponent component (that calls the service). You can define either this class in the providers attribute of the component either when bootstrapping your application.
See the question to know more about how hierarchical injectors works and how to inject things into services:
What's the best way to inject one service into another in angular 2 (Beta)?
Since the AlertModel class seems to be a model class I don't think that you need to inject it. You can simply import the class and instantiate it:
#Injectable()
export class AlertService {
alertModel: AlertModel = new AlertModel();
public alert(){
this.alertModel.message = 'success';
//...
}
}

Categories

Resources