0

I'm fairly new to Angular, and I'm trying to figure out why scope variables isn't updating after they've been set.

I'm calling a Node API returing json objects containing my data. Everything seems to work fine except setting $scope.profile to the data returned from the API.

Setup:

app.js

(function() {
  var app = angular.module("gamedin", []);


  app.controller('profileController', function($scope, $http, $timeout) {
    $scope.profile = {};

    $scope.getProfile = function() {
      var vanityUrl = $scope.text.substr($scope.text.lastIndexOf('/') + 1);

      $http.get('/steamid/' + vanityUrl)
      .then(function(data) {
        $http.get('/profile/' + data.data.response.steamid)
        .then(function(data) {
          console.log(data.data.response.players[0]); // Correct data
          $scope.profile = data.data.response.players[0]; // View isn't updated
        })
      })

      // Reset the input text
      $scope.text = "";
    }
  });

  ...

  app.directive('giHeader', function() {
    return {
      restrict: 'E',
      templateUrl: 'components/header/template.html'
    };
  })

  app.directive('giProfile', function() {
    return {
      restrict: 'E',
      templateUrl: 'components/profile/template.html'
    }
  })

})();

components/header/template.html

<header>
  <div class="header-content" ng-controller="profileController">
    <div class="col-md-3"></div>

    <div class="col-md-6">
      <div class="header-content-inner">
        <input ng-model="text" ng-keyup="$event.keyCode == 13 && getProfile()" class="form-control" type="text" placeholder="Enter Steam URL">
      </div>
      <p>e.g., http://steamcommunity.com/id/verydankprofilelink</p>
    </div>

    <div class="col-md-3"></div>
  </div>
</header>

components/profile/template.html

<div class="container">
  <div ng-controller="profileController">
    <h3> 
      <strong>Username: {{ profile.personaname }}</strong>
    </h3>
    <p> SteamID: {{ profile.steamid }}</p>
  </div>
</div>

index.html

<!doctype html>
<html ng-app="gamedin">
<head>
  ...
</head>

<body>

  ...

  <gi-header></gi-header>

  <gi-profile></gi-profile>

  ...

</body>
</html>

I've tried wrapping it in $scope.$apply, like this

$scope.$apply(function () {
  $scope.profile = data.data.response.players[0];
});

... which resulted in Error: [$rootScope:inprog]

Then I tried

$timeout(function () {
  $scope.profile = data.data.response.players[0];
}, 0);

and

$scope.$evalAsync(function() { 
  $scope.profile = data.data.response.players[0]; 
});

... and although no errors were thrown, the view still wasn't updated.

I realize that I'm probably not understanding some aspects of angular correctly, so please enlighten me!

4
  • Which section do you expect to be updated? I don't see any reference to profile variable in the HTMLs. Are you talking about the directives? Commented Apr 10, 2016 at 13:48
  • Isn't there an issue with the property name "personaname"? Seems weird. Commented Apr 10, 2016 at 13:55
  • @OmriAharon: I want to update components/profile/template.html (that accesses the profile variable) when $scope.profile is updated. Commented Apr 10, 2016 at 14:09
  • Have you tried my answer? Commented Apr 10, 2016 at 14:13

2 Answers 2

1

The problem is that you have 2 instances of profileController, one in each directive template. They should both share the same instance, because what happens now is that one instance updates profile variable on its scope, and the other is not aware. I.e., the profileController instance of header template is executing the call, and you expect to see the change on the profile template.

You need a restructure. I suggest use the controller in the page that uses the directive, and share the profile object in both directives:

  <gi-header profile="profile"></gi-header>

  <gi-profile profile="profile"></gi-profile>

And in each directive:

return {
  restrict: 'E',
  scope: {
     profile: '='
  },
  templateUrl: 'components/header/template.html'
};

And on a more general note - if you want to use a controller in a directive, you should probably use the directive's "controller" property.

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

1 Comment

@topic No problem :) Please try to mark the answers that solved your problem as "solved" (the check mark) so others will know you've found your answer.
0

Try using this method instead:

$http.get('/steamid/' + vanityUrl)
  .then(function(data) {
    return $http.get('/profile/' + data.data.response.steamid).then(function(data) { 
      return data;
    });
  })
  .then(function(data) {
     $scope.profile = data.data.response.players[0]; // View isn't updated
  })

Where you use two resolves instead of one and then update the scope from the second resolve.

8 Comments

Thanks, but it still doesn't work. I'm returning from a callback, that's why I chained it.
If you console log the data in the second resolve what do you get?
Then it should work as you expect, what if you wrap the $scope.profile = data.data.response.players[0]; in a timeout?
Did you try it with my solution too or with the one you previously had?
Yeah, still nothing I'm afraid.
|

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.