Hỏi cách return value trong factory trong angularjs?


  • Angel

    Mình có 1 factory như sau:

    app.factory('getApiUrl', function (http, $q) {
        var obj = {};
        obj.getResponse = function (url) {
            var promise = $q.defer();
    
            httpq.get(url).then(function (data) {
                //obj = data.data;
                promise.resolve(data.data);
            });
            return promise.promise;
        }
        return obj;
    });
    

    giờ mình muốn xài cái factory này, trong controller mình viết
    var test=getApiUrl.getResponse (url);
    nhưng không thể gán giá trị cho hàm này được.


  • Banned

    Bạn đang dùng promise không đúng cách rồi. Anw, bạn giải thích cụ thể câu hỏi của bạn hơn được không?



  • Vì method httpq.get(url) là một method async, do đó nếu để lệnh return promise.promise sau nó thì lệnh này có thể sẽ được chạy trước khi method httpq.get(url) được thực thi xong. Do đó câu lệnh return phải được viết trong hàm callback của method httpq.get(url), tức được viết trong then. Bạn có thể viết lại như sau:

    app.factory('getApiUrl', function (http, $q) {
        var obj = {};
        obj.getResponse = function (url) {
            var promise = $q.defer();
            return httpq.get(url).then(function (data) {
                //obj = data.data;
                return promise.resolve(data.data);
            });
        }
        return obj;
    });
    

    Method getResonse sẽ trả về một promise. Để sử dụng được giá trị trả về khi promise này được fulfill thành công bạn có thể gọi như sau:

    getApiUrl.getResponse(url).then(function (data) {
       // Do something with data
    });
    

    Tuy nhiên bản thân method httpq.get(url) đã trả về là một promise rồi nên bạn không cần phải tạo thêm một promise nữa. Ngắn gọn hơn sẽ là:

    app.factory('getApiUrl', function (http, $q) {
        var obj = {};
        obj.getResponse = httpq.get;
        return obj;
    });
    

    Còn cách gọi thì vẫn như bên trên:

    getApiUrl.getResponse(url).then(function (data) {
       // Do something with data
    });
    

    Không biết mình có hiểu đúng ý bạn không.


  • Angel

    Cảm ơn bạn đã giải thích cho mình hiểu rõ, có điều mình muốn hỏi thêm về work flow chương trình chút, vd chương trình mình lấy list danh sách từ 2 nguồn web api về, rồi mình muốn so sánh giữa 2 list hoặc gộp 2 list lại với nhau, như vậy thì khi mình gọi hàm , mình không thể dùng hàm gộp được, có cách nào xử lý không bạn. Mình cảm ơn bạn nhiều.

    Mình có thử viết lại theo cách gắn gọn của bạn :

    app.factory('getApiUrl', function (http, $q) {
    var obj = {};
    obj.getResponse = httpq.get(url).then(function (data) {});
    return obj;
    });
    tuy nhiên hàm không chạy được, bạn co thể trợ giúp mình phần này chút được kông bạn


  • Angel

    @rikky À, vì mình tínhxử lý data cho cả 2 cái web api, cho nên nhất thiết mình phải gán được dữ liệu vào biến, sau đó dùng biến đó để xử lý rồi mới đổ ra lại giao diện, cho nên mình muốn tìm cách nào để thực hiện



  • Vì Angular sử dụng thư viện promise Q nên bạn có thể sử dụng hàm Q.all để làm được điều như bạn muốn, ví dụ:

    Q.all([getFromDisk(), getFromCloud()]).done(function (values) {
        assert(values[0] === values[1]); // values[0] is fromDisk and values[1] is fromCloud
    });
    

    Trong đó getFromDisk()getFromCloud() là các hàm async trả về các promise, Q.all nhận đối số là một mảng các promise, khi tất cả các promise này được fulfill xong thì hàm nested trong done sẽ được thực thi. Bạn có thể làm tương tự với ứng dụng bạn đang trong làm.


  • Espresso

    Bạn có thể yham khảo cái này:

    app.factory('setDefault', function($http, $q) {
    return {
    getLocation: function() {
    var def = $q.defer();
    $http.post("/admin/callAPI", {
    link: "/locations/list",
    method: "GET"
    })
    .success( function (data) {
    if (data.response.locations) {
    for (var i = 0; i < data.response.locations.length; i++) {
    if(data.response.locations[i].address && data.response.locations[i].address.line) {
    var line = data.response.locations[i].address.line;
    var lineSplit = line.split(' ');
    if (lineSplit[0].match(/^-?\d+$/)) {
    data.response.locations[i].streetName = lineSplit[1];
    }else {
    data.response.locations[i].streetName = lineSplit[0];
    }
    }
    }

                }
                def.resolve(data.response.locations); 
            })
            .error( function(error){
                def.resolve(error);
            });
            return def.promise;   
        },
        getSubCategory: function() {
            var def = $q.defer();
            $http.get("/admin/globalData?item=lSubCategory")
            .success( function (data) {
                def.resolve(data); 
            })
            .error( function(error){
                def.resolve(error);
            });
            return def.promise; 
        },
        getCategory: function() {
            var def = $q.defer();
            $http.get("/admin/globalData?item=lCategory")
            .success( function (data) {
                def.resolve(data); 
            })
            .error( function(error){
                def.resolve(error);
            });
            return def.promise; 
        },
    
    };
    

    });


Log in to reply