AngularJS: функция из сервиса не работает в директиве ng-infinite-scoll

Я хочу использовать ng-infinite-scroll (https://sroze.github.io/ngInfiniteScroll/). Но когда я хочу вызвать функцию из моей службы (внедренной в контроллер), ничего не происходит (эта функция не срабатывает). Когда я вызываю функцию не из службы, а из $scope контроллера - все работает нормально. Как вызвать функцию из внедренного сервиса в директиве бесконечной прокрутки?

Моя структура HTML:

<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>

Мой showPublicationsCtrl контроллер:

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

Мой publicationsFactory сервис:

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;
}]);

Если я создам какую-то функцию в своем контроллере, например $scope.myFunction, а затем в структуре HTML я назначу атрибут infinite-scroll для myFunction(), функция будет успешно выполнена. Итак, я думаю, что, возможно, есть некоторые ошибки в том, как я внедряю службу в контроллер. Но все остальное, кроме ng-inginite-scroll, работает по плану.


person Dmitrij Burlaj    schedule 21.03.2017    source источник


Ответы (2)


infinite-scroll привязан к $scope.publicationsFactory:

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

но publicationsFactory недоступен в вашей области, вы должны выставить его следующим образом:

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

    publicationsFactory.getPublications();
    $scope.publications = publicationsFactory.publications;
}]);

Как обновить $scope.publications последними публикациями, полученными с помощью Factory

Ваша фабрика может вернуть обещание, разрешенное с помощью последних публикаций, измените свой код следующим образом:

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;
}]);

Затем в вашем контроллере:

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

    publicationsFactory.getPublications()
    .then(function(results) {
        $scope.publications = results;
    });
}]);    
person Stephane Janicaud    schedule 21.03.2017
comment
Да, я думаю, это будет работать, но тогда, если у меня будут какие-то обновления в моем publicationsFactory.publications, они будут автоматически отображаться при просмотре? - person Dmitrij Burlaj; 21.03.2017
comment
Как видите, я динамически создаю список в своей html-структуре из массива publications. А также в другом месте на моей странице я создал форму, позволяющую пользователям добавлять новые элементы в массив publications, а также добавлять новые элементы в базу данных на сервере. Если я открою фабрику публикаций в своем контроллере, будет ли представление автоматически обновляться, когда пользователь добавляет новый элемент? - person Dmitrij Burlaj; 21.03.2017
comment
Нет, публикации $scope не могут автоматически обновляться без нового запроса к "/Publications :) - person Stephane Janicaud; 21.03.2017
comment
Но на стороне сервера после публикации нового комментария вы можете отправить новое событие WebSocket, содержащее новую публикацию, а затем добавить его на стороне клиента в $scope.publications в нужном месте в зависимости от даты публикации. - person Stephane Janicaud; 21.03.2017
comment
Для этого вы должны открыть канал WebSocket на стороне сервера и подписаться на него на стороне клиента. - person Stephane Janicaud; 21.03.2017
comment
Посмотрите, пожалуйста, на эту скрипту: jsfiddle.net/apft2rdq У меня есть эта функция для сбора всех данных, которые пользователь введите входные данные формы, а затем создайте объект, который будет затем: 1) Нажат на publicationsFactory.publications, чтобы отобразить его сразу при просмотре. 2) Сделайте запрос POST на сервер, чтобы добавить этот новый элемент в базу данных. Когда я выставлю фабрику публикаций, неужели я не смогу использовать эту функцию, как раньше, чтобы сразу изменить вид? - person Dmitrij Burlaj; 21.03.2017
comment
Если функция, привязанная к infinite-scroll, просто обновляет $scope.publications, то отправка в нее новой публикации после разрешения добавления обещания должна повлиять на DOM. Итак, да, представление должно автоматически обновляться - person Stephane Janicaud; 21.03.2017
comment
Если это не работает (но должно!), попробуйте обернуть код обратного вызова обещания успеха iside $scope.$apply(function() { for() ... }); или $timeout(function() { for() ... }, 0);, чтобы заставить angular обновить свою область видимости. - person Stephane Janicaud; 21.03.2017
comment
Нет, функция, привязанная к бесконечной прокрутке, обновляет не $scope.publications, а publicationsFactory.publications, массив в сервисе publicationsFactory. Как сделать, чтобы эта функция обновлялась напрямую $scope.publications в контроллере? - person Dmitrij Burlaj; 21.03.2017
comment
@DmitrijBurlaj поздравляю! Я обновил свой ответ, чтобы привести пример, объясняющий, как обновить $scope.publications последними публикациями, полученными с помощью Factory. Наслаждаться. - person Stephane Janicaud; 21.03.2017

Вы должны добавить эту строку в свой ctrl:

$scope.getPublications = publicationsFactory.getPublications;

А затем вызовите эту функцию ctrl из представления. Таким образом, вы привязываете ссылку на сервисную функцию к области действия контроллера, которая доступна вам в представлении.

Изменить: Другой вариант - привязать всю службу к свойству ctrl, как уже предложил кто-то другой.

person Community    schedule 21.03.2017
comment
Хорошо, а какой вариант лучше? - person Dmitrij Burlaj; 21.03.2017