I have an issue with Observables in Angular 2
My component calls service function on Init like below:
delivery: IDeliveryCountry[];
ngOnInit() {
this.checkoutService._getInfo().subscribe(dev => this.delivery = dev);
}
This is how interface looks like IDeliveryCountry:
export interface IDeliveryCountry {
iso: string;
name: string;
}
This is how Service looks like:
_getInfo(): Observable<IDeliveryCountry[]> {
return this.http.get(this.deliveryCountryUrl)
.map((response: Response) => <IDeliveryCountry[]>response.json())
}
json file with data looks like this:
[
{
"iso":"se",
"name":"Sweden"
},
{
"iso":"dk",
"name":"Denmark"
}
]
My html file is just a simple ngFor loop:
<div *ngFor='let dev of delivery'>{{dev.iso}}</div>
So far all things works perfect, as expected I get back "se" and "dk" in UI.
The problem appears when I change a structure of data in my json file to following:
{
"country": {
"iso":"se",
"name":"Sweden"
}
}
I want data to only have one country with iso and name property for it. So my html file looks like following:
<div>{{delivery.iso}}</div>
But I am getting iso as undefined all the time
" Cannot read property 'iso' of undefined "
Thank you!
You should first of all use:
{{delivery.country.iso}}
The undefined error you are getting, is because the data is coming async, so use the safe navigation operator to avoid this:
{{delivery?.country?.iso}}
Demo
Optionally you could extract the data that is inside country, so you can shorten your code in your template from {{delivery?.country?.iso}} to just {{delivery?.iso}}, this can be done like so:
.map(res => res.json().country) // extract the data from the object country
You can just do this without ngFor since it is an Object
<div>{{delivery.country.iso}}</div>
After your comments, undefined is because the data is coming async, so use the elvis operator to avoid this:
{{delivery?.country?.iso}}
Alternatively you could change your service to return the DeliveryCountry[]
getInfo(): Observable<IDeliveryCountry[]> {
return this.http.get(this.deliveryCountryUrl)
.map((response: Response) => response.json())
.map(delivery => delivery.country);
}
Then:
ngOnInit() {
this.checkoutService.getInfo()
.subscribe(deliveryCountries => this.deliveryCountries = deliveryCountries);
}
Then:
<div *ngFor="let deliveryCountry of deliveryCountries">{{deliveryCountry?.iso}}</div>
Related
I am a little confused about how to go about this. So I have this JSON file called posts.json.
[
{
"id": 1,
"title": "Kylie Jenner",
"content": "Social Media Public Figure",
"disclaimer": "*Disclaimer: This user may have comment filtering turned on",
"slug": "hello-world",
"img" : "https://ilarge.lisimg.com/image/16801290/1080full-kylie-jenner.jpg",
"banner" : "https://i.pinimg.com/originals/a5/2b/96/a52b963809c7e64e538b113cccf61dda.jpg",
"handle": "kyliejenner",
"handlelink" : "https://www.instagram.com/kyliejenner/"
}
]
I am currently trying to make a GET request to an API(url) that also includes specific data from my json file. In this case it will include the celebs handle. This is what I have setup here on Graphs.js.
export default class Graph extends Component {
constructor(props) {
super(props);
}
state = {
handle: '',
}
componentDidMount() {
axios.get('http://localhost:5000/celebs/' + handle)
.then(response => {
this.setState({ celebs: response.data })
})
.catch((error) => {
console.log(error);
})
}
}
I am aware this isn't right as this is where I am stuck. "+ handle" is to come from the json file. I want to make a request to the url where /handle will match the handle directly from json file as defined "handle": "#kyliejenner". But I keep getting an error saying 'handle' is not defined no-undef. No matter how I do it, I can't seem to get it right and keep getting the same error.
So how do I go about defining handle with the data from the json file passed into it? More specifically the handle data.
I apologize in advance if this isn't clear. Please let me know if you need further clarrification.
You can store the json in a different file assign the data to an object and you can import it like this.
import posts from 'posts.js';
Now you have access to the posts object in your component, so you can just access it using
const handle = posts[i].handle; //pass the index of array(i);
As pointed in the comment by Sean, your local state is a bit wrong. You should declare it like this:
constructor(props) {
super(props);
this.state = {handle: ''};
}
And use it like this:
axios.get('http://localhost:5000/celebs/' + this.state.handle)
Or, using Template Literals:
axios.get(`http://localhost:5000/celebs/${this.state.handle}`)
More info in the docs: https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
I'm kinda new to Angular and I need to do a function that does an http.post on click and it works (POST DONE is returned and I get the data), the problem is that i need to render data inside tables but 'postReponse' returns only [Object Object] in my html file and I can't find a way to render the data as it should, does anyone have a fix for this issue please ?
Here's the code sample :
public postReponse: any;
postRefs(){
return this.httpClient.post('someUrl',
{
"someBody"
})
.subscribe(
data => {
console.log("POST DONE", data)
return this.postResponse = data;
},
error => {
console.log("ERROR POST", error)
}
)
}
//home.component.html
<tr>
<td>{{postResponse}}</td>
<td>{{postResponse}}</td>
<td>{{postResponse}}</td>
<td>{{postResponse}}</td>
</tr>
postResponse is an object with keys and values, for example if it contains two attributes id and name then it will look like this :
{ id : 1, name = 'name' }
So if you need to access to the name attribute you need to write inside your html:
<td>{{postResponse.name}}</td>
I am trying to get the get the data from oracle db and displaying it. I have created a service using express api and node and able to run it successfully.
I have created angular service to fetch the data, and assign it in angular component, but i am not able to map the JSON response to the angular variable. Please check the code below and help me what i need to change in angular component.ts and how can i use that variable in html.
JSON Data from oracle DB:
[{"COUNT":27}]
angular service:
getCount(): Promise<String[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => response.json().data)
.catch(this.handleError);
}
angular component.ts
dataGS : String[];
getData(): void {
this.dataService
.getCount()
.then(dataGS => this.dataGS = dataGS);
Your response does not have a property data, it's just an array. So instead of:
.then(response => response.json().data)
do:
.then(response => response.json())
Now you will get your array. Then as proposed by jitender you can iterate your response:
<div><p *ngFor="let d of dataGS ">{{d}}</p></div>
You can achieve this with the help of template bindings in angular.
For Example -
In your component you receive this.dataGS = [{"COUNT":27}] after getting the data from the db. Then on your html template you can display this with the help of Interpolation like
<div>{{dataGS[0].count}}</div>
What about
getCount(): Promise<String[]> {
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => {
response.json().map(function(item) {
return item['COUNT'];
})
})
.catch(this.handleError);
}
in your html
<div><p *ngFor="let d of dataGS ">{{d}}</p></div>
I can't bind my Angular HTML to my devices array because there is a mismatch between what I am expecting the object to look like. I want to bind to device.modelName but it fails because the object I'm actually getting back has the property ModelName without camelCase!
Googling a solution I saw that I should use type assertion so I did by adding <DeviceStatus[]> resulting in the line <DeviceStatus[]>response.json()); in my component class. Unfortunately this didn't seem to change anything.
Why does it seem like my json object isn't being mapped properly?
My model interface:
export interface DeviceStatus {
deviceId: string;
modelName: string;
}
My component:
export class FetchDataComponent {
public devices: Observable<DeviceStatus[]>;
constructor(http: Http) {
this.devices =
http.get('api/Devices')
.map((response: Response) => <DeviceStatus[]>response.json());
this.devices.subscribe(x => console.log(x));
}
}
The result in Chrome console:
(2) [Object, Object]
0: Object
DeviceId: "1"
ModelName: "Model Name"
...
Type assertion only informs the compiler, it does nothing to the actual data as it says in the docs:
A type assertion is like a type cast in other languages, but performs
no special checking or restructuring of data
Always remember that the type system in typescript doesn't get translated to javascript, so in runtime you don't have that.
You'll need to do the convertion yourself:
this.devices =
http.get('api/Devices')
.map((response: Response) => response.json().map(device => ({
deviceId: device.DeviceId,
modelName: device.ModelName
}));
Here is the ASP.NET code using the formatter:
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver=
new CamelCasePropertyNamesContractResolver();
It converts the properties to camel case before returning them in the response.
You can find out more about it here: http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Serialization_CamelCasePropertyNamesContractResolver.htm
And there is a more complete example in this post here: Web API 2: how to return JSON with camelCased property names, on objects and their sub-objects
In the following code I am getting data from server and filling array with them:
Vue.http.post('/dbdata', DataBody).then((response) => {
App.$refs.userContent.rasters_previews_list.$set(response); // putting JSON answer to Component data in userContent
console.log("App.$refs.userContent.rasters_previews_list: ", App.$refs.userContent.rasters_previews_list.length);
}, (response) => {
console.log("Error")
});
Now I am filling. data is declared in var userContent = Vue.extend({. I am using App.$refs.userContent.rasters_previews_list to set it's value, because one man from SO said that there is no other way to get access to constructor. I tried to do output of rasters_previews_list after changing with watch, but here is what I am see. http://img.ctrlv.in/img/16/08/04/57a326e39c1a4.png I really do not understand am I setting it's right way or no. If yes, why I do not see data and see only this crap?
data: function () {
return {
rasters_previews_list: []
}
}
But How I can iterate it with v-for?
<ul v-for="img in rasters_previews_list">
<li>{{img}}</li>
<ul>
This code is display one bullet. So it's look like it's assume that there is one object.
My object in browser console look like:
Object {request: Object, data: Array[10], status: 200, statusText: "OK", ok: true}
Your setting the full response instead of just the data you actually need.
Vue.http.post('/dbdata', DataBody).then((response) => {
App.$refs.userContent.rasters_previews_list.$set(response.data);
console.log("App.$refs.userContent.rasters_previews_list: ", App.$refs.userContent.rasters_previews_list.length);
}, (response) => {
console.log("Error")
});
If this isn't what you are looking for please post a full example.