Reading an environment variable before it is defined [duplicate] - javascript

This question already has answers here:
Angular2: Cannot read property 'name' of undefined
(7 answers)
Closed 3 years ago.
I am using an environment variable to be able to read something from a JSON and display in my HTML. My issue is that my HTML is trying to read the environment variable before it has been defined in the .ts and therefore I get an error.
I am currently defining the variable in ngOnit() but this gives me an error. I am using httpclient to be able to read the JSON (from a server) and obviously what is happening is that the variable is being read in the HTML before httpclient has got the data.
HTML
<p>Player One is: {{ id.playerone }} </p>
.ts
import { HttpClient } from '#angular/common/http';
export class ApComponent implements OnInit {
id: any = [];
constructor(private httpService: HttpClient) { }
ngOnInit() {
this.httpService.get('http://server/info.json').subscribe(
result => {
this.id = result;
},
error => {
console.log('Error Occured', error);
}
);
}
}
JSON
{
"playerone":"ajf806",
"playertwo":"hof934"
}
I get the expected output of Player One is: ajf806 but I also get an error in the console which is:
ERROR TypeError: Cannot read property '0' of undefined.
It does work and I get the output but I don't want to have the error in the console. Is there a way to delay the HTML reading the environment variable until the JSON has been read?

Change your variable like this:
id: any;
also change your template like this:
<p>Player One is: {{ id?.playerone }} </p>
Another version of the above code [a bit better]:
import { HttpClient } from '#angular/common/http';
export class ApComponent implements OnInit {
id$: Observable<any>;
constructor(private httpService: HttpClient) { }
ngOnInit() {
this.id$ = this.httpService.get('http://server/info.json')
.pipe(
catchError((error) => {
//handle your error
console.log(error);
})
)
);
}
}
Now change your template to make use of async pipe like this:
<ng-conatiner *ngIf="(id$ | async) as id">
<p>Player One is: {{ id.playerone }} </p>
</ng-container>
NOTICE - you are not subscribing to the observable in your component. async pipe is taking care of subscription management [i.e. subscribing/unsubscribing.].

Related

Unable to parse all data from java rest API to angular front end

I'm sending a list of MonthSheetParsed Objects (this holds Month object, which holds a set of Day objects) from my backend program (rest API). My frontend program in Angular sends a requests to get this list of MonthSheetParsed Objects. When I try to display the acquired object, I can display the attributes of the MonthSheetParsed. But when I try to get the set<Day> in the Month object, which is an attribute of the MontSheetParsed, I get the error from TypeScript:
core.mjs:7640 ERROR TypeError: Cannot read properties of undefined (reading 'setDays').
So I guess I set my models in Angular wrong which makes it not parse the Day objects correct. Maybe because of the date attribute in the Day object. But it might also be something else.
Am I setting my models correct to parse the incoming data?
If so, why is my set of Days undefined?
Here below you can find the jsonData, afterwards the models in Angular, the service, component.ts in component.html.
JsonData:
[{"id":1,"username":"user#mail.be","status":"PREPOSITION","year":2022,"
month":6,"monthObject":{"year":2022,"month":6,"daysOfMonth":
[{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-01"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-02"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-03"},
{"dayType":"WEEKEND","workingHours":8,"date":"2022-06-04"},
{"dayType":"WEEKEND","workingHours":8,"date":"2022-06-05"},
{"dayType":"FEESTDAG","workingHours":8,"date":"2022-06-06"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-07"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-08"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-09"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-10"},
{"dayType":"WEEKEND","workingHours":8,"date":"2022-06-11"},
{"dayType":"WEEKEND","workingHours":8,"date":"2022-06-12"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-13"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-14"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-15"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-16"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-17"},
{"dayType":"WEEKEND","workingHours":8,"date":"2022-06-18"},
{"dayType":"WEEKEND","workingHours":8,"date":"2022-06-19"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-20"},
{"dayType":"VAKANTIE","workingHours":8,"date":"2022-06-21"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-22"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-23"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-24"},
{"dayType":"WEEKEND","workingHours":8,"date":"2022-06-25"},
{"dayType":"WEEKEND","workingHours":8,"date":"2022-06-26"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-27"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-28"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-29"},
{"dayType":"WERKDAG","workingHours":8,"date":"2022-06-30"}]}}]
Models Angular - Day.ts
export class Day {
date!:Date;
dayType!:DayTypes;
workingHours!:number;
}
Models Angular - DayTypes.ts
export enum DayTypes {
NOGNIETBEPAALD = 'NOGNIETBEPAALD',
WERKDAG = 'WERKDAG',
FEESTDAG = 'FEESTDAG',
VAKANTIE = 'VAKANTIE',
ZIEKTE = 'ZIEKTE',
WEEKEND = 'WEEKEND',
}
Models Angular - Month.ts
export class Month {
year!:number;
month!:number;
setDays!:Set<Day>;
}
Models Angular - Status.ts
export enum Status {
PREPOSITION = 'Preposition',
CONFIRMED = 'Confirmed',
HANDLED = 'Handled',
}
Models Angular - MonthlySheet.ts
export class MonthlySheet {
id!:number;
username!:string;
status!:Status;
year!:number;
month!:number;
monthobject!:Month;
}
angular service:
#Injectable({
providedIn: 'root'
})
export class TimesheetService {
constructor(private http: HttpClient) { }
getAllTimesheetsByUsername(username: String): Observable<MonthlySheet[]>{
const url = environment.TIMESHEETSAPI_URL + "timesheets/findAllByUsername/" + `${username}`;
return this.http.get<MonthlySheet[]>(url);
}
}
angular component.ts
#Component({
selector: 'app-timesheet',
templateUrl: './timesheet.component.html',
styleUrls: ['./timesheet.component.css']
})
export class TimesheetComponent implements OnInit {
timesheets!:MonthlySheet[];
constructor(private timesheetService: TimesheetService) { }
ngOnInit(): void {
this.timesheetService.getAllTimesheetsByUsername(username).subscribe(sheet => {this.timesheets = sheet});
}
}
angular component.html
<h2>Overzicht timesheets</h2>
<ul *ngFor="let sheet of timesheets">{{sheet.username}} - {{sheet.year}}/{{sheet.month}} - {{sheet.status}}
<li *ngFor="let daily of sheet.monthobject.setDays">{{daily.date}}-{{daily.dayType}}</li>
</ul>
The enums are correct, switch the models to interfaces:
export interface DaysOfMonth {
dayType: DayType;
workingHours: number;
date: Date;
}
export interface MonthObject {
year: number;
month: number;
daysOfMonth: DaysOfMonth[];
}
export interface TimeSheet {
id: number;
username: string;
status: Status;
year: number;
month: number;
monthObject: MonthObject;
}
The reason it can't read these properties is prodably due to a leak in the routing module which causes the filter proxy server to reroute the traffic through the firewall, the solution is easy, you have to inject the https method directly into the spring boot server using the h2 database servlets, using this you can breach the router module and start injecting requests from inside out, causing the router module to crash - it will crash once the system variables have overflowed and from there on you can find out the routing encryption keys as they will be show in their decyphered form. Once that's done it will be able to read the days again.
export class Month {
year!:number;
month!:number;
setDays!:Day[]; // Set<Day>;
}
Array cannot be assigned directly to Set, It can be created as
setDay: Set<Day> = new Set([...Day]);
You need to have Day[] in the model.

Angular 6 not able to render data on view

hello i am learning angular 6 and i am creating a simple app where i get data from API using Services Module and data is coming from API but when i try to display in view it gives error below is my code please help me what i am doing wrong.
Comoponent
export class LibraryComponent implements OnInit {
users$: Object;
constructor(private data: DataService) { }
ngOnInit() {
this.data.getLibrary().subscribe(
data => this.users$ = data
);
}
}
HTML
<h1>{{users.artist.name}}</h1>
API Data
{
"artist":{
"name":"Bebe Rexha",
"mbid":"db8fad3a-e131-47a1-8782-c2ee93708cdd",
"url":"https://www.last.fm/music/Bebe+Rexha",
"image":[
{
"#text":"https://lastfm-img2.akamaized.net/i/u/34s/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"small"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/64s/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"medium"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/174s/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"large"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/300x300/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"extralarge"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/300x300/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":"mega"
},
{
"#text":"https://lastfm-img2.akamaized.net/i/u/300x300/3c877e9871c5a1c6b23ba80c69e5cfb1.png",
"size":""
}
],
"streamable":"0",
Error
LibraryComponent.html:1 ERROR TypeError: Cannot read property 'artist' of undefined
at Object.eval [as updateRenderer] (LibraryComponent.html:1)
users$ is undefined in your ts initially and on subscribing to the data from the observable it assigns a value to the users$ property.
<h1>{{users$?.artist.name}}</h1>
The ? here handles the undefined problem.
In the assigning user to the "users$" variable but in the html you are referring to the wrong reference "users".
Please use ? safe navigation operator of angular. it will not throw any error if value is not available.
<h1>{{users$?.artist?.name}}</h1>

Angular 6.0.5 - Cannot access property that's there

I, for the life of me cannot understand why I can't access a property on an angular 6 class. Here is some code:
#Component({
selector: 'admin-badge-component',
templateUrl: './badge.component.html'
})
export class AdminBadgeComponent implements OnInit {
// Badge Object
public badgeObject: IVisitorBadge = null;
// On Init
public ngOnInit() {
this.route.params.subscribe((params) => {
// Get Badge Object From API
this.visitorService.getVisitorBadge(params['aid'],params['vid'])
.subscribe((response: IVisitorBadge) => {
console.log(response);
this.badgeObject = response;
});
});
}
}
the console.log outputs every thing as intended:
{
"id":2,
"visit_id":325,
"visitor_id":45,
"created_at":"2018-09-29 15:00:10",
"updated_at":"2018-09-29 15:00:10",
"visitor": {
...
"firstname": "matthew",
"lastname": "brown",
...
}
}
However, when I goto access and display the visitor firstname in my template using the following code:
<div>
<h3>
{{ badgeObject?.visitor?.firstname }} {{ badgeObject?.visitor?.lastname }}
</h3>
</div>
Nothing displays. If I try to access the properties directly without the ? notation, I get cannot access 'firstname' of undefined. Even if I wrap the template in *ngIf and check for property first. I've also tried initting and setting a loadingBool that gets set to false after I have the API response, and using it in the *ngIf still nothing.
Here is screenshot of full class: https://imgur.com/a/eEfCSL3
public constructor(private _change: ChangeDetectorRef) { }
this.visitorService.getVisitorBadge(params['aid'],params['vid'])
.subscribe((response: IVisitorBadge) => {
this.badgeObject = response;
this._change.markForCheck();
});
});
You have to tell the change detector that the component is dirty when you lazy load data. The first time the template is rendered the value of badgeObject is null, but later it is assigned a value.
Use the ChangeDetectorRef:
https://angular.io/api/core/ChangeDetectorRef
Found the issue. Not mentioned above is the this.visitorService.getVisitorBadge method, which I was accidentally setting the responseType to text in the HttpClient callout. Reset that back to json, now it's working.

Angular: Cannot read property 'insertNode' of undefined at TransitionAnimationEngine

I have created my own directive, that hides content if user is not logged: *onlyUser. When I try to use it in component that utilises ng/animation I sometimes get an error:
Cannot read property 'insertNode' of undefined at TransitionAnimationEngine
Directive looks like this:
export class OnlyUserDirective {
constructor(private _templateRef: TemplateRef<any>,
private _viewContainer: ViewContainerRef,
private _userContextService: UserContextService) {
this._userContextService.isLogged$().subscribe(x => {
if (x === true) {
this._viewContainer.createEmbeddedView(this._templateRef);
} else {
this._viewContainer.clear();
}
});
}
}
And when I try to use it within a component with #Component({ animations: [...] }) I sometimes get the error from this question's beginning. Is this expected behavior, or an angular bug?
It is a known bug -> https://github.com/angular/angular/issues/19712.
I am checking if it is working with Angular 5

Angular 2: {{object}} works, {{object.child}} throws error

Been working with Angular v1 for some time now and since Angular v2 came in Beta, been playing around with that.
Now I've got this piece of code, but can't get it to work, really don't know why. Somehow, when I print {{profileUser | json}} everything works fine (profileUser is an object).
But when I want to print a child of that object (for example {{profileUser.name}} or {{profileUser.name.firstName}}), Angular throws the following error:
EXEPTION: TypeError: undefined is not an object (evaluating 'l_profileUser0.name') in [ {{profileUser.name}} in ProfileComponent#4:11.
It's really confusing to me, should be just one of the simplest things around.. Just started with TypeScript btw..
Here is some code - ProfileService.ts:
import { Injectable } from 'angular2/core';
import { Headers } from 'angular2/http';
import { API_PREFIX } from '../constants/constants';
import { AuthHttp } from 'angular2-jwt/angular2-jwt';
import 'rxjs/add/operator/map';
#Injectable()
export class ProfileService {
API_PREFIX = API_PREFIX;
constructor(private _authHttp:AuthHttp) {
}
getProfileData(username:string):any {
return new Promise((resolve, reject) => {
this._authHttp.get(API_PREFIX + '/users/username/' + username)
.map(res => res.json())
.subscribe(
data => {
resolve(data.data);
},
err => {
reject(err);
}
)
;
});
}
}
And here is my ProfileComponent:
import {Component, OnInit} from 'angular2/core';
import {RouteParams} from 'angular2/router';
import {ProfileService} from '../../services/profile.service';
#Component({
selector: 'profile',
templateUrl: './components/profile/profile.html',
directives: [],
providers: [ProfileService]
})
export class ProfileComponent implements OnInit {
public username:string;
public profileUser:any;
constructor(private _profileService: ProfileService,
private _params: RouteParams) {
this.username = this._params.get('username');
}
ngOnInit() {
this.getProfileData(this.username);
}
getProfileData(username:string):void {
this._profileService.getProfileData(username)
.then(data => {
this.profileUser = data;
console.log(data);
})
;
}
}
Finally, the profile.html template:
<pre> <!-- works! -->
{{profileUser | json}}
</pre>
or..
<pre> <!-- throws the error -->
{{profileUser.name | json}}
</pre>
or..
<pre> <!-- throws the error -->
{{profileUser.name.firstName}}
</pre>
FYI, the profileUser looks like this:
{
"id": "9830ecfa-34ef-4aa4-86d5-cabbb7f007b3",
"name": {
"firstName": "John",
"lastName": "Doe",
"fullName": "John Doe"
}
}
Would be great if somebody could help me out, this is really holding me back to get familiar with Angular v2. Thanks!
In fact your profileUser object is loaded from an HTTP request and it can be null at the beginning. The json pipe simply does a JSON.stringify.
It's what your error message said: undefined is not an object (evaluating 'l_profileUser0.name').
You need to be sure that your profileUser object isn't null to be able to get its name attribute and so on. This can be done using an *ngIf directive:
<div *ngIf="profileUser">
{{profileUser.name | json}}
</div>
When the data will be there, the HTML block will be displayed.
As Eric stated the Elvis operator could also help you. Instead of having {{profileUser.name | json}}, you could use {{profileUser?.name | json}}.
Hope it helps you,
Thierry
It happens because when your controller is created, the profileUser is undefined. And, when you use {{profileUser | json}} the filter json knows that you data is undefined and do nothing. When the profileUser is finally defined, the angular updates thw whole thing and then profileUser | json works. But, when you use {{ profileUser.anything | json}} you will get an error because profileUser starts undefined.
You can solve it, setting a empty profile to your variable at beginning of your controller, just like that:
profileUser = { name: {}};
This way, profileUser never will be undefined

Categories