I have my service as PortAllocationService below
#Injectable({
providedIn: 'root'
})
export class PortAllocationService {
businessSwitchName: any;businessSwitchIp: any;businessSwitchportName: any;
businessSwitchNodeId: any;routerName: any;routerIp: any;routerDetailsportName: any;
routernodeID: any;aggSwitchName: any;aggSwitchPort: any;aggNodeIP: any;
aggNodeId: any;serviceName: any;convertorDetails: any;handoffPort: any;qosLoopingPort: any;
constructor(private http:HttpClient) { }
portService(da){
return this.http.post(url.portAllocationUrl , da).
subscribe ((response:any) => {
//Port Allocation response is mapped here
console.log(response);
// businessSwitchDetails
this.businessSwitchName = response.businessSwitchDetails.nodeName;
this.businessSwitchIp = response.businessSwitchDetails.nodeIP;
});
}
and my component as below
export class WimaxFormComponent {
data : any = {};
btsIp :any; vCategory:any;nVlan:any;
businessSwitchName:any;businessSwitchIp:any;businessSwitchportName:any;
routerName:any;routerIp:any;aggSwitchName:any;aggSwitchPort:any;
routerDetailsportName:any;routernodeID:any;aggNodeIP: any;aggNodeId: any;
businessSwitchNodeId: any;serviceName: any;convertorDetails: any;
handoffPort: any;qosLoopingPort: any;
serviceId: any;serviceType: any;customerName: any;
vReservedValue:boolean;cVlan: string;sVlan: any;
path: string;
constructor(
private service: PortAllocationService){
}
onChange(){
let portAllocationData = {
"serviceAttribute": {
"serviceType": this.serviceType,
"category": "category",
"name": this.serviceId
},
"btsIp": this.btsIp
}
console.log(portAllocationData);
this.service.portService(portAllocationData);
}
When i call the onChange function the call is made to service and we get the response from server . But i want to access all variable values from my service to Component like for example i have tried in constructor and onChange both as
this.businessSwitchName = service.businessSwitchName // this is coming as undefined
Could you please let me know how to access the variable values into component.
Rather than subscribing to the API call in the service itself, I would simply return the observable made by http.post(). And then move the subscribe to the component itself:
Service:
portService(da){ return this.http.post(url.portAllocationUrl , da) });
Component:
this.service.portService(portAllocationData).subscribe(response => {
// Do stuff with the response here
});
However, if you really want to keep the variables in the service, I would put the API call in the constructor of the service, change the fields in the service to start with an underscore (or some other local/private identifier) and then have get methods for each variable you want to be able to access.
Service:
get businessSwitchName() {
return this._businessSwitchName;
}
Component:
this.service.businessSwitchName
Related
As the title says I'm trying to access a method that is declared in one class (Post) from another class (Comments) which is following a singleton pattern. Post class is a service class which has some methods to make API calls. So I need to have access to them from inside Comments class so that I can make API calls.
This is how a simplied version of Post class looks like right now:
#Injectable({
providedIn: 'root'
})
class PostService extends AnotherService {
constructor( auth: AuthService, http: HttpClient ) {
super('string', auth, http);
}
getPost( id: string ) {
return this.http.get(`posts/${id}`);
}
}
This is how the Comments class look like:
class Comments {
private postService: PostService;
private static instance;
private constructor() {}
static createInstance() {
if ( !Comments.instance ) {
Comments.instance = new Comments();
}
return Comments.instance;
}
getComments( id ) {
// these does not even run
this.postService.getPost( id )
.then( post => {
console.log( post );
})
.catch( error => {
console.log( error );
});
}
}
How can I go about accessing it?
=========UPDATE=======
Creating an instance of Comment class in another class called ClassC.
const instance - Comments.createInstance();
instance.getComments( id );
Use a new service to save your comment object data
let say We have a service named SharedDataService.
private _comments: Array<any> =[];// or array<IComment> (a defined interface from your part)
class SharedDataService(){}
get comments():Array<any>{
return this._comments}
set comments(value:Array<any>){
this._comments = value;
}
}
You should init PostService on your Comments Constructor
private constructor(private postService: PostService,private sharedDataService :SharedDataService) {
}
getComments() {
// these does not even run
this.postService.getPost( '1' )
.then( post => {
this.sharedDataService.comments = post // if You get an array of comments here
console.log( post );
console.log(this.comments)// getter function its new value has been set
})
.catch( error => {
console.log( error );
});
get comments(){
this.sharedDataService.comments
}
}
If You want to send two http request in parallel then get their values You should use combineLatest rxjs operator.
Your post service will be like this:
getPost(id: string) {
$postDataHttpRequest = this.http.get(`posts/${id}`);
$commentsDataHttpRequest = this.http.get(`posts/${id}/comments`);
return combineLatest($postDataHttpRequest, $commentsDataHttpRequest)
}
///
This is how the Comments class look like:
private constructor(private postService: PostService) {
}
getComments() {
this.postService.getPost( '1' )
.subscribe( (posts,comments) => {
console.log(posts);
console.log(comments);
},(error)=>{console.log(error)})
}
I have a few decorators that when called, I want to setMetadata to use it in my logging,
In my controller, I have these:
#Post("somePath")
#Permission("somePermission")
#UseGuards(JwtAuthGuard)
#HttpCode(200)
#Grafana(
"endpoint",
"functionalmap"
)
async getSubscriptionFromPwebFormFilter(
#Body(ValidationPipe) someDto: someDtoType
): Promise<ISuccessResponse> {
// some logic
}
In my decorators I want to set some data into the metadata to use in my logging inteceptor,
Grafana decorator:
export const Grafana = (functionalMap: string, endpoint: string) =>
applyDecorators(
SetMetadata("endpoint", endpoint),
SetMetadata("functionalMap", functionalMap)
);
AuthGuard decorator:
#Injectable()
export class JwtAuthGuard extends AuthGuard("jwt") {
constructor(
private readonly reflector: Reflector,
private readonly someService: SomeService
) {
super();
}
public async canActivate(context: ExecutionContext): Promise<boolean> {
const role = this.reflector.get<string>("permission", context.getHandler());
const request = context.switchToHttp().getRequest();
const { valueToLog } = request.body;
const jwtToken = request.headers.authorization;
console.log("check value exist", valueToLog);
SetMetadata("valueToLog", valueToLog);
}
Now, in my logging interceptor, I am getting all the values of the metadata this way:
#Injectable()
export default class LoggingInterceptor {
constructor(private readonly reflector: Reflector) {}
intercept(context: ExecutionContext, next: CallHandler) {
const executionStart = Date.now();
return next.handle().pipe(
tap((responseData) => {
const response = context.switchToHttp().getResponse<ServerResponse>();
const { statusCode } = response;
const valueToLog = this.reflector.get(
"valueToLog",
context.getHandler()
); // this is undefined
const endpoint = this.reflector.get("endpoint", context.getHandler()); // this have value
const functionalMap = this.reflector.get(
"functionalMap",
context.getHandler()
); // this have value
...
// some logic
})
);
}
}
In my case, the value of endpoint and functionalMap can be retrieved from the reflector, however, valueToLog is appearing as undefined,
Is setting of metadata not working for auth guard decorator?
I will be using the term "Decorator" in this explanation so I will first define it.
Decorators are functions that accept information about the decorated declaration.
Ex:
function ClassDecorator(target: typeof DecoratedClass) {
// do stuff
}
// it can then be used like this
#ClassDecorator
class DecoratedClass {}
when calling #SetMetadata(key, value) it returns a decorator. Functions like SetMetadata are referred to as Decorator Factories.
Decorators use the form #expression, where expression must evaluate to a function that will be called at runtime with information about the decorated declaration.
In your example you called SetMetadata("valueToLog", valueToLog). This returns a decorator. Decorators must be called with information about the decorated declaration. To actually attach the metadata you can do something like this:
SetMetadata("valueToLog", valueToLog)(context.getHandler());
I'm trying to use an angular service to store and communicate data through observable.
Here is my service
public _currentLegal = new BehaviorSubject({
name: 'init',
_id: 'init',
country: 'init',
city: 'init',
});
readonly currentLegal$ = this._currentLegal.asObservable();
constructor(private http: HttpClient) {
}
setCurrentLegal(legal) {
const legaltest = {
name: 'test',
_id: 'test',
country: 'test',
city: 'test',
}
console.log('emitting next value from', legal.name)
this._currentLegal.next({ ...legaltest });
}
I got a component that call setCurrentLegal, the console.log is triggered and correct. I then navigate to another component which subscribe to the currentLegal$ observable and the value is still the same (init) !
I tried accessing the value directly by setting public type and using getValue(), same.
I tried duplicating the object as to not pass a reference, did not change anything.
Here is my subscripting component ngOnInit :
ngOnInit(): void {
this.legalToUpdate = this.legalService.currentLegal$.subscribe((legal) => {
console.log(legal)
})
}
What's wrong here ?
Thanks
You have this behavior because you use it in different modules and it is created a different instances.
Put your service to be provide in root:
#Injectable({ providedIn: 'root' })
export class LegalService implements HttpInterceptor { }
This is my component.ts where when it's loaded I get the data from the api, which I can see in the console.log, I do infact get my array of 10 objects (they come in groups of 10 on the api). I have the correct path in the API for the source code of the first image in the array of 10 which I typed to out the correct path for in normal http/javascript format of data.hits.hits[n]._source.images[n].urls.original. However when I try to put it in angular it can't read the data value as it is right now since it's out of scope, but I can't figure out how to word it in a better way.
import { Component, OnInit } from '#angular/core';
import { ConfigService } from '../../config.service';
import { Observable } from 'rxjs';
#Component({
selector: 'app-property-binding',
templateUrl: './property-binding.component.html',
styleUrls: ['./property-binding.component.css']
})
export class PropertyBindingComponent implements OnInit {
private isHidden : boolean;
public zeroImage : string;
private Photos : Observable<Object>;
constructor(private configService: ConfigService) { }
ngOnInit() {
//doing the API call
this.Photos = this.configService.getConfig();
this.Photos.subscribe((data) => console.log(data));
}
toggle() : void {
this.isHidden = !this.isHidden;
if(this.isHidden){
//var zeroImg = document.createElement("img");
this.zeroImage.src = data.hits.hits[0]._source.images[0].urls.original;
}
}
}
Here is the Angular html page that should property bind the src with the variable that I want.
<p>
View Artworks
</p>
<button class="btn btn-info" (click)="toggle()">Show Artwork</button>
<div class="col-md-4" *ngIf="isHidden">
<img [src]="zeroImage">
</div>
Here is the service method that I have the method that makes the API call
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { HttpHeaders } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ConfigService {
private httpOptions = {
headers: new HttpHeaders({
'ApiKey': 'my_personal_key'
})
};
private configUrl = 'https://api.art.rmngp.fr/v1/works';
constructor(private http: HttpClient) { }
getConfig(){
let obs = this.http.get(this.configUrl, this.httpOptions)
console.log("Inside the getConfig method, before subscribe, doing API call" +
obs);
//might not need to subscribe here??
//obs.subscribe((response) => console.log(response))
return obs;
//return this.http.get(this.configUrl, this.httpOptions);
}
}
And slightly unrelated code, this is the normal http/javascript where I wrote the code Outside of Angular, which works perfectly fine.
function displayPhoto(){
fetch('https://api.art.rmngp.fr/v1/works/, {headers: {ApiKey: "my_personal_key"}})
.then(function(response){
return response.json();
})
.then(function(data){
document.getElementById("zeroImg").src = data.hits.hits[0]._source.images[0].urls.original;
Again, the API call in Angular works, I can see I am pulling the data successfully, I however can not set the image to the first image in the set of data and have been struggling with it. any help will help
You are not doing anything with the data when you subscribe
this.Photos.subscribe((data) => console.log(data));
You have not done anything with the data here.
zeroImg.src = data.hits.hits[0]._source.images[0].urls.original;
zeroImg is a string and makes no sense to set a src property on it and data is undefined at the point. The only place there is a data variable is in your subscription function but it is not available here.
The following will set the src of the image
this.Photos.subscribe((data) => {
this.zeroImg = data.hits.hits[0]._source.images[0].urls.original;
});
Make the toggle function just toggle the isHidden flag and get rid of the rest.
ngOnInit() {
//doing the API call
this.Photos = this.configService.getConfig();
this.Photos.subscribe((data) => {
this.zeroImg = data.hits.hits[0]._source.images[0].urls.original;
});
}
toggle() : void {
this.isHidden = !this.isHidden;
}
On my web-app written in angular I am posting data to a Database and I am displaying this data in a table on the same html. Each data record has an ID. And every time I am adding new data, the ID is going to be increased. The first input field shows the actual ID, see the screenshot below:
In my ngOnInit-method I am initialising the id and I call the function fbGetData() in order to display the data.
But now I am facing one odd problem:
Everytime I starting the application the initial value which is displayed in the ID-field is NaN.
Obviously I cannot post any data to the database because the ID is not a number. So I have to switch to another page on my application and then switch back. After that the correct ID is displayed. I also tried to move my methods from the ngOnInit-method to the constructor but this didn't help.
Somehow I think that I need to implement the methods asynchronously, but I have no idea how to do this, since I am quite new to Angular/Typscript.
I hope you guys can help me with this problem or give me any hint or idea.
I appreciate your answers!
Here is my .ts Code:
import { Component, OnInit, ViewEncapsulation } from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { DataService } from '../data.service';
import { Http } from '#angular/http';
import { rootRoute } from '#angular/router/src/router_module';
import { SearchNamePipe } from '../search-name.pipe';
import { LoginComponent } from '../login/login.component';
import {NavbarService} from '../navbar.service';
declare var firebase: any;
const d: Date = new Date();
#Component({
selector: 'app-business-function',
templateUrl: './business-function.component.html',
styleUrls: ['./business-function.component.css'],
encapsulation: ViewEncapsulation.None,
providers: [DataService, SearchNamePipe, LoginComponent]
})
export class BusinessFunctionComponent implements OnInit {
id;
name: String;
descr: String;
typ: String;
bprocess: String;
appsystem: String;
applications: String;
datum: String;
liste = [];
bprocessliste = [];
applicationliste = [];
appsystemliste = [];
isDesc: boolean = false;
column: String = 'Name';
direction: number;
loginName: String;
statusForm: Boolean = false;
private idlist = [];
constructor(
private dataService: DataService,
private router: Router,
private route: ActivatedRoute,
private searchName: SearchNamePipe,
private navbarService: NavbarService
) {
this.datum = Date().toString();
}
ngOnInit() {
this.navbarService.show();
firebase.database().ref().child('/AllID/').
on('child_added', (snapshot) => {
this.idlist.push(snapshot.val()
)})
this.id = this.idlist[0];
console.log("ID: "+this.id);
console.log("IDlist: "+this.idlist[0]);
this.id++;
console.log("ID: "+this.id);
this.fbGetData();
}
fbGetData() {
firebase.database().ref().child('/BFunctions/').orderByChild('CFlag').equalTo('active').
on('child_added', (snapshot) => {
//firebase.database().ref('/BFunctions/').orderByKey().on('child_added', (snapshot) => {
// alter code ... neuer Code nimmt nur die Validen mit dem X Flag
this.liste.push(snapshot.val())
});
// firebase.database().ref().child('/ID/').on('child_added', (snapshot) => {
//Bprocess DB Zugriff
firebase.database().ref().child('/BProcess/').orderByChild('CFlag').equalTo('active').
on('child_added', (snapshot) => {
this.bprocessliste.push(snapshot.val())
});
//Appsystem DB Zugriff
firebase.database().ref().child('/Appsystem/').orderByChild('CFlag').equalTo('active').
on('child_added', (snapshot) => {
this.applicationliste.push(snapshot.val())
})
//Application DB Zugriff
firebase.database().ref().child('/Application/').orderByChild('CFlag').equalTo('active').
on('child_added', (snapshot) => {
this.applicationliste.push(snapshot.val())
});
console.log(this.applicationliste);
}
You need to update the id inside your callback:
firebase.database().ref().child('/AllID/').on('child_added', (snapshot) => {
this.idlist.push(snapshot.val())
this.id = this.idlist[0];
console.log("ID: "+this.id);
console.log("IDlist: "+this.idlist[0]);
this.id++;
console.log("ID: "+this.id);
this.fbGetData();
})
Otherwise id retains it initial undefined value. This is because the call to firebase is asynchronous.
Here is what happens in your original code:
call to firebase API... wait your response
set id to this.idlist[0], which is empty (undefined)
...some time later, getting response from firebase
id does not get updated because the code in point 2. has already been executed.
Anything that you need to do when you get the result from an asynchronous call, must be executed inside the callback function.