0

I have the following code.

controller.js

angular.module('LiveAPP.main',['LiveAPP.factory'])
.controller('mainCtrl', ['$scope','$http', '$location','dataFactory',mainCtrl])

.directive('ratehome',function(){
  return {
    restrict:"E",
    template: "<div id='rateYo'></div>",
    link: function(scope, ele, attrs){
      console.log("NEW",scope.recentArtist)
    }
  }
})


function mainCtrl($scope,$http,$location,dataFactory){

  $scope.getRecentArtists = function(){
     return $http({
        method: 'GET',
        url: '/artistsearch',
        params: {getArtist: "all"}
    }).then(function(recent){
      $scope.recentArtist = recent.data

    })
  };

  $scope.getRecentArtists();

  $scope.recentArtist = ""

  $scope.$watch('recentArtist',function(newValue,oldValue){
    $scope.recentArtist = newValue

  })

}    

test.html

<ratehome></ratehome>
<ratehome></ratehome>
<ratehome></ratehome>

What happens here is upon instantiation of my controller(routing is set up correctly) there is a $http GET request that responds with data that I need that gets assigned to $scope.recentArtist. I want this data to be accessible in my link function, but it's not. I have a feeling that my directive is compiling before this request is sent. Is there any way around this? What is odd to me is that when I console.log(scope) and check in Chrome Developer Tools my data is there. Yet when I console.log(scope.recentArtist) its empty similar to its state in the controller. I was thinking I could maybe make the $http.get in my directive, but that seems a little awkward to me.

I have been having trouble with this problem for a few days, hopefully somebody can help me out.

3 Answers 3

1

If you're using angular ui-router you could also use resolve. With resolve you can do the $http before the controller starts.

You can use resolve to provide your controller with content or data that is custom to the state. resolve is an optional map of dependencies which should be injected into the controller.

If any of these dependencies are promises, they will be resolved and converted to a value before the controller is instantiated and the $stateChangeSuccess event is fired.

from the docs.

Please have a look at the demo below or this jsfiddle.

angular.module('demoApp', ['ui.router'])
    .config(function ($urlRouterProvider, $stateProvider) {
    $urlRouterProvider.otherwise('/');
    $stateProvider.state('home', {
        url: '/',
        template: '<ratehome></ratehome><ratehome></ratehome><ratehome></ratehome>',
        controller: 'mainCtrl',
        resolve: {
            artists: function (artistsService) {
                console.log('Resolve');
                return artistsService.get(); //'/artistsearch',//artistsService.get();
            }
        }
    });
})
    .controller('mainCtrl', ['$scope', '$http', '$location', 'artists', MainCtrl])

    .directive('ratehome', function () {
    return {
        restrict: "E",
        template: '<div id="rateYo"><ul><li ng-repeat="artist in recentArtist">{{artist}}</li></ul></div>',
        link: function (scope, elem, attrs) {
            console.log("NEW", scope.recentArtist);
        }
    }
})

    .factory('artistsService', function ($http) {
    return {
        get: function () {
            console.log('getting');
            return $http({
                method: 'GET',
                url: 'http://crossorigin.me/http://www.mocky.io/v2/558b30615f3dcbc414067170', //'/artistsearch',
                //params: {getArtist: "all"}
            }).then(function (recent) {
                //console.log(recent);
                return recent.data;
            });
        }
    };
});

function MainCtrl($scope, $http, $location, artists) {

    $scope.recentArtist = artists;
    console.log('ctrl', artists);    

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.1/angular.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.2.15/angular-ui-router.js"></script>
<div ng-app="demoApp">
    <div ui-view=""></div>
</div>

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

Comments

1

AS your directive is not using isolated scope, that does mean you can directly access your controller scope inside your directive. I'd suggest you to to put that $watch inside directive link instead of your controller. That would intimate you that the ajax has been completed and data got changed & you get those changed value inside watcher function.

Code

.directive('ratehome',function(){
  return {
    restrict:"E",
    template: "<div id='rateYo'></div>",
    link: function(scope, ele, attrs){
      $scope.$watch('recentArtist',function(newValue,oldValue){
        console.log("NEW",newValue)
      });
    }
  }
})

Comments

0

Your link function is running before the $http response comes back as you suspect. You can wait for it by using $broadcast and $on:

angular.module('LiveAPP.main',['LiveAPP.factory'])
    .controller('mainCtrl', ['$scope','$http', '$location','$rootScope','dataFactory',mainCtrl])
    .directive('ratehome',function(){
        return {
            restrict:"E",
            template: "<div id='rateYo'></div>",
            link: function(scope, ele, attrs){
                scope.$on('artistLoaded', function(){
                    console.log("NEW",scope.recentArtist);
                });
            }
        };
    });


function mainCtrl($scope,$http,$location,$rootScope,dataFactory){
    $scope.getRecentArtists = function(){
        return $http({
            method: 'GET',
            url: '/artistsearch',
            params: {getArtist: "all"}
        }).then(function(recent){
            $scope.recentArtist = recent.data
            $rootScope.$broadcast('artistLoaded');
        });
    };

    $scope.getRecentArtists();
    $scope.recentArtist = "";

    $scope.$watch('recentArtist',function(newValue,oldValue){
        $scope.recentArtist = newValue
    });
}  

This way the code will not run until the response has been returned and set

2 Comments

This is a pretty subjective question, but is it good practice to use broadcast to a directive? I was under the impression that $broadcast was mostly a way to communicate across controllers?
I haven't read either way whether it is good or bad. In my opinion its slightly cleaner than a $watch if you only need to update a few times or once. Since a $watch will run every $digest cycle and the $on will only run specifically when you tell it to run. But like I said I haven't heard either way so I could be subjectively or objectively wrong!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.