Angular 5 - async pipe with firebase - html

I want to add async pipe to angular firebase but i've got error that I don't know how to fix:
ERROR Error: InvalidPipeArgument: '[object Object]' for pipe
'AsyncPipe'
Firebase NoSQL database:
{
"boss" : [ null, {
"isPremium" : true,
"name" : "John",
"students" : 10000
} ],
"users" : [ null, "user", "user2" ]
}
UPDATE
I've changed component code:
user$: AngularFireList<any>;
constructor(db: AngularFireDatabase) {
this.user$ = db.list("/users");
}
html:
<ul>
<li *ngFor="let user of user$ | async">
{{ user }}
</li>
</ul>
I'm getting the same error...
In Angular version 4 it works but, how to fix that in angular 5.2.0 ??

The async pipe works with observables as argument. The error clearly states that user$ field is not an observable.
Maybe you wanted to subscribe to the valueChanges() observable of the db.object()?
Take a look here: https://github.com/angular/angularfire2/blob/master/docs/rtdb/objects.md
UPDATE
It seems that AngularFireList<any> is not an Observable, so you would receive the same error.
As I can see in the documentation of the angularfire2, the list() method returns an object in latest version, which has a valueChanges() method. Consider changing the code by calling the valueChanges() method and using the async pipe onto the resulting observable.
More details here: https://github.com/angular/angularfire2/blob/master/docs/version-5-upgrade.md#50

You're getting that error because, async pipe works with Observables and the data you're returning is not.
You might want to change your code to this:
user$: Observable<any[]>;
constructor(db: AngularFireDatabase) {
this.user$ = db.list("/users").snapshotChanges();
}
Or this:
constructor(db: AngularFireDatabase) {
this.user$ = db.list("/users").valueChanges();
}

Related

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.

Typescript casting json to object in angular using `as` doesn't work

Angular tutorial has the following line in the HTTP section:
response => response.json().data as Hero
when getting hero. response.json().data returns the following:
I tried to do the same thing. I used Django on server side and return json using rest_framework.
In Angular i have my class:
export class MyClass {
name: string;
}
response.json() returned from server looks the following way:
so what i try to do is:
myObject: MyClass;
ngOnInit(): void {
this.getResponseFromServer().then(myObject => this.myObject = myObject);
}
getResponseFromServer(): Promise<MyClass> {
return this.http.get("http://127.0.0.1:8000/myurl/")
.toPromise()
.then(response => response.json() as MyClass)
.catch(this.handleError);
}
and my template contains:
<ion-card>
<ion-card-header> Card Header </ion-card-header>
<ion-card-content>
Response from server {{myObject.name}}
</ion-card-content>
</ion-card>
and i get Error: Cannot read property 'name' of undefined.
When i change in html {{myObject.name}} to {{myObject}}, then there's no error and Response from server and i have Response from server [object Object] printed.
So the question is what is the difference between my code and angular tutorial? I've seen lots of answered question like How do I initialize a typescript object with a JSON object, but i want it to be much easier with just using as keyword.
This has nothing to do with TypeScript.
Error: Cannot read property 'name' of undefined.
is runtime error.
The example from the guide uses directives as safeguards:
<div *ngIf="hero">
<h2>{{hero.name}} details!</h2>
...
</div>
and
<a *ngFor="let hero of heroes" ...>
<div class="module hero">
<h4>{{hero.name}}</h4>
</div>
</a>
While the code above doesn't.
When myObject is originally undefined, nothing prevents compiler from parsing {{myObject.name}} expression, hence the error. Safe navigator operator (known as Elvis operator) should be used to avoid this:
{{myObject?.name}}

Observable and Angular2

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>

ember 1.12 findAll issue using rest, pod model over json response

I have a Rest adapter right configured and when I try:
router.js
export default Ember.Route.extend({
model: function() {
return this.store.find('main.user');
}
});
I got this:
WARNING: Encountered "main.user" in payload, but no model was found
for model name "mainUser" (resolved model name using
plezure#serializer:-rest:.typeForRoot("main.user"))
Error while processing route:
main.user Assertion Failed: The response from a findAll must be an
Array, not undefined Error: Assertion Failed: The response from a
findAll must be an Array, not undefined
My Json return:
{
"main.user": [
{ "id": "1", "name": "foo" },
{ "id": "2", "name": "bar" }
]
}
model.js
import DS from 'ember-data';
export default DS.Model.extend({
name: DS.attr('string')
});
My pod are right configured, everything is fine, all works if I change to the find to a non-pod model, like this (model exists at main/):
export default Ember.Route.extend({
model: function() {
return this.store.find('main');
}
});
But with 'main.user' ember is uncapable to deal with json return, using fixtures pod names works well, it's ony happens on json response.
Anyone have any ideia about this kind of issue?

Getting Type Error when using Ember Embedded Records Mixin with keyForAttribute

I've been banging my head against deserializing data with Ember. I feel like I've set it up right but I keep getting the same error. I'm trying to use the EmbeddedRecords Mixin, but it simply hasn't worked for me. Below is my debug data.
DEBUG: Ember : 1.6.1
DEBUG: Ember Data : 1.0.0-beta.7+canary.b45e23ba
DEBUG: Handlebars : 1.3.0
DEBUG: jQuery : 1.10.2
DEBUG: Model Fragments : 0.2.2
Here is a simple setup of what I've been doing. I have my model defined like this -
App.Subject = DS.Model.extend({
title: DS.attr('string'),
sections: DS.hasMany('section')
});
App.Section = DS.Model.extend({
title: DS.attr('string'),
subject: DS.belongsTo('subject')
});
App.SubjectSerializer = DS.RESTSerializer.extend(DS.EmbeddedRecordsMixin, {
attrs: {
sections: { embedded: 'always' }
}
});
and here is the format of the JSON payload I'm sending for a 'show'
{
"subject": {
"_id":"549987b098909eef0ac2d691",
"title":"Maths",
"sections":[{
"title":"Precalc",
"_id":"549987b098909eef0ac2d693"
}, {
"title":"Calc",
"_id":"549987b098909eef0ac2d692"
}],"__v":0
}
}
I get the errors in the console
Error while processing route: subjects.show undefined is not a function TypeError: undefined is not a function
at Ember.Mixin.create.extractSingle (http://localhost:3300/js/highered.js:2043:25)
at apply (http://localhost:3300/js/highered.js:20664:27)
at superWrapper [as extractSingle] (http://localhost:3300/js/highered.js:20240:15)
at Ember.Object.extend.extractFind (http://localhost:3300/js/highered.js:4007:21)
at Ember.Object.extend.extract (http://localhost:3300/js/highered.js:3892:37)
at http://localhost:3300/js/highered.js:11864:34
at invokeCallback (http://localhost:3300/js/highered.js:23228:19)
at publish (http://localhost:3300/js/highered.js:22898:9)
at publishFulfillment (http://localhost:3300/js/highered.js:23318:7)
at http://localhost:3300/js/highered.js:28736:9
highered.js:16581 undefined is not a function TypeError: undefined is not a function
at Ember.Mixin.create.extractSingle (http://localhost:3300/js/highered.js:2043:25)
at apply (http://localhost:3300/js/highered.js:20664:27)
at superWrapper [as extractSingle] (http://localhost:3300/js/highered.js:20240:15)
at Ember.Object.extend.extractFind (http://localhost:3300/js/highered.js:4007:21)
at Ember.Object.extend.extract (http://localhost:3300/js/highered.js:3892:37)
at http://localhost:3300/js/highered.js:11864:34
at invokeCallback (http://localhost:3300/js/highered.js:23228:19)
at publish (http://localhost:3300/js/highered.js:22898:9)
at publishFulfillment (http://localhost:3300/js/highered.js:23318:7)
at http://localhost:3300/js/highered.js:28736:9
Which as best I can tell is directly related to extractSingle at the this.keyForAttribute method
extractSingle: function(store, primaryType, payload, recordId, requestType) {
var root = this.keyForAttribute(primaryType.typeKey),
partial = payload[root];
updatePayloadWithEmbedded(store, this, primaryType, partial, payload);
return this._super(store, primaryType, payload, recordId, requestType);
},
although an interesting thing to note is that the error occurs at extractArray when I am using the subjects index route, which return the json above but with array brackets as well.
extractArray: function(store, type, payload) {
var root = this.keyForAttribute(type.typeKey),
partials = payload[pluralize(root)];
forEach(partials, function(partial) {
updatePayloadWithEmbedded(store, this, type, partial, payload);
}, this);
return this._super(store, type, payload);
}
Which makes me think that Ember Data is having trouble recognizing the format. This happens any time I define a serializer for a model, not just when I enable embedded records.
I'm hoping someone will be able to explain this. As a final note I've been using the Ember Data Model Fragments library as well, but I disabled that and still got this error so I don't think that is it.
The Embedded Records mixin doesn't work with the RESTSerializer before beta 9.
You can view the state of it here Ember-data embedded records current state?
You'll also want to be wary of updating ember or ember data without the other version in certain circumstances. Ember Data cannot read property 'async' of undefined