0

I'm experiencing a very strange issue, I retrieve the users profile from Firebase inside this profile is an Photo Object basically an array of photos the user has uploaded.

My get Profile method:

getUserProfile(): Observable<User> {

    var userId = null;

    var auth = this.af.auth.subscribe(user => {
        userId = user.uid;
    });

    auth.unsubscribe();

    return this.af.database.object('/users/' + userId)
        .map(pro => new User(
            pro.$key,
            pro['email'],
            pro['gender'],
            pro['last_name'],
            pro['first_name'],
            pro['display_name'],
            pro['photos'],
            pro['hobbies']))
}

My user class is as follows:

export class User {
    public constructor(
        public userId: string,
        public email: string,
        public gender?: string,
        public last_name?: string,
        public first_name?: string,
        public display_name?: string,
        public photos: Photo[] = [],
        public hobbies: Hobbies[] = [],
    ) { }
}

Inside my component I call the getUserProfile as so:

this.userSubscription = this.profileService.getUserProfile().subscribe(profile => {
   console.log(profile.photo);
});

When I write console.log(profile.photos); I see the following:

enter image description here

Yet when I try to loop through this collection by doing the following:

for(var i = 0; i < profile.photos.length; i++){
   console.log('here');
}

Nothing is written to the console, even when I do the following:

console.log(profile.photos.length); it says undefined....

I'm not entirely sure what is going wrong, can anyone spot the reason into why I can't loop through the photo array and access the properties?

Code Ratchet
  • 5,758
  • 18
  • 77
  • 141
  • did you put the loop in the subscribe block? – Pengyy Mar 24 '17 at 03:27
  • 1
    You can't access an object's length like that. see: http://stackoverflow.com/questions/5223/length-of-a-javascript-object – But those new buttons though.. Mar 24 '17 at 04:06
  • Possible duplicate of [How do I loop through or enumerate a JavaScript object?](http://stackoverflow.com/questions/684672/how-do-i-loop-through-or-enumerate-a-javascript-object) – But those new buttons though.. Mar 24 '17 at 04:08
  • Tried object.keys() however I still can't access the cloud_Id – Code Ratchet Mar 24 '17 at 04:19
  • In your case, based on your `console.log(profile.photos)` image, this object seems to be a dictionary and not an array. Try to use the following: `for(let key in profile.photos) { console.log(profile.photos[key].cloud_id) }` to see what will happening – Diullei Mar 24 '17 at 04:42
  • @Diullei I get the error: Property 'cloud_id' does not exist on type 'Photo'. any – Code Ratchet Mar 24 '17 at 04:45
  • @Diullei changed `profile` to `(profile:any)` in the response didn't fix the issue either. – Code Ratchet Mar 24 '17 at 04:46
  • OK, but this snippet: `for(let key in profile.photos) { console.log(profile.photos[key].cloud_id) }` works? – Diullei Mar 24 '17 at 04:48
  • No, that doesn't work either, i.e Property 'cloud_id' does not exist on type 'Photo'. any – Code Ratchet Mar 24 '17 at 04:51
  • ok, but take a look. You are saying that when you do: `console.log(profile.photos)` you have an object with a field per photo (see your image above). So `profile.photos` is not an array, its an object like a dictionary. – Diullei Mar 24 '17 at 04:55
  • So, I think you need to type the `photos` property as something like: `public photos: {[index: string]:Photo }`. Since it's not an array, you will not have a `length` property. – Diullei Mar 24 '17 at 04:57
  • @Diullei it needs to remain as an array as it's referenced else where within the application, i'm trying to find the syntax to loop the dictionary returned from firebase and push into the photos array – Code Ratchet Mar 24 '17 at 05:07
  • please, see my answer. I think you can use this code to build your array. – Diullei Mar 24 '17 at 05:16

3 Answers3

1

The profile.photos is an object and not an array. Try to change the photos member on you interface to:

public photos: {[index: string]: Photo} = {}

So, to iterate this object you can do:

for(let key in profile.photos) { 
    let photo = profile.photos[key];
    //... 
}

UPDATE

If you want to see other options to get all property values from a javascript Object see this: How to get all properties values of a Javascript Object (without knowing the keys)?

Community
  • 1
  • 1
Diullei
  • 11,420
  • 2
  • 27
  • 31
0

for syntax is breaking your code.Try this.

this.userSubscription = this.profileService.getUserProfile().subscribe(profile => {
console.log(profile.photo);
  for (let entry of profile.photo) {
       console.log(entry); 
  }
});

Reference : https://www.typescriptlang.org/docs/handbook/iterators-and-generators.html

Vivek
  • 1,375
  • 2
  • 15
  • 24
0

All you need is something like this, give it a try

service.ts

import 'rxjs/add/operator/mergeMap';

import {User} from './user';

export default class Service {
  getUserProfile(): Observable<User> {
    return this.af.auth.flatMap(({ id }) =>
      this.af.database.object('/users/' + id)
    );
  }
}

component.ts

import Service from './service';

export class Component {
  constructor(readonly service: Service) { }

  ngOnInit() {
    this.service.getUserProfile().subscribe(({ photos = [] }) => {
      photos.forEach(console.log);
    });
  }
}

user.ts

export interface User {
  userId: string,
  email: string,
  gender?: string,
  last_name?: string,
  first_name?: string,
  display_name?: string,
  photos: Photo[],
  hobbies: Hobbies[];
}

No manual deserialization lining up keyed values by name to shove them into a meaningless User class, just use an interface. No mutable security variables. No subscriptions to worry about, for the time being. Just get the basic problem right.

Aluan Haddad
  • 29,886
  • 8
  • 72
  • 84
  • although this is sound advice in terms of how to setup his services, it doesn't really answer his actual question - his photos isn't an array, it's an object where each photo is a different key. – snorkpete Mar 24 '17 at 08:49