0

I have an Ionic app that allows users to auth with Instagram, Facebook, and Twitter. You can link other accounts that aren't your primary login as well. The problem I'm running into is making calls to the Instagram API in my controller so I can display the profile image for the associated Instagram account. Facebook and Twitter offer a designated URL to do this so I don't need to make a GET request and I don't run into this issue.

I am using Auth0 and I am broadcasting changes to the Auth0 user profile to make sure auth credentials are current throughout the app.

.service('auth', function ($rootScope) {
      var self = this;
      self.profile = 'OldProfile';

      self.setProfile = function (newVal) {
        self.profile = newVal;
        $rootScope.$broadcast('newProfile', newVal);
      }
});

and in my controller:

   $scope.profile = auth.profile;

   $rootScope.$on('newProfile', function (e, data) {
         $scope.profile = data;
        });

   $scope.changeProfile = function () {
            auth.setProfile('NewProfile');
          }

The problem I'm encountering is I need to grab user credentials from the Auth0 profile to construct the Instagram $http.get request for that particular user, then get the URL for the user profile image.

  $scope.facebook = [];
  $scope.twitter = [];
  $scope.instagram = [];

  $scope.facebookCheck = function() {
     for (i = 0; i < $scope.profile.identities.length; i++) {
        if (angular.equals($scope.profile.identities[i].provider, "facebook")) {
            if ( i == 0) {
                     $scope.facebook.name = $scope.profile.name;
                     $scope.facebook.photo = "http://graph.facebook.com/" + $scope.profile.user_id + "/picture?type=large";
                 } else {
                     $scope.facebook.name = $scope.profile.identities[i].profileData.name;
                     $scope.facebook.photo = "http://graph.facebook.com/" + $scope.profile.identities[i].user_id + "/picture?type=large";
                 }
                     return true;
        }
    }

    return false;
};

   $scope.twitterCheck = function() {
     for (i = 0; i < $scope.profile.identities.length; i++) {
        if (angular.equals($scope.profile.identities[i].provider, "twitter")) {
            if ( i == 0) {
                     $scope.twitter.name = "@" + $scope.profile.screen_name;
                     $scope.twitter.photo = "https://twitter.com/" + $scope.profile.screen_name + "/profile_image?size=normal";
                 } else {
                     $scope.twitter.name = "@" + $scope.profile.identities[i].profileData.screen_name;
                     $scope.twitter.photo = "https://twitter.com/" + $scope.profile.identities[i].profileData.screen_name + "/profile_image?size=normal";
                 }
                     return true;
        }
    }

    return false;
};
$scope.instagramCheck = function() {
     for (i = 0; i < $scope.profile.identities.length; i++) {
        if (angular.equals($scope.profile.identities[i].provider, "instagram")) {

            if ( i == 0) {

                     $scope.instagram.name = "@" + $scope.profile.nickname;

                     $http.jsonp("https://api.instagram.com/v1/users/"+ $scope.profile.user_id +"/?access_token="+ $scope.profile.access_token).success(
                     function(data, status) {

                       $scope.instagram.photo = data.data.profile_picture;
                      }
                  );

                 } else {

                     $scope.instagram.name = "@" + $scope.profile.identities[i].profileData.nickname;

                     $http.jsonp("https://api.instagram.com/v1/users/"+ $scope.profile.identities[i].user_id +"/?access_token="+ $scope.profile.identities[i].access_token).success(
                     function(data, status) {

                       $scope.instagram.photo = data.data.profile_picture;
                     }
                  );
                 }

                     return true;
        }
    }

    return false;
};

The if-else is due to the way Auth0 stores user data. If the user first logs in with the provider (Instagram in this case), it will be identity 0 and the JSON tree is a little skewed as such. I know I can't make the $http.get request in this manner, but I'm not sure how to get around doing it. I'm new to Angular and I'm having trouble grasping how to get around this problem. I have looked through tons of questions and blog posts about similar problems, but can't figure it out. Here is the view in question as well,

<ion-view title="Account">
  <ion-content class="has-header padding">
    <div class="list item-shadow">
        <ion-item  class="item item-light item-avatar" ng-if="facebookCheck() == true">
            <img ng-src={{facebook.photo}}>
            <h2><i class="icon icon-color-fb ion-social-facebook"></i>&nbsp; {{facebook.name}}</h2>
            <p>Your Facebook account is linked</p>
        </ion-item >
        <ion-item  class="item item-light item-avatar" ng-if="twitterCheck() == true">
            <img ng-src={{twitter.photo}}>
            <h2><i class="icon icon-color-twitter ion-social-twitter"></i>&nbsp; {{twitter.name}}</h2>
            <p>Your Twitter account is linked</p>
        </ion-item >
        <ion-item class="item item-light item-avatar" ng-if="instagramCheck() == true">
            <img ng-src={{instagram.photo}}>
            <h2><i class="icon icon-color-insta ion-social-instagram"></i>&nbsp; {{instagram.name}}</h2>
            <p>Your Instagram account is linked</p>
        </ion-item>
    </div>
    <button class="button button-block button-positive icon-left icon ion-social-facebook" ng-if="facebookCheck() == false" ng-click="linkFacebook()"> Add Facebook Account</button>
    <button class="button button-block button-calm icon-left icon ion-social-twitter" ng-if="twitterCheck() == false" ng-click="linkTwitter()"> Add Twitter Account</button>
    <button class="button button-block button-dark icon-left icon ion-social-instagram" ng-if="instagramCheck() == false" ng-click="linkInstagram()"> Add Instagram Account</button>
    <br>  
    <button class="button button-assertive button-block" ng-click="logout()">Logout</button>
  </ion-content>
</ion-view>

Any help/guidance is appreciated.

4
  • From what I can tell, there are things going on that we can't see that's causing the problem. Each one of those ng-ifs with a function need to run at every digest cycle. If they update some value that kicks off another digest cycle then you're in an infinite loop of digests. This may be the problem but I don't know. Can you include the contents of those methods? What kicks off setProfile ? Commented Sep 2, 2015 at 15:20
  • Sure, I added them. I should have explained further that everything else works flawlessly when I leave out the $http.get for the Instagram API. I had this setup before to grab the image URLs directly from Auth0, but their system does not update the data until the auth token expires which does not happen just from changing a profile photo. Changing the profile photo resulted in a 404 because the old profile image that was linked to no longer existed, so I altered my approach in response. That's when I ran into this trouble. Commented Sep 2, 2015 at 15:23
  • Try doing your checks someplace else and not at runtime. Not only is this a lot of http calls but I think this may be causing the infinite digest. Commented Sep 2, 2015 at 15:25
  • I'm not sure what you mean. The only http calls are in the instagramCheck and I'm not sure where else I can do this. When I was pulling the profile image directly from the auth object from auth0 it performed beautifully, it just 404'd the image if a user changed their profile picture after logging in. Can you explain a little further what you're suggesting? Commented Sep 2, 2015 at 15:32

1 Answer 1

1

In you html you are doing checks at runtime-

ng-if="facebookCheck() === true"

The issue probably is that the facebook check is also updating the scope.

$scope.facebook.name = $scope.profile.name;

This should kick off another digest to update the view with the new values. Once that digest kicks off, the checks are done again, etc etc.

When the profile is loaded, set $scope.facebook.name there. Additionally, have another set a vars like, isFacebook, isInstagram, etc. And update your view to this- ng-if="isFacebook".

The short and skinny: You're kicking off a digest with your check everytime a digest occurs. This is your infinite loop.

Sign up to request clarification or add additional context in comments.

3 Comments

Why is it fine when I'm not using $http.get though? When I set $scope.instagram.picture from the value in the profile object this problem doesn't occur at all. I'm going to try implementing what you're suggesting, but I'm trying to wrap my mind around why the $http.get is exacerbating this problem.
$http.get kicks off a digest (or apply, i don't remember). Either way, you shouldn't have your read-only methods doing write operations.
I solved this problem by following your advice. I moved the socialprovider.name = profile.name (and similar) bits outside of the check methods. It should be noted though, for anyone viewing this, that I was also not making the proper call to the Instagram API. I needed to request the response be wrapped in the proper callback which is angular.callbacks._0 . This was throwing an error. Thanks for your help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.