2

I'm going to get some data from server using $http and JSON response. $http.get() are called after route change. But template are changed before data is downloaded. My goal is:

  • User press a hyperlink in menu, that changes a route,
  • Shows Loading Spinner (DOM Element is in another controller which is on page everytime)
  • Initializing $scope.init() (via ng-init="init()") in controller which is in my new template, this also initializing get data from server
  • Data are downloaded, now I can hide spinner and change visible template

How can I do this? My App looks for example:

Javascript:

var myApp = angular.module('myApp', []);

myApp.controller('MyCtrl', function($scope, $http) {
    $scope.init = function() {
       $http({method: 'GET', url: 'http://ip.jsontest.com/'}).success(function(data) {
           console.log(data);
               $scope.ip = data.ip;
           });
    }
});

myApp.config(function($routeProvider) {

    $routeProvider.when('/link', {
        controller: 'MyCtrl',
        templateUrl: 'embeded.tpl.html'
    });
});

HTML:

<script type="text/ng-template" id="embeded.tpl.html">
    <div ng-controller="MyCtrl" ng-init="init()">
    Your IP Address is: {{ip}}
    </div>
</script>

<div>

    <ul>
        <li><a href="#/link">change route</a></li>
    </ul>

    <div ng-view></div>
</div>
Siper
  • 1,175
  • 1
  • 14
  • 39
  • Have you looked at this thread? http://stackoverflow.com/questions/17144180/angularjs-loading-screen-on-ajax-request – codingjoe Dec 21 '13 at 15:47
  • Yes, but that's not what I need. – Siper Dec 21 '13 at 15:52
  • Why don't you simply send the http request when the controller is constructed, and have a view like `
    ...
    ` (i.e. it doesn't show anything until the data is received)?
    – JB Nizet Dec 21 '13 at 16:01
  • I would rather change the page structure. I don't think ng-view is the best solution for you. Maybe you could work with with ngInclude to change just what you need to update in your page. Have the url change a significant role in your application logic? Do you use some url parameter? – pasine Dec 21 '13 at 17:32

2 Answers2

6

You need to resolve data before routing happens, thus, move your $http to config section.

This is good tutorial for that, http://www.thinkster.io/pick/6cmY50Dsyf/angularjs-resolve-conventions

This is config part.

 $routeProvider.when('/link', {
    controller: 'MyCtrl',
    templateUrl: 'embeded.tpl.html',
    resolve: {
      data: function ($q, $http) {
        var deferred = $q.defer();
        $http({method: 'GET', url: 'http://ip.jsontest.com/'}).then(function(data) {
          deferred.resolve(data);
        });
        return deferred.promise;
      }
    }
 }

and this is controller part

//`data` is injected from routeProvider after resolved
myApp.controller('MyCtrl', function($scope, $http, data) { 
  $scope.ip = data.ip
});

I think promise in AngularJS is very important concept for any async. processing. You need to use this technique every time you have callback.

Marius Schulz
  • 15,976
  • 12
  • 63
  • 97
allenhwkim
  • 27,270
  • 18
  • 89
  • 122
  • That's it! But I've a just one question. Is it possible to use ngResource in resolve object? – Siper Dec 22 '13 at 16:03
  • The question is 'Does ngResource returns promise?'. if so `return MyResource.get({id: $route.current.params.id});`, if not `return MyResource.get({id: $route.current.params.id}).promise;`. – allenhwkim Dec 22 '13 at 16:27
  • My question is, does ngResource can be used in resolve convention :) Just instead `$http.get()` I want use `MyRes.get()` – Siper Dec 22 '13 at 16:30
  • as it said here, http://stackoverflow.com/a/16759067/454252, `return MyRes.get().$promise;` – allenhwkim Dec 22 '13 at 17:26
  • Yes, but I don't need define my resource somewhere (just like in controller)? It looks: `Controllers.controller('dashboardCtrl', ['$scope', 'DashboardRes', function($scope, Res) {...}]);`. My Resource looks that: `app.factory('DashboardRes', ['$resource', function($resource) {...});`, without create new variable. – Siper Dec 22 '13 at 18:19
1

I will not do it all for you, however I will point you in the right direction.

First you need the ngRoute module.

var myApp = angular.module('myApp', ['ngRoute']);

And the JS file:

<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.5/angular-route.js"></script>

Now you routes will be working and you do not need to call a special init function in your controller since they get instanciated on every route change when used with ng-view.

For the spinner, you could add some interceptors to all ajax requests using the $httpProvider. Inside the interceptors you could emit some events on the $rootScope and listen to then in a specialed custom attribute directive e.g. spinner where the magic would occur ;)

plalx
  • 42,889
  • 6
  • 74
  • 90