Cannot read property 'name' of null Angular2 JSON - json

I got this code in AppComponent:
getPlanetsToView(page){
let pageToView = page*10 + 10;
for(var i=0; i<pageToView; i++){
this.planetsToView.push(this.planets.planets[i]);
}
}
ngOnInit() {
this.http.get('app/planets.json').subscribe(res => {
this.planets = res.json();
console.log(this.planets);
this.getPlanetsToView(0);
});
And I have this in template:
{{planetsToView[0].name | json}}
I have got problem:
Photo
When I tried with {{planetsToView[0] | json }} it works but contain another properties also.

Could be this problem:
At the time your component is initialized your JSON is not yet loaded into this.planets because the http.get call is asynchronous. Can you try this in your template: (Note the ? which is added)
{{planetsToView[0]?.name | json}}
The ? is called elivs operator and is used to safe guard against undefined references in view templates. Read more here:

Related

Angular Get method returns an Undefined instead of object

I am an Angular beginner and I've made a service and made all the set up so that the Get method works on a JSON file and it worked! but the problem is whenever I want to access to the data inside the JSON file it tells me that it is undefined, and I want to use it as an object in the ts file.
It works when using data biding like this {{stats | JSON}}, but I couldn't use it in the TS. can I convert this 'undefined' to a simple object?
stats: any;
constructor(private statsData: StatDataService) {
this.statsData.GetEmbedded().subscribe((data: any) => {
this.stats = data;
});
}
`
for example I can't use stats.preOrders[0]
To better understand the situation, let's create an example.
example.component.ts
interface Statistics {
median: number;
average: number;
}
export class Example {
// stats is undefined until GetEmbedded() fires
stats?: Statistics;
constructor(private statsData: StatDataService) {
this.statsData.GetEmbedded().subscribe((stats: Statistics) => {
this.stats = stats;
});
}
}
example.component.html
<div>The median is: {{ stats.median }}</div>
Why will this example result in an error? Your variable stats initially is undefined, so it will not have any properties. GetEmbedded() will take some milliseconds to fire but in the same time, the template already tries to access stats.median.
One option to solve this problem would be to check if the variable stats is not undefined and if it is not, access the properties you need.
example.component.html
<div *ngIf="stats">The median is: {{ stats.median }}</div>

Parsing JSON to display the data in angular

So I have my data stored in database and I'm extracting in angular and I'm getting the data the problem is when I'm trying to display the data I'm getting the following error. I just need to display the question in html using ngFor* .I'm completely new to angular any guidance will be very helpful .
this.selfHelpService.getFgSelfHelpByName("BYOD").subscribe(data => {
// console.log(data);
const BYOD = JSON.parse(data["data"]);
// console.log(BYOD );
});
<div class="cards" *ngFor="let BYOD of BYOD">
<div class="read-1">
{{BYOD.posts.question}}
</div>
</div>
since you are getting the data, you can do the following:
// If this is your response:
{"BYOD":[ ` { "posts": [ {"Question":"BYOD (Android)","answer":"???"}, {"Question":"BYOD (IOS)","answer":"?????"} ] } ] };
this.selfHelpService.getFgSelfHelpByName("BYOD").subscribe(data => {
try {
const BYOD = JSON.parse(JSON.stringify(data["data"]));
} catch(err) {
console.log('Try catch error ==>', err);
}
// Declare a variable in the component.ts above constructor called byodPostsData
// Assign the values to that variable
this.byodPostsData = BYOD[0].posts;
});
// In your HTML now, simply loop through the this.byodPostsData;
<div class="cards" *ngFor="let eachPost of byodPostsData">
<div class="read-1" *ngIf="eachPost && eachPost.question">
{{ eachPost.question }}
</div>
</div>
As mentioned earlier by other commentators here: Am not sure why you are using JSON.parse(). But if you should use it for sure, then try using this:
// Generally its considered good practice to use try-catch for JSON.parse() for data
try {
const BYOD = JSON.parse(JSON.stringify(data["data"]));
} catch(err) {
console.log('Try catch error ==>', err);
}
I am not sure what you are trying to loop, but, if you want to loop over byod,
<div class="cards" *ngFor="let byod of byod.BYOD[0].posts">
<div class="read-1">
{{byod.Question}}
</div>
</div>
Besides in your example code, byod is locally scope in the function, you should make a component variable from that to make it accessable by the HTML.
Feel free to ask if something is unclear.
As you are new to Angular: this is how decided to access the response:
The 0 should come from the fact that the response is a JSON object with a JSON key BYOD which has an array as value: so the BYOD[0] indicates that you are trying to access the first item of the array from BYOD, which is another object with the JSON key "posts", the value of "posts" is an array you want to loop over. If you parse the data from the request to a component property called byot, it should be accessable in the html the following: byod.BYOD[0].posts I hope I made it a bit more clear.
Here is a stackblitz!
https://stackblitz.com/edit/angular-ivy-jcxgfo?file=src/app/app.component.ts

Nested *ngFor in Observable Array

I am trying to bind a nested observable array using Angular 6 in my HTML and show the list(image_urls) in my carousel.
However, I am unable to bind the nested array. Any help or advice is much appreciated. Thanks in advance
This is what I have so far:
Components.ts
getAvailableCars()
{
this.cars$ = this.carService.getAvailableCars();
this.cars$.subscribe(car => {
car.forEach(c => {
c.image_urls = new Array<any>();
this.fileUploads = this.uploadFileService.getFiles(c.car_id);
this.fileUploads.subscribe(res => {
c.image_urls = res;
});
});
});
}
HTML
<div class="row" *ngFor="let car of cars$ | async”>
<span>{{car.name}}</span>
<mdb-carousel [isControls]="true" [animation]="'slide'”>
<mdb-slide *ngFor="let file of car.image_urls | async”>
<span>{{file.url}}</span>
</mdb-slide>
</mdb-carousel>
</div>
Console
Car(3) [{…}, {…}, {…}]
0:
car_id: 30
exterior_color: 4
fuel_type_name: "Petrol"
image_urls: Array(2)
0: FileUpload {url: "https://s3.amazonaws.com/xx/30/SocialPost_5695408_facebook.png"}
1: FileUpload {url: "https://s3.amazonaws.com/xx/30/logo_size.jpg"}
length: 2
__proto__: Array(0)
If i use this.fileUploads directly in the Carousel it works, but not when i push it to c.image_urls. Since, I have multiple cars and each have different image urls, I need to add the image_urls to the object of car.
Thanks again!
I got it working. I was modifying the observable in subscribe instead of in map.

Observable with Angular 4 , NgFor only supports binding to Iterables such as arrays

Yes, I see that other people get this error , I just don't quite get how to fix it in my code
private _url = 'https://min-api.cryptocompare.com/data/pricemulti?fsyms=BTC,ETH,LTC,EOS,DASH&tsyms=USD'
If I didn't have the return it does not crash with the error , but I do want to return the data.
I have a component that calls up this method ( in this service ts file )
Subscriber:
getAllCoins() {
var blah = [];
return this.getCoins().subscribe(
data => {
blah = data;
//console.log('subscriber coins', blah)
}
)
}
Calls this code
getCoins() {
return this.http.get(this._url)
.map((response: Response) => response.json())
//.do(data => console.log(data))
.do(data => console.log('All: ' + JSON.stringify(data))) // do operator to peek
.catch(this.handleError);
}
Now, I see that the data from the url looks like this
{
"BTC": {
"USD": 3349.1
},
"ETH": {
"USD": 296.3
},
"LTC": {
"USD": 47.56
},
"EOS": {
"USD": 1.83
},
"DASH": {
"USD": 195.83
}
}
How can I prevent from getting this error errors.ts:42 ERROR Error: Uncaught (in promise): Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
UPDATE for comment question
#Component({
template: `
<div>test</div>
<div *ngFor="let coin of coinsList">
abc
</div>
`
})
As others have said, *ngFor only works on iterables.
There are a couple of methods that can be done to overcome this problem. Ones that come to my mind right now are:
1) You can push your list of objects to an Array.
this._ConfigurationService.getCoins()
.subscribe(
(data)=> {
for(let key in data){
this.coinsList.push(data[key]);
}
},
(error) => console.log("error : " + error)
);
template:
<div *ngFor="let coin of coinsList">
<span>{{coin | json}}</span>
</div>
Full plunker example: http://plnkr.co/edit/zrzVF8qKl8EvKKp2Qt45?p=preview
2) You can convert the response from object to an iterable using a pipe as shown in here: How to iterate [object object] using *ngFor in Angular 2
3) You can implement the iterable function to your object as shown here: Angular NgFor only supports binding to Iterables such as Arrays.
4) You can create special directive as shown here: Can ngForIn be used in angular 4?
My suggestion would be to use the first one for simplicity.
As the erorr says you are trying to do a ngFor over Object, it works over any iterables.
Probably you can iterate over them and create an array, and then use it for the ngFor.

How to render angular variables using innerHTML - Angular2

In my application their is some text which is coming from a constant file which is declared like this:
export const EmpStrings = {
data: "Welcome {{employee.name}}"
}
And In my component file there is an object called employee.
public employee = { name: 'xyz', dept: 'EE' }
Now In my HTML I want to use it like this:
<div class='e-data' [innerHTML] = "EmpStrings.data"></div>
But this didn't seems to be working.
I tried various variations:
[inner-html] = "EmpStrings.data"
[innerHTML] = {{EmpStrings.data}}
[innerHTML] = "{{EmpStrings.data}}"
But none of them seems to be working.
If you don't want to use JitCompiler then you can parse string yourself
component.ts
ngOnInit() {
this.html = EmpStrings.data.replace(/{{([^}}]+)?}}/g, ($1, $2) =>
$2.split('.').reduce((p, c) => p ? p[c] : '', this));
}
template
<div [innerHTML]="html"></div>
Plunker Example
use ${employee.name} to bind angular variable to innerHTML
"data": `Welcome ${employee.name}`
Angular doesn't interpolate strings like this, as far as I know one of the reason is security. The const doesn't have the context where your employee is in hence you see the error saying employee is not defined.
You could do this:
Change your constant:
export const EmpStrings = {data: "Welcome "};
then:
<div class='e-data'>{{EmpStrings.data}}{{employee.name}}</div>
But if for some reason you must use [innerHTML]:
In your component class, add a method:
getWelcomeMessage(){return EmpStrings.data + this.employee.name;}
in the component view:
<div class='e-data' [innerHTML] = "getWelcomeMessage()"></div>