尝试在AngularJS工厂中返回局部变量时,如何避免使用函数表达式?

时间:2015-01-08 05:35:04

标签: javascript angularjs

我如何回归"故事"发出" vm.stories = storyDataAsFactory.stories"与我现在所做的相比,这是" vm.stories = storyDataAsFactory.stories()" ?我没有成功地尝试过每一种组合。此外,我能够在没有括号的情况下调用storyDataAsFactory.getStories,这基于我如何配置它是有意义的,但是当我创建一个返回self.stories的函数时它不起作用。

以下代码按指定的方式工作 -

storyDataAsFactory.$inject = ['$http', '$q'];

angular.module('ccsApp').factory('storyDataAsFactory', storyDataAsFactory);

function storyDataAsFactory($http, $q) {
    var self = this;
    var stories = [];

    function getStories(url) {
        url = url || '';

        var deferred = $q.defer();

        $http({method: 'GET', url: url})
            .success(function (data, status, headers, config) {
                self.stories = data;

                deferred.resolve(data);
            })
            .error(function (data, status, headers, config) {
                deferred.reject(status);
            });

        return deferred.promise;
    }

    function listStories() {
        return self.stories;
    }

    return {
        stories: listStories,

        getStories: getStories('stories.json')
    };
}

更新:

我还有问题。这是我的确切代码,我根据社区进行了更改 -

storyDataAsFactory.$inject = ['$http', '$q'];

angular.module('ccsApp').factory('storyDataAsFactory', storyDataAsFactory);

function storyDataAsFactory($http, $q) {
    var stories = [];

    function getStories(url) {
        url = url || '';

        if (url !== '') {
            var deferred = $q.defer();

            //determine if ajax call already occurred;
            //if so, data exists in cache as local var
            if (stories.length !== 0) {
                deferred.resolve();
                return deferred.promise;
            }

            $http({method:'GET', url:url})
                .success(function (data, status, headers, config) {
                    stories = data;

                    deferred.resolve();
                })
                .error(function (data, status, headers, config) {
                    deferred.reject(status);
                });

            return deferred.promise;
        } else {
            alert('URL was empty.');
        }
    }

    return {
        stories: stories,

        getStories: function(url) {
            getStories(url);
        }
    };
}

storyDataAsFactory.stories不会返回任何内容。请记住,我接着已经解决了适当的解决方案,所以这不是异步。问题。我只是没有得到这个!我已经好几个小时没有成功了。

2 个答案:

答案 0 :(得分:0)

我认为你对Angular服务和工厂概念感到困惑:

让我们看下面的话:

Angular服务:

module.service( 'serviceName', function );
Result: When declaring serviceName as an injectable argument you will be provided
        with the instance of a function passed to module.service.

Angular工厂

module.factory( 'factoryName', function );
Result: When declaring factoryName as an injectable argument you will be provided
        the value that is returned by invoking the function reference passed to
        module.factory. So if you want to access the methods of that factory then
        they should be there along with returned value.

您给定代码的Angular服务版本将是:

schoolCtrl.service('storyDataAsService', storyDataAsService);

function storyDataAsService($http, $q) {
    var self = this;
    var stories = [];

    this.getStories = function(url) {
        url = url || '';

        var deferred = $q.defer();

        $http({method: 'GET', url: url})
            .success(function (data, status, headers, config) {
                self.stories = data;

                deferred.resolve(data);
            })
            .error(function (data, status, headers, config) {
                deferred.reject(status);
            });

        return deferred.promise;
    };
    this.stories = function(){
        // @TODO return value
    }
}

Angular的工厂版本:

storyDataAsFactory.$inject = ['$http', '$q'];

angular.module('ccsApp').factory('storyDataAsFactory', storyDataAsFactory);

function storyDataAsFactory($http, $q) {
    var self = this;
    var stories = [];

    function getStories(url) {
        url = url || '';

        var deferred = $q.defer();

        $http({method: 'GET', url: url})
            .success(function (data, status, headers, config) {
                self.stories = data;

                deferred.resolve(data);
            })
            .error(function (data, status, headers, config) {
                deferred.reject(status);
            });

        return deferred.promise;
    }

    return {
        stories: function() {
            // @TODO return value
        },

        getStories: getStories
    };
}

答案 1 :(得分:0)

在您的情况下,self是您工厂storyDataAsFactoryProvider的提供者。但是您需要使用局部变量stroies,而不是提供者对象字段self.stroies。我修复了你的错误。现在它有效。

UPD:如果你想使用stories作为字段而不是getter,你就不能改变局部变量(引用原始数组)。您可以仅修改原始数组。



storyDataAsFactory.$inject = ['$http', '$q'];

angular.module('ccsApp', /*XXX added []*/[]).factory('storyDataAsFactory', storyDataAsFactory);

function storyDataAsFactory($http, $q) {
    var stories = [];

    function getStories(url) {
        url = url || '';

        if (url !== '') {
            var deferred = $q.defer();

            //determine if ajax call already occurred;
            //if so, data exists in cache as local var
            if (stories.length !== 0) {
                deferred.resolve();
                return deferred.promise;
            }

            $http({method:'GET', url:url})
                .success(function (data, status, headers, config) {
                    // XXX using this code you lose original array
                    //stories = data;
              
                    // XXX instead you need to clear and to fill original array
                    stories.splice(0, stories.length);
                    data.forEach(function(x) { stories.push(x); });

                    deferred.resolve();
                })
                .error(function (data, status, headers, config) {
                    deferred.reject(status);
                });

            return deferred.promise;
        } else {
            alert('URL was empty.');
        }
    }

    return {
        stories: stories, // XXX using field instead of getter you need to keep original array

        getStories: function(url) {
            getStories(url);
        }
    };
}

// ------------ tests --------------------
describe('storyDataAsFactory.stories()', function() {
  var $httpBackend, $http, $q, storyDataAsFactory;
  
  beforeEach(module('ccsApp'));
  
  beforeEach(inject(function(_$httpBackend_) {
    $httpBackend = _$httpBackend_;
    $httpBackend.whenGET('stories.json').respond([1, 2, 3]);
  }));
  
  beforeEach(inject(function(_$http_, _$q_, _storyDataAsFactory_) {
    $http = _$http_;
    $q = _$q_;
    storyDataAsFactory = _storyDataAsFactory_;
  }));
  
  it('should return empty array before ajax resolved', function() {
    storyDataAsFactory.getStories('stories.json');
    expect(storyDataAsFactory.stories).toEqual([]);
    $httpBackend.flush();
  });
  
  it('should return filled array after ajax resolved', function() {
    storyDataAsFactory.getStories('stories.json');
    $httpBackend.flush();
    expect(storyDataAsFactory.stories).toEqual([1, 2, 3]);
  });
});

// ------------ run tests --------------------
window.onload = function() {
  var jasmineEnv = jasmine.getEnv();
  var htmlReporter = new jasmine.HtmlReporter();
  jasmineEnv.addReporter(htmlReporter);
  jasmineEnv.execute();
};

<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/1.3.1/jasmine.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/1.3.1/jasmine.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/1.3.1/jasmine-html.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.28/angular-mocks.js"></script>
&#13;
&#13;
&#13;