How to show TypeScript object in HTML (Ionic/Firebase/Angular) - javascript

How do I display an object in my HTML file? (Using Ionic) It seems fairly simple, but it won't work. I retrieve the object like this, from a snapshot of my database path:
this.userPath.subscribe(snapshots => {
this.snapshotValue = snapshots.val()
console.log(this.snapshotValue);
})
And the console looks something like this:
http://i.imgur.com/Kk0A6n5.png (I don't have 'reputation' to post images)
I feel like I've tried everything. Like:
<h1>{{snapshotValue}}</h1> //this returns "[object object]"
<h1>{{snapshotValue.navn}}</h1> //this gives me an error: "cannot read property navn of undefined"
<h1>{{snapshotValue[0]}}</h1> //this gives me an error: "cannot read property '0' of undefined.
How do I get the individual values from this object?

you want to use the async pipe with the elvis operator (?) for observables. Below is using just the elvis.
<h1>{{snapshotValue?.navn}}</h1>
The elvis operator checks if the object exists before checking for a property on the object.
In the future instead of using this
this.userPath.subscribe(snapshots => {
this.snapshotValue = snapshots.val()
console.log(this.snapshotValue);
})
you can do
<h1>{{(userPath | async)?.navn}}</h1>
https://angular.io/api/common/AsyncPipe
The async pipe does the subscribe and gets the latest value for you

This happens when you try to render the view before the data is available.Try the following method
In your component declare a boolean variable
private isDataAvailable:boolean=false;
And in your subscribe method make this true once the data is available
this.userPath.subscribe(snapshots => {
this.snapshotValue = snapshots.val()
console.log(this.snapshotValue);
this.isDataAvailable=true;
})
And reneder the template once the data is available using *ngIf
<div *ngIf="isDataAvailable">
<h1>{{snapshotValue}}</h1>
<h1>{{snapshotValue.navn}}</h1>
<h1>{{snapshotValue[0]}}</h1>
</div>
This should do the trick.You can also use async pipe for the same.Find docs here

<h1>{{snapshotValue | json}}</h1> // this should return you a { stringified json }

Related

Can I use a dynamic value to access a specific array in Vue.js?

I've been trying to figure out how to do this, but can't seem to get it to work. I have created a function that is being called when I click a component using v-on:click. I am also trying to pass in a value that I can then use to access a particular array that is coming in the form of data from a backend.
Here is the function in the component:
<v-card
#click="getContent('topSellers')"
>
I am then passing the 'topSellers' value as an "id" into the function that is being used to get access the exact array that I am looking for:
getContent(id) {
this.accordion = this.data.id;
console.log("data", id);
}
First of all, this.data.topSellers works. And I am seeing that the id value is correct in the console. Obviously, this is not working because id is currently a string, but I don't know how to fix that issue. Any help would be appreciated!
You need this.data[id] instead of this.data.id.
See property accessors on MDN for reference.
data[id] will access the property of data with the name of the value of id, in your case topSellers. So data.topSellers is equivalent to data["topSellers"]
[] allows you to access objects with variables.
It is recommended to handle exceptions because the variable received is not safe.
getContent(id) {
const accordion = this.data[id] || null;
if(accordion){
console.log("data", accordion);
this.accordion = accordion;
}
}

How to handle "Error in render: TypeError: Cannot read property 'abc' of undefined" in Vue js

Real-world data is often not as structured as we think. I remember if an angularjs template tries to access a property of undefined, it just renders an empty string. I like this default very much. When it comes to Vue, a single error will prevent the whole component from rendering.
I read about error boundary but it is unrealistic to wrap every single element that might access a property of undefined.
My question is: how to gracefully handle such errors and confidently build a component that always renders, even with bad data?
You can use something like this:
<p>{{x?x.abc:""}}</p>
if x in not defined in your data object, this will raise a warring but your app will still functioning ok.
One way to work around this warring, is to define a getter like for x in your computed object, something like this:
{
data(){
_x:null, //or it may completely missing or an empty object {}
},
computed:{
x: function(){
return this._x?this._x:{}
}
}
}
now you can use it like:
<p>{{x.abc}}</p>

How to load page after array is filled?

I have got an angular app, with a component named "detail".
In the detail.component.ts I fetch data from an API and fill it in an array, then filter the array for a certain item and put this item in another array. Here is the shortened code:
import { HttpClient } from '#angular/common/http';
//code
public data: any = []
public item: any = []
//code
constructor(public http: HttpClient) { }
getData()
{
const url ='myUrl'
this.http.get(url).subscribe(data => {this.data = data; this.item=this.data.find(/*my search*/)})
}
//code
ngOnInit()
{
this.getData()
}
Then I display the properties of the selected Item with the file "detail.component.html" like this:
<div><span>Name: </span>{{item.name}}</div>
This works, the items properties are displayed.
The problem is, that in the console a lot of ERROR messages appear. They go like this:
Cannot read property 'name' of undefined at Object.eval [as updateRenderer]
It seems like it is trying to render and display the item.name before the function getData() is done and the array is filled.
Have you any idea how to solve this so that there are no error messages in the console anymore?
Just
use this
<div><span>Name: </span>{{item?.name}}</div>
OR
<div *ngIf="item"><span>Name: </span>{{item.name}}</div>
Try adding a check before displaying it in the UI.
<div *ngIf="item"><span>Name: </span>{{item.name}}</div>
And so the item.name wont be evaluated until there is value in item.
As the error is self-explanatory, it is trying to render the view even before the data is available. You can add the defensive condition to resolve this. Something like *ngIf="item && item.name".
Hope it helps!
You can also use Safe navigation operator ? like this:
<div><span>Name: </span>{{item?.name}}</div>
Use a Resolve. Angular Documentation For Resolve
Example Of an Resolve

ERROR TypeError: Cannot read property 'list' of undefined

Getting the error as mentioned when I am trying to get the response from API call and display the information in the response object in the template.
ERROR TypeError: Cannot read property 'list' of undefined.
In service.ts, I am making a server call. I am using OpenWeatherMap API.
getDetails(cityName, countryCd): Observable<any>{
return this.httpclient.get(`${this.url}${cityName},${countryCd}&APPID=${this.apiKey}`);
}
Object format returned by the API:
{"city":{"id":1851632,"name":"Shuzenji",
"coord":{"lon":138.933334,"lat":34.966671},
"country":"JP",
"cod":"200",
"message":0.0045,
"cnt":38,
"list":[{
"dt":1406106000,
"main":{
"temp":298.77,
"temp_min":298.77,
"temp_max":298.774,
"pressure":1005.93,
"sea_level":1018.18,
"grnd_level":1005.93,
"humidity":87,
"temp_kf":0.26},
"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04d"}],
"clouds":{"all":88},
"wind":{"speed":5.71,"deg":229.501},
"sys":{"pod":"d"},
"dt_txt":"2014-07-23 09:00:00"}
]}
In home.component.ts, I am subscribing to the service API call. I am getting the reposnse which is of type 'object'.
I have an array of objects called cities. I am loading the response object from the server as one of the property in each object of the array cities.
this.cities = this.cityService.getCities().slice();
this.cities.forEach(element => {
this.weatherService.getDetails(element.cityName, element.countryCd).subscribe(response => {
element['cityWeather'] = response;});
});
In home.component.html, I am iterating this cities array and the using the response data from the API. The data is displayed properly without any issues.
But in the console I am seeing an error for every iteration of cities array -
ERROR TypeError: Cannot read property 'list' of undefined.
<div class="col-md-4" *ngFor="let city of cities; let i = index">
<span>{{city.cityWeather.list[0].main.temp | kelvinToCelcius}} ℃</span>
<span>{{city.cityWeather.list[0].wind.speed | mtrPersecToKmPerhr}} km/h</span>
</div>
I am relatively new to Angular, need to know what is this error about and how this can be resolved.
Your issue is that in your home component you refer to
<span>{{city.cityWeather.list[0].main.temp | kelvinToCelcius}} ℃</span>
<span>{{city.cityWeather.list[0].wind.speed | mtrPersecToKmPerhr}} km/h</span>
These values may not be defined at all times, so if city.cityWeather is undefined, accessing the .list property would result in the error
Cannot read property 'list' of undefined.
You can fix this by using the Angular safe navigation operator (also known as the Elvis operator).
The Angular safe navigation operator (?.) is a fluent and convenient way to guard against null and undefined values in property paths
-- Angular docs
By changing . to ?., Angular will not throw an error if it can't find the property on the object.
Note that this only works in component templates, and not in TypeScript files.
You can either use The Angular
safe navigation operator (?.)
city.cityWeather?.list[0]?.main.temp
city.cityWeather?.list[0]?.wind.speed
or you can try using Angular async pipe
https://angular.io/api/common/AsyncPipe
Try to change your code like this:
<div class="col-md-4" *ngFor="let city of cities; let i = index">
<span>{{city?.cityWeather?.list[0]?.main?.temp | kelvinToCelcius}} ℃</span>
<span>{{city?.cityWeather?.list[0]?.wind?.speed | mtrPersecToKmPerhr}} km/h</span>
</div>
This may be due the fact that your getCities() request is completed and your getDetails() call is yet to return response which it will give at some point in time due to the asynchronous nature of code. So when the loop execute cityWeather is not available and you get the error. The ? will not throw error but instead it will show data when it will be available.

Angular 5 - Replacement for json().token in HttpClient? [duplicate]

I am trying to change an existing app from using Http to using HttpClient, however i have an error.
So in my service now you can see the new code vs the old code that's been commented out:
constructor(
// private http: Http
private http: HttpClient
) { }
getSidebar() {
// return this.http.get('http://localhost:3000/sidebar/edit-sidebar')
// .map(res => res.json());
return this.http.get('http://localhost:3000/sidebar/edit-sidebar');
}
And in my page.component.ts I have this
this.sidebarService.getSidebar().subscribe(sidebar => {
this.sidebar = sidebar.content; // this does not work now
});
However for the line above which I commented on I get this error now:
Property 'content'
does not exist on type 'Object'.
However if I console.log(sidebar) I get the following:
{_id: "59dde326c7590a27a033fdec", content: "<h1>sidebar here</h1>"}
So what's the issue?
Once again, Http works but HttpClient does not.
You can specify the type that is being returned, using an interface, class, etc. For example, you can use something like the following:
return this.http.get<Sidebar>('http://localhost:3000/sidebar/edit-sidebar');
As an example, Sidebar might be defined as:
interface Sidebar {
_id: string;
content: string;
}
See Typechecking the response from the Angular docs for further information:
...TypeScript would correctly complain that the Object coming back from HTTP does not have a results property. That's because while HttpClient parsed the JSON response into an Object, it doesn't know what shape that object is.
HttpClient parse automatically the JSON response to an Object and the shape of that object is not known, that's why Typescript show this error
alternative solution, using bracket notation:
this.sidebarService.getSidebar().subscribe(sidebar => {
this.sidebar = sidebar["content"];
});
You can assign the variable(sidebar) an interface to explicitely tell what it will get or assign to it so it doesnt throw compile time error.
this.sidebarService.getSidebar().subscribe((sidebar: any) => {
this.sidebar = sidebar.content;
});
you can do this like that with type <any>
if you do this you will not get that error
this.http.get<any>('http://localhost:3000/sidebar/edit-sidebar');
Using bracket notation instead of dot notation to reference sidebar['content'] instead of sidebar.content will solve the issue.
The Type-checking the response section of the Angular docs on HttpClient mention's this, although it's not all that clear:
The subscribe callback above requires bracket notation to extract the
data values. You can't write data.heroesUrl because TypeScript
correctly complains that the data object from the service does not
have a heroesUrl property.
Error Description
ERROR in src/app/home.component.ts(131,20): error TS2339: Property
'someProperty' does not exist on type '{}'.
why Occured ?
I think this error is in service file , whenever you making http call and that call returns any Object(json) or array of Objects (json) , then yours http call should return Observable or Model of that result type
Home.service.ts
connectToServer(data) {
return this.http.post('http://localhost:5000/connect' , data)
}
Suppose , I have above Post http call , where i connect to server by passing data inside 'data' and this request returns me connection Object (Json).But where u seen that i didn't specify observable or model for holding result and if i access the result Object properties from component.ts it will says result.somepropery does not exist on {} .
Solutions
First :
connectToServer(data) : Observable<any> {
return this.http.post('http://localhost:5000/connect' , data)
}
Note : Don't forget to import Observable
Second :
connectToServer(data) : <Connection> {
return this.http.post('http://localhost:5000/connect' , data)
}
In second case you need to define Interface for declaring Connection Object fields and needs to import here.

Categories

Resources