2016-08-13 31 views
0

在AngularJS中,我似乎無法理解'promise'的概念,我使用restangular庫通過REST獲取資源,但是我總是得到空結果。下面的代碼在angularjs中使用延遲結果

.service('CareersService', [ 'Restangular', '$sce', function(Restangular, $sce){ 
      var vacancies = []; 
      var result; 
      this.getVacancies = function() { 
       Restangular.all('job_posts').getList({active: 'true'}).then(function(job_posts){ 
       job_posts.forEach(function(job_post){ 
        vacancies.push(_.pick(job_post,['id','title','min_experience','max_experience','location'])); 
       }) 
      }) 
      return vacancies; 
      } 
      this.getVacancy = function(job_id){ 
        Restangular.one('job_posts',job_id).get().then(function(job_post){ 
        result = _.pick(job_post, 'title','min_experience','max_experience','location','employment_type','description'); 
        var safe_description = $sce.trustAsHtml(result.description); 
         var emp_type = _.capitalize(result.employment_type); 
         _.set(result, 'description', safe_description); 
         _.set(result, 'employment_type', emp_type); 
      }); 
       return result;    
      } 
    }]).controller('DetailsCtrl', ['$scope' ,'$stateParams', 'CareersService' ,function($scope, $stateParams, CareersService) { 

      $scope.data.vacancy = { title: 'Loading ...', contents: '' }; 

      $scope.data.vacancy = CareersService.getVacancy($stateParams.job_id); 

}]) 

,然後在視圖

<div class="container"> 
    <a ui-sref="careers" class="btn btn-primary">Show All</a> 
    <div class="row"> 
     <h2>{{ data.vacancy.title }}</h2> 
     <p>{{ data.vacancy.min_experience }}</p> 
     <p>{{ data.vacancy.max_experience }}</p> 
     <p>{{ data.vacancy.location }}</p> 
     <p>{{ data.vacancy.employment_type }}</p> 
     <p ng-bind-html="data.vacancy.description"></p>  
    </div> 
</div> 

我缺少的東西在使用承諾的方式?


更新

這裏是更新的代碼感謝我來到這裏的所有幫助,

  this.getVacancies = function() { 
       Restangular.all('job_posts').getList({active: 'true'}).then(function(job_posts){ 
       job_posts.forEach(function(job_post){ 
        vacancies.push(_.pick(job_post,['id','title','min_experience','max_experience','location'])); 
       }) 
       return vacancies; 
      }) 
      } 
     this.getVacancy = function(job_id){ 
        Restangular.one('job_posts',job_id).get().then(function(job_post){ 
        vacancy = _.pick(job_post, 'title','min_experience','max_experience','location','employment_type','description'); 
        ... 
        return vacancy; 
      }); 
      } 
}]) 

並在控制器

CareersService.getVacancy($stateParams.job_id).then(function (vacancy){ 
      $scope.data.vacancy = vacancy; 
      }); 

CareersService.getVacancies().then(function (vacancies){ 
     $scope.data.vacancies = vacancies; 
    }); 

我現在得到的錯誤

Cannot read property 'then' of undefined

在生產線

CareersService.getVacancies().then(function(vacancies) { 
+0

你註銷了什麼空缺包含?並且還讓你感到沮喪並檢查你是否獲得了服務中的數據? –

+0

有一個對服務的調用,並且成功(現在是304)響應,所以數據肯定被填充到job_post中。不知道爲什麼結果沒有被填充。未定義它表示當我在返回之前登錄到控制檯時。對於JS和Angular來說,這是一個不錯的選擇,所以甚至無法找出一個好的失敗測試,​​否則也會分享這個測試 –

+1

''return'vacancies/result' ** **之前** .then()調用:[爲什麼我的變量在函數內部修改後沒有改變? - 異步代碼引用](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – Andreas

回答

1

Restangular使得在HTTP API調用,一旦撥打電話返回底層承諾目的。並且它的功能在.then中可以得到API響應的數據。

所以在這裏你正在一個異步調用,並考慮它的出現它同步的方式一樣,你可以看到你已經從Restangular調用返回result/vacancies陣列,以這種方式result/vacancies總是要爲空。

在這種情況下,您應該從服務方法返回承諾。並從承諾中返回適當的格式化數據,以便您可以在控制器中承諾(通過檢索數據)chain

服務

this.getVacancies = function() { 
    //returned Restangular promise 
    return Restangular.all('job_posts').getList({ 
    active: 'true' 
    }).then(function(job_posts) { 
    job_posts.forEach(function(job_post) { 
     vacancies.push(_.pick(job_post, ['id', 'title', 'min_experience', 'max_experience', 'location'])); 
    }); 
    //return calculated result 
    return vacancies; 
    }) 
} 
this.getVacancy = function(job_id) { 
    //returned Restangular promise 
    return Restangular.one('job_posts', job_id).get().then(function(job_post) { 
    result = _.pick(job_post, 'title', 'min_experience', 'max_experience', 'location', 'employment_type', 'description'); 
    var safe_description = $sce.trustAsHtml(result.description); 
    var emp_type = _.capitalize(result.employment_type); 
    _.set(result, 'description', safe_description); 
    _.set(result, 'employment_type', emp_type); 
    //returned result to chain promise 
    return result; 
    }); 
} 

正如我說,現在你可以很容易地內控制器鏈的承諾具有在服務方法調用.then功能。

CareersService.getVacancy($stateParams.job_id).then(function(result){ 
    $scope.data.vacancy = result; 
}); 

更新

沒有.then語法的工作,但你需要一個方法調用之後加入.$object做小的變化了。

$scope.data.vacancy = CareersService.getVacancy($stateParams.job_id).$object; 

$object是承諾對象內加入由Restangular屬性。在進行API調用時,當時它將$scope.data.vacancy的值作爲空數組([]),並且一旦服務器響應並響應,它就會用服務器收到的響應填充該對象。在幕後它只更新$object屬性的值,該值自動更新$scope.data.vacancy的值。

$resourcengResource中存在相同的行爲。


我想也承認,當你鏈接承諾時,你必須明確處理錯誤情況。而在目前的代碼中,你沒有處理這種失敗情況。所以我建議你也可以通過在Restangular REST API調用中加入error函數來達到這個目的。並使用$q.reject('My error data, this can be object as well')

+0

好吧,所以基本上'$ scope.data.vacancy = CareersService.getVacancy($ stateParams.job_id);'''或$ scope.data.vacancies = CareersService.getVacancies ();'不用等待結果填充就執行?我以爲因爲我處理結果,然後阻止服務,情況並非如此。 –

+0

值得注意的是,'$ scope.data.vacancies = CareersService.getVacancies();'最終會渲染帶有第一批中獲取的列表空位的索引視圖,所以仍然有點混亂。 –

+0

@AnadiMisra你在這裏,我也加了解釋。 –

0

您正在進行異步調用以獲取結果。所以你需要一個回調或promise來處理這個問題。用最少的代碼改變一個選擇是讓服務來回報承諾,並在控制器通過then

.service('CareersService', ['Restangular', '$sce', function(Restangular, $sce) { 
    var vacancies = []; 
    var result; 
    this.getVacancies = function() { 
    Restangular.all('job_posts').getList({ 
     active: 'true' 
    }).then(function(job_posts) { 
     job_posts.forEach(function(job_post) { 
     vacancies.push(_.pick(job_post, ['id', 'title', 'min_experience', 'max_experience', 'location'])); 
     }) 
    }) 
    return vacancies; 
    } 
    this.getVacancy = function(job_id) { 
    return Restangular.one('job_posts', job_id).get().then(function(job_post) { 
     result = _.pick(job_post, 'title', 'min_experience', 'max_experience', 'location', 'employment_type', 'description'); 
     var safe_description = $sce.trustAsHtml(result.description); 
     var emp_type = _.capitalize(result.employment_type); 
     _.set(result, 'description', safe_description); 
     _.set(result, 'employment_type', emp_type); 
     return result; 
    }); 
    } 
}]).controller('DetailsCtrl', ['$scope', '$stateParams', 'CareersService', function($scope, $stateParams, CareersService) { 

    $scope.data.vacancy = { 
    title: 'Loading ...', 
    contents: '' 
    }; 

    CareersService.getVacancy($stateParams.job_id).then(function(result) { 
    $scope.data.vacancy = result; 
    }); 

}]) 
0

得到的結果你的話外做回嘗試中移動它,然後運作

this.getVacancies = function() { 

      Restangular.all('job_posts').getList({active: 'true'}).then(function(job_posts){ 
      job_posts.forEach(function(job_post){ 
       vacancies.push(_.pick(job_post,['id','title','min_experience','max_experience','location'])); 
      }) 
      return vacancies; 
     })   
     }