Search code examples
javascriptangularjsangularjs-serviceangularjs-controllerangularjs-factory

How can I pass an data from factory to my controller in angularjs?


I'm trying to move all the business logic from my controller to the factory, but I'm having some trouble passing fields data.

factory.js

app.factory("Quote", function ($resource) {
    // TODO: this shouldn't start with /en/
    var quoteStatus = [];
    var quoteLanguage = [];

    var Quote = $resource("/en/quote/api/quote/:id", {}, {
        retrieve: {
          method: 'GET',
          params: {},
          isArray: true
        },
        query: {
          method: 'GET',
          params: {},
          isArray: true,
          url: '/en/quote/api/quote/'           
        },
        fields: {
          method: 'GET',
          url: '/en/quote/api/quote/fields/ '
        },
        update: {
          method: 'PATCH',
        },
    });

    Quote.fields().$promise.then(function (fields) {
        var tempObj = [];
        for (key in fields.status) {
            // must create a temp object to set the key using a variable
            tempObj[key] = fields.status[key];
            quoteStatus.push({
                value: key,
                text: tempObj[key]
            });
        }

        for (key in fields.language) {
            // must create a temp object to set the key using a variable
            tempObj[key] = fields.language[key];
            quoteLanguage.push({
                value: key,
                text: tempObj[key]
            });
        }

        //$scope.addLanguage($scope.language);

        Quote.status = quoteStatus;
        Quote.language = quoteLanguage;
    });

    return Quote;


});

controller.js

$scope.quoteStatus = Quote.status;

However this is not working since $scope.quoteStatus is undefined. What am I missing?

Thanks in advance.


Solution

  • You can't expect async operation to behave in synchronous way.

    Basically when controller inject Quote in its factory function that time Quote service object gets created & then calls Quote.fields(). hen you ask Quote.status inside a controller will always return undefined. You are not maintaining promise anywhere so that controller will come to know that the data is ready or not.

    I think you should introduce $q.when flag there to check the Quote.fields() operation completed or not & then do get the desired variable there.

    For implementing above mention thing you need to store the promise of Quote.fields() call somewhere in service. like below

    var quoteFieldsPromise = Quote.fields().$promise.then(function (fields) {
    
       /// the code will be same here
    
    };
    

    Then add new method which will hold of quoteFieldsPromise promise object and return the value of quoteStatus & quoteLanguage.

    var getQuoteDetails = function(){
       $q.when(quoteFieldsPromise).then(function(){
          return { quoteStatus: Quote.quoteStatus, quoteLanguage: Quote.quoteLanguage };
       })
    }
    

    But the way you have returned whole Quote object, which only has $resource object which needs to be changed. I mean to say that the getQuoteDetails method which I've created can not be return with Quote object. So I'd rather rather refactor service to below.

    Service

    app.factory("Quote", function($resource, $q) {
        // TODO: this shouldn't start with /en/
        var quoteStatus = [], //kept private if needed
            quoteFieldsPromise, 
            quoteLanguage = [];//kept private if needed
    
        var QuoteApi = $resource("/en/quote/api/quote/:id", {}, {
            //inner code is as is 
        });
    
        //preserve promise of .fields() call
        quoteFieldsPromise = Quote.fields().$promise.then(function(fields) {
            //inner code is as is 
            //below lines are only changed.
    
            Quote.status = quoteStatus;
            Quote.language = quoteLanguage;
        });
    
        var getQuoteDetails = function() {
            return $q.when(quoteFieldsPromise).then(function() {
                return {
                    quoteStatus: quoteStatus,
                    quoteLanguage: quoteLanguage
                };
            })
        };
    
        return {
            QuoteApi: QuoteApi,
            getQuoteDetails: getQuoteDetails
        };
    });
    

    Controller

    Quote.getQuoteDetails().then(function(quoteDetails){
        $scope.quoteStatus = quoteDetails.quoteStatus;
        $scope.quoteStatus = quoteDetails.quoteLanguage;
    });