Search code examples
angularjsangularjs-directiveangularjs-scopeangular-servicesnginfinitescroll

AngularJS: function from service don't work in ng-infinite-scoll directive


I want to use ng-infinite-scroll (https://sroze.github.io/ngInfiniteScroll/). But when I want to call function from my service (injected to controller) nothing happened (this function doesn't trigger). When I call function not from the service but from $scope of the controller - everything works fine. How to call function from the injected service in infinite-scroll directive?

My HTML structure:

<div class="col-xs-12 publications-container" ng-controller="showPublicationsCtrl">
    <h3 class="publ-heading">Proposed Publications</h3>
    <ul class="list-group" infinite-scroll="publicationsFactory.getPublications()" infinite-scroll-disabled='publicationsFactory.busyLoadingData'>
      <li ng-repeat="publication in publications" class="list-unstyled list-group-item" ng-cloak>
        <p class="text-warning">Author: <i>{{publication.author}},   {{publication.timestamp | date: 'MMM. d, y'}}</i></p>
        <p ng-text-truncate="publication.text" ng-tt-words-threshold="3">{{publication.text}}</p>
        <p class="text-muted">Channels: <i>{{publication.channels.join(", ")}}</i></p>
      </li>
    </ul>
  </div>

My showPublicationsCtrl controller:

twitterApiApp.controller("showPublicationsCtrl", ['publicationsFactory', '$scope', function (publicationsFactory, $scope) {
  publicationsFactory.getPublications();
  $scope.publications = publicationsFactory.publications;
}]);

My publicationsFactory service:

angular.module('twitterApiApp').factory('publicationsFactory', ['$http', function($http) {
  var publicationsFact = {};
  publicationsFact.publications = [];
  publicationsFact.busyLoadingData = false;

  publicationsFact.getId = function() {
publicationsFact.id = publicationsFact.publications.length > 0 ?
                      publicationsFact.publications[publicationsFact.publications.length-1]['id'] : 0;
  };

  publicationsFact.getPublications = function () {
    console.log("Triggered");
    if (publicationsFact.busyLoadingData) return;
    publicationsFact.busyLoadingData = true;
    publicationsFact.getId();
    $http.get("/Publications?id_gte=" + publicationsFact.id + "&_limit=2").then(function(response) {
      for (var i = 0; i < response.data.length; i++) {
        publicationsFact.publications.push(response.data[i]);
      };
    });
    publicationsFact.busyLoadingData = false;
  };
  return publicationsFact;
}]);

If I create some function in my controller, for example $scope.myFunction and then in HTML structute I assign infinite-scroll attribute to myFunction() the function will be successfully executed. So, I think maybe there are some mistakes in the way I inject the service in the controller. But everything else except ng-inginite-scroll works as planned.


Solution

  • infinite-scroll is binded to $scope.publicationsFactory :

    <ul class="list-group" infinite-scroll="publicationsFactory.getPublications()" infinite-scroll-disabled='publicationsFactory.busyLoadingData'>
    

    but publicationsFactory is not available in your scope, you must expose it like this :

    twitterApiApp.controller("showPublicationsCtrl", ['publicationsFactory',  '$scope', function (publicationsFactory, $scope) {
        // Expose publication factory
        $scope.publicationsFactory = publicationsFactory;
    
        publicationsFactory.getPublications();
        $scope.publications = publicationsFactory.publications;
    }]);
    

    How to update $scope.publications with latest publications retrieved using Factory

    Your factory can return a promise resolved with the latest publications, change your code like this :

    angular.module('twitterApiApp').factory('publicationsFactory', ['$http', '$q', function($http, $q) {
        var publicationsFact = {};
        publicationsFact.publications = [];
        publicationsFact.busyLoadingData = false;
    
    
        publicationsFact.getId = function() {
            publicationsFact.id = publicationsFact.publications.length > 0 ?
                publicationsFact.publications[publicationsFact.publications.length - 1]['id'] : 0;
        };
    
        /**
         * Get latest publications
         * @returns {object} A promise
         */
        publicationsFact.getPublications = function() {
            var deferred = $q.defer();
    
            console.log("Triggered");
            if (publicationsFact.busyLoadingData) return;
            publicationsFact.busyLoadingData = true;
            publicationsFact.getId();
            $http.get("/Publications?id_gte=" + publicationsFact.id + "&_limit=2").then(function(response) {
                for (var i = 0; i < response.data.length; i++) {
                    publicationsFact.publications.push(response.data[i]);
                };
                // Resolve promise with updates publications list
                deferred.resolve(publicationsFact.publications);
            }, function(error) {
                // Reject promise with error message
                deferred.reject(error.message);
            });
            publicationsFact.busyLoadingData = false;
    
            // Return promise
            return deferred.promise;
    
        };
        return publicationsFact;
    }]);
    

    Then, in your controller :

    twitterApiApp.controller("showPublicationsCtrl", ['publicationsFactory',  '$scope', function (publicationsFactory, $scope) {
        // Expose publication factory
        $scope.publicationsFactory = publicationsFactory;
    
        publicationsFactory.getPublications()
        .then(function(results) {
            $scope.publications = results;
        });
    }]);