I can’t find an element from an array which is has stored an array from a service. In console output it’s always show undefined message - angular6

Here is my component code. In this code I have stored all data in a local array to find an item from this array. But when I try to get an element from this array it shows undefined.
//-------------------------------------------------------------
Component.ts
export class AccountsComponent implements OnInit
{
retVal = [];
constructor(
public service:AccountingService)
{
this.service.getAccounts().forEach(item=>{
this.retVal.push(item['chartofaccount']); // Locally stored the value to an array//
});
}
ngOnInit()
{
console.log(this.getAccountById(2));
}
getAccountById(id)
{
return this.retVal.find(x => x.id === id); // Return value showed undefined//
}
} //-------------------------------------------------------------
Service.ts
getAccounts():Observable<ChartOfAccount[]>
{
return this._htc.get<ChartOfAccount[]>(this.apiUrl+'chart-of-account', httpOptions)
.pipe(
tap(data => console.log("Data:", data)),
);
}

Try to call your service methods in new method in your component instead of constructor.
This approach should fix your problem.
Why?
Angular: function calling on constructor
https://www.angularjswiki.com/angular/what-is-the-difference-between-constructor-and-ngoninit-in-angular/
//-------------------------------------------------------------
Component.ts
export class AccountsComponent implements OnInit
{
retVal = [];
constructor(
public service:AccountingService)
{
});
}
ngOnInit()
{ this.getAccountsData();
console.log(this.getAccountById(2));
}
getAccountsData() {
this.service.getAccounts().forEach(item=>{
this.retVal.push(item['chartofaccount']); // Locally stored the value to an array//
});
}
getAccountById(id)
{
return this.retVal.find(x => x.id === id); // Return value showed undefined//
}
} //-------------------------------------------------------------

Related

Angular 10: Call a child component function from parent component

I have 2 component parent (Login Screen) and a child (user-list). Parent component has dropdowlist. The grid loads according to the item chosen in the drop down list I need to fire function of the child component and this is not working for me. I have the following code:
parent component html:
I have the following code:
<div>[items]="UserTypeSelectItems"[(ngModel)]="UserTypeId" id="fieldType"
bindLabel="value" bindKey="key" (change)="changeUserType()" [clearable]="false">
</div>
<app-user-list></app-user-list>
parent component ts:
I have the following code:
export class Login-ScreenComponent implements OnInit {
#ViewChild(UserListComponent)child:UserListComponent;
userTypeSelectItems: Array<SelectItem>;
userTypeId: any;
items: any;
constructor(
private userTypeSettingsService: userTypeSettingsService,
) {
this.userTypeSettingsService.getuserTypes().subscribe((data) => {
this.userTypeSelectItems = data;
if (
this.userTypeSelectItems &&
this.userTypeSelectItems.length > 0
) {
this.userTypeId =
this.userTypeSettingsService.selectedContractTypeId ??
this.userTypeSelectItems[0].key;
this.userTypeSettingsService.setContractTypeId(this.contractTypeId);
this.userTypeSettingsService.fillSelectedFields(this.userTypeId).subscribe(dataFields => {
this.items = dataFields;
this.child.getUser();
});
}
});
}
changeUserType() {
this.child.getUser();
}
child component ts:
I have the following code:
getUser() {
this.loading = true;
this.userService
.getAllUsers(this.userTypeId)
.pipe(finalize(() => (this.loading = false)))
.subscribe(
(data) => {
this.rows = data.map(notif => {
return {
user_status_id: status_id,
});
},
(err) => this.toastr.error(err),
() => (this.loading = false)
);
}
'''''''
if I understand your question correctly, that's what I'd suggest
Parent HTML
<div>[items]="UserTypeSelectItems"[(ngModel)]="UserTypeId" id="fieldType"
bindLabel="value" bindKey="key" (change)="changeUserType()" [clearable]="false">
</div>
<app-user-list [userTypeId]="userTypeId"></app-user-list>
In the parent ts remove all the calls of the this.child.getUser()
In the child component you should have input parameter userTypeId with setter. It will invoke the getUser() function every time when value is changed.
private _userTypeId: number;
#Input()
get userTypeId(): number {
return this._userTypeId;
}
set userTypeId(value: number): void {
this._userTypeId = value;
this.getUser();
}
You also can use the external service which will be injected in the parent and child components or use some Subject in the parent component, create Observable base of it which will be sent as input parameter to the child component. There you subscribe on the observable and then you need to emit the value with subjectvar.next(value) and as result function will be called. I can write down the example if you need.
UPD: example with observables
Parent component ts file:
private userTypeIdSubject$ = new Subject<string>();
private userTypeId$ = this.userTypeIdSubject$.asObservable();
changeUserType(): void {
// some code goes here
this.userTypIdSubject$.next(userTypeId); // this should send the message to the observer (child)
}
Parent HTML:
<div>[items]="UserTypeSelectItems"[(ngModel)]="UserTypeId" id="fieldType"
bindLabel="value" bindKey="key" (change)="changeUserType()" [clearable]="false">
</div>
<app-user-list [userTypeObservable]="userTypeId$"></app-user-list>
Child TS
#Input()
userTypeObservable: Observable<string>;
ngOnInit() {
if(this.userTypeObservable) {
this.userTypeObservable.subscribe(
(userTypeId) => {
this.userTypeId = userTypeId;
this.getUser();
}
}
}
}

Service keeps deleting global object

I have a service that defines an object to be shared across multiple components. I'm setting this object's values in a function that is called during the APP_INITIALIZER and it seems to be ok at first, but when i try to get this object from other components, it's always empty...
In my data.service.ts i have this:
// Object to be shared across components
private loggedUser = {};
setObject(user) {
this.loggedUser = user;
}
getObject() {
return this.loggedUser;
}
// Function that is correctly executed during the APP_INITIALIZER
Init() {
return new Promise<void>((resolve, reject) => {
this.getCurrentUser().subscribe((data: any) => {
// I receive an object with some properties here
this.setObject(data);
resolve();
});
});
}
Then in one of my components i try to get this object with:
ngOnInit() {
var user = this.dataService.getObject();
console.log(user); // It's always empty
}
EDITED:
In my app.module.ts i have a factory that will receive the promise from Init() function:
export function initializeApp1(appInitService: DataService) {
return (): Promise<any> => {
return appInitService.Init();
}
}
providers: [ DataService, { provide: APP_INITIALIZER, useFactory: initializeApp1, deps: [DataService], multi: true} ],
As you can see, my goal is to set an object during the APP_INITIALIZER and being able to share it across components after that.

Angular can't read value of 'undefined' - unable to read value of 'casestudy' in the setTitle() method?

This is my component:
export class CaseStudyDetailComponent implements OnInit {
casestudy: CaseStudy;
constructor ( private caseStudyService: CaseStudyService, private route: ActivatedRoute, public titleService: Title ) { }
ngOnInit() {
this.route.params.subscribe((params: { Handle: string }) => {
this.caseStudyService.getCaseStudy(params.Handle).subscribe(casestudy => this.casestudy = casestudy);
});
this.titleService.setTitle(this.casestudy.Handle);
}
}
This is the service it is calling:
getCaseStudy(Handle: string): Observable<CaseStudy> {
return this.http.get<CaseStudy>(`${environment.apiPath}/project/handle/${Handle}`);
}
I want to be able to access the value of 'casestudy' in the 'setTitle()' method. I might potentially just be misunderstanding expected behaviour or have my syntax wrong.
Let me know if more information is required.
Because your console.log gets excecuted before your subscribe can set the response in the caseStudy.
To fix this put the console.log method in the subscribe
this.caseStudyService.getCaseStudy().subscribe(caseStudy => {
... code
console.log(caseStudy);
});

Angular HTTP GET

I have a server running on "localhost:3000". It displays data as JSON at e.g. "localhost:300/locations".
My "data.service.ts" includes this code:
path: string = 'http://localhost:3000'
constructor(private http: HttpClient) { }
// Locations
getAllLocations(): Observable<Location[]> {
let location = null;
this.http.get(this.path + '/locations')
.map((res => location = res))
.catch((error: any) => Observable.throw(console.log(error)));
return location;
}
In my result.component.ts I'm running this code:
constuctor(private dataservice: DataService) { }
ngOnInit() {
console.info(this.dataservice.getAllLocations());
}
I'm expecting to get as output all Locations as JSON, instead of this the output is "null".
Does anyone have a suggestion on how to make this work properly?
UPDATE:
Also tried this for the HTTP call:
getAllLocations(): Observable<Location[]> {
this.http.get<Location[]>(this.path + '/locations')
.pipe(
tap(items => console.info('fetched items'))
);
}
The output for this code is unfortunately: "Object { _isScalar: false, source: {...}, operator: {...} }"
Did you know that HttpClient#get returns an Observable? You can just return the get method in your method.
Secondly, you can set an interface to the method so that it'll return the JSON as typed.
Lastly, you can use template literals in your API URL.
/**
* Retrieves a list of locations.
* (TODO: Add better documentation here)
*/
getAllLocations(): Observable<Location[]> {
return this.http.get<Location[]>(`${this.path}/locations`);
}
You can then handle this in the actual component that calls this method:
constuctor(private dataservice: DataService) { }
ngOnInit() {
this.dataservice.getAllLocations().subscribe(result => {
console.log(result);
});
}
You have to return Observable from the service:
path: string = 'http://localhost:3000'
constructor(private http: HttpClient) { }
// Locations
getAllLocations(): Observable<Locations[]> {
return this.http.get(this.path + '/locations').pipe(
map((res => location = res)),
catch((error: any) => Observable.throw(console.log(error))));
}
And subscribe to it in the component.
constructor(private dataservice: DataService) { }
ngOnInit() {
this.dataservice.getAllLocations().subscribe(result => {
console.log(result);
})
}

Read data from a local JSON file with data binding in ngOnInit() results in undefined variable

I am trying to get a data from json file in the assets folder, and then assign this data to a variable that will be binded to another #Input variable of a child componenet.
Code
Based on multiple solutions on the net, I retrieve my JSON data this way:
#Injectable()
export class JSONService {
constructor(private http: HttpClient) { }
public fromJSON(jsonFileName: string): Observable<any[]> {
let result: any[] = new Array();
let pathToJson: string = "assets/" + jsonFileName + ".json";
return this.http.get(pathToJson).map(data => {
let result: any[] = new Array();
// Apply some treatment on data and push it to the result array
return result;
});
}
}
I then call my service in the ngOnInit() method of the parent component:
ngOnInit() {
this.jsonService.fromJSON("users.json").subscribe(fields => {
this.fields= fields;
console.log(this.fields); // Log (I): this.fields is well defined
});
console.log(this.fields); // Log (II): this.fields is undefined
}
Where the variable fields is binded to a child component:
<child-component [childFields] = "fields"></child-component>
Problem
The problem that I am facing is that the asynchronous call to the fromJSON method causes this.fields to be undefined at some point of the lifecycle of the page execution (Log (II) from the code above), and this causes to send an undefined value of the this.fields variable to the child component.
How to avoid to have an undefined value of the fields variable, and make sure that the child component is always loaded with the data from the json file?
Just add *ngIf to check if the data is loaded
<child-component *ngIf="fields" [childFields] = "fields"></child-component>
Service.ts
#Injectable()
export class JSONService {
constructor(private http: HttpClient) { }
public fromJSON(jsonFileName): Observable<any[]> {
console.warn('Retriving Default Data from File.......');
return this.http.get(filename)
.map(this.extractData)
.catch(this.handleError);
}
private extractData(res: Response) {
let body = res.json();
return body || [];
}
private handleError(error: any) {
const errMsg = (error.message) ? error.message :
error.status ? `${error.status} - ${error.statusText}` : 'Server error';
console.error(errMsg);
console.log('Server Error!');
return Observable.throw(errMsg);
}
}
parent.component.ts
constructor(public jsonService: jsonService) {
}
ngOnInit() {
this.jsonService.fromJSON('assets/users.json').subscribe(
function (success) {
this.data = success;
this.datahandle(success);
},
error => console.log('Getting Server Data Error :: ' +
JSON.stringify(error)));
}
datahandle(jsonData){
console.log('check data' + JSON.stringify(jsonData)); <-----check data
// may parse your jsonData if required
this.fields = jsonData ;
let keys = Object.keys(jsonData);
console.log(keys);
}
}
parent.component.html
<child-component *ngIf="fields" [childFields] = "fields"></child-component>
Assuming your component is somewhat like below
export class SomeComponent implements OnInit {
public fields: any[];
ngOnInit() {
this.jsonService.fromJSON("users.json").subscribe(fields => {
this.fields = fields;
console.log(this.fields); // Log (I): this.fields is well defined
});
console.log(this.fields); // Log (II): this.fields is undefined
}
}
Then you can either initialize fields with an empty array
public fields: any[] = [];
OR in template
<child-component *ngIf="fields" [childFields]="fields"></child-component>