2016-03-02 64 views
14

我對Angular來說很新穎,並且在進行同步操作時遇到問題。我已經解決了一些問題,這些問題來自於角控制器,我從newController文件中得到錯誤'Can not call method then undefined'。TypeError:無法調用未定義的Angularjs的方法'then'

angular.module('newApp.newController', ['angularSpinner', 'ui.bootstrap']) 

.controller('newController', function($q, $scope, utilityFactory, $http) { 
    utilityFactory.getData().then(function(data) { 

     console.log("success"); 
     console.log(data); 

    }); 
}); 


angular.module('newApp.utility', []) 
    .factory('utilityFactory', function($q, $http) { 

     var utils = {}; 

     //This is a cordova plugin 
     var getLauncher = function() { 
      return window.plugin.launcher; 
     }; 

     var success = function(data) { 
      console.log(device); 
      return device; 
     } 
     var fail = function(error) { 
      console.log("error", error); 
     }; 

     utils.getData = function() { 
      /* Get the store number details initially before initalizing the application */ 
      if (window.plugin) { 
       var launcher = getLauncher(); 
       console.log("Fetching data from device"); 
       //Cordova js is returning this method 
       return launcher.getDevice(success, fail); 
      } 
     }; 
     return utils; 
    }) 
+1

'getData'不返回任何東西 –

+0

我用這個也 回報launcher.getD設備(成功,失敗); – Bharath

+0

但是它不會爲'else'返回任何東西,而'launcher.getDevice'返回什麼? – charlietfl

回答

1
return launcher.getDevice(success, fail); 

此行是問題,我只想有一個承諾把它包:

return $q(launcher.getDevice.bind(launcher, success, fail)); 

編輯:還需要照顧其他條件,所以代碼會:

utils.getData = function() { 
     /* Get the store number details initially before initalizing the application */ 
     if (window.plugin) { 
      var launcher = getLauncher(); 
      console.log("Fetching data from device"); 
      //Cordova js is returning this method 
      return $q(launcher.getDevice.bind(launcher, success, fail)); 
     } 
     return $q.resolve(); // or $q.reject(reason); 
    }; 
+0

我會檢查這一點。 – Bharath

+0

試過這個,在調用getDevice方法後,它進入錯誤回調函數並打印消息 - 「錯誤」 – Bharath

5

有了這樣的理解:

Launcher.prototype.getDevice = function(successCallback, failureCallback) { 
    exec(successCallback, failureCallback, KEY, 'getDevice', []); 
} 

,我們知道window.plugin.launcher.getDevice()返回undefined,而不是數據對象。相反,它通過其成功/失敗回調來提供響應。

因此,要使用promise,window.plugin.launcher.getDevice()需要「promisified」,涉及明確創建new Promise()及其解析/拒絕.getDevice的回調。 (簡單地包裝在$ q(...)中是不一樣的,並且不起作用)。

angular.module('newApp.utility', []).factory('utilityFactory', function($q, $http) { 
    return { 
     getDevice: function() { 
      return $q.defer(function(resolve, reject) { 
       window.plugin.launcher.getDevice(resolve, reject); // If this line throws for whatever reason, it will be automatically caught internally by Promise, and `reject(error)` will be called. Therefore you needn't explicitly fork for cases where `window.plugin` or `window.plugin.launcher` doesn't exist. 
      }).promise; 
     } 
    }; 
}); 

從控制器調用現在應該工作:

angular.module('newApp.newController', ['angularSpinner', 'ui.bootstrap']).controller('newController', function($q, $scope, utilityFactory, $http) { 
    return utilityFactory.getDevice().then(function(data) { 
     console.log(data); 
    }).catch(function(error) { 
     console.error(error); 
    }); 
}); 
+0

如何解析並拒絕獲取數據 – Bharath

+0

通過將Promise的resolve和reject函數作爲successCallback和errorCallback 'window.plugin.launcher.getDevice()'。 –

+0

'ReferenceError:Promise is not defined' 得到這個錯誤 – Bharath

1

1)你的實際模塊應該是 「NEWAPP」,而不是 「newApp.newController」 和 'newApp.utility'。這就是將這兩個組件放在單獨的模塊中,而不是放在myApp模塊中。

2)每當你宣佈一個新的模塊時,才應使用

angular.module('newApp', []) 

的語法。當你要訪問的模塊,你應該使用

angular.module('newApp') 

https://docs.angularjs.org/api/ng/function/angular.module

3)你utilityFactory返回一個變量「設備」尚未宣佈任何地方

4)你可以用」 t使用'then'而不返回getData函數中的承諾。然後是一個在Javascript承諾中實現的方法,所以你不能在你的代碼中的任何地方使用它。 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

utils.getData = function() { 
    var deferred = $q.defer(); 

    if (window.plugin) { 
     var launcher = getLauncher(); 
     console.log("Fetching data from device"); 
     //Cordova js is returning this method 
     return launcher.getDevice(success, fail); 
    } 

    return deferred.promise;  
}; 

這裏是調試代碼時,我用了一個codepen。我稍微修改了一下你的代碼,但是它會給出一個返回promise的函數的例子。 http://codepen.io/anon/pen/QNEEyx?editors=1010

0

正如其他一些答案中提到的,您需要從utils.getData函數中返回Promise。 Angular的$q助手可以讓你做到這一點。但是,其他一些答案顯示您這樣做的方式違背了最佳做法。當使用$q,最好的做法是要做到以下幾點:

var myPromise = $q(function (resolve, reject) { 
    // Do some logic in here that is asynchronous and either invoke resolve with 
    // the results or reject with an error that may have occurred 
}); 

因此,你的代碼就變成了:

angular.module('newApp.utility', []) 
    .factory('utilityFactory', function($q, $http) { 

     var utils = {}; 

     //This is a cordova plugin 
     var getLauncher = function() { 
      return window.plugin.launcher; 
     }; 

     var success = function(data) { 
      console.log(device); 
      return device; 
     } 
     var fail = function(error) { 
      console.log("error", error); 
     }; 

     utils.getData = function() { 
      /* Get the store number details initially before initalizing the application */ 
      return $q(function (resolve, reject) { 
       if (!window.plugin) { 
        // You can handle this case as a rejection of the promise 
        reject(new Error('Window plugin not found')); 
        return; 
       } 

       var launcher = getLauncher(); 
       console.log("Fetching data from device"); 
       //Cordova js is returning this method 
       // When device is ready it will "resolve" the promise and 
       // invoke any of the ".then()" functions you add to the promise 
       // If an error occurs, it will invoke any ".catch()" functions 
       // that you have added. 
       launcher.getDevice(resolve, reject); 
      }); 
     }; 
     return utils; 
    }) 

有關$q服務的更多信息,請從官方AngularJS文檔,檢查這個職位: https://docs.angularjs.org/api/ng/service/ $ q

此外,如果您想了解更多關於承諾和JavaScript中的異步編程的一些資源:

的承諾整潔的可視化工具 - http://bevacqua.github.io/promisees/#

教程上的承諾 - https://www.toptal.com/javascript/javascript-promises

另一件事是尋找到作爲AngularJS最佳實踐的一般指導是角風格導遊約翰爸爸:https://github.com/johnpapa/angular-styleguide

最後,你有你的模塊設置的方式稍微關閉。每次調用angular.module(moduleName, dependencies)將創建一個具有這些依賴關係的新模塊。雖然將角度應用分解爲多個模塊是一個好主意,但您需要確保使用ng-app指令引用的根或「主」應用具有對所有子模塊的引用,並且任何引用依賴關係的模塊從另一個模塊中將該模塊包含在其依賴列表中。

在你的情況,你創建一個名爲newApp.newController模塊,但你擁有它,因爲它試圖引用utilityFactory,這是在所謂的newApp.utility一個單獨的模塊定義的,但不是由你newApp.newController模塊引用它不會工作。爲了解決這個問題,請執行下列操作:

angular.module('newApp.newController', ['angularSpinner', 'ui.bootstrap', 'newApp.utility']) 
// Make sure to add 'newApp.utility' to the dependencies of the 'newApp.newController' module. 

或者,你可以創建兩個控制器和同一模塊中的效用工廠:繞角模塊系統

// Create the module once 
angular.module('newApp', ['angularSpinner', 'ui.bootstrap']); 

// Reference it by invoking it with just one parameter 
angular.module('newApp').controller('newController', ...); 

angular.module('newApp').factory('utilityFactory', ...); 

用法和最佳實踐能在這裏找到: https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md#modules

相關問題