2016-08-17 38 views
0

我正在嘗試設計一個Angular應用程序,它具有使用Angular服務註冊回調函數和「數據請求對象」的組件。該服務基本上跟蹤所有數據請求對象以及它們引用的回調函數。然後,它執行長輪詢來對RESTful API進行異步調用。當所有數據進入時,服務決定哪些組件需要哪些數據並用API調用的結果調用它們。具有多個API數據服務的應用程序

我遇到麻煩的問題是,每個組件可能需要將數據「轉換」爲一個規定了特定格式的JSON對象。例如,一個圖表組件可能要求數據結果是單向的,但是一個表格組件可能需要數據結果看起來是另一種方式。

爲了讓事情變得更加複雜,我想設計我的數據服務,使組件可以註冊來自多個不同RESTful API的數據。

因爲我對Angular相當陌生,所以我想獲得幫助完成這種類型的應用程序的一些最佳實踐。我想要做的是讓我的組件註冊一個'主要'數據服務。註冊功能將作爲參數的回調函數和數據請求對象,這將是在格式像這樣:

{ 
    "service": "apiService", 
    "request": { 
     ... 
    } 
} 

然後會有對每個API的RESTful一個單獨的角服務。這些子服務將處理如何處理數據請求對象,並對應於上面的「服務」字段。主數據服務將在長輪詢週期中將請求排隊到子服務。因此,主數據服務將看起來像(注:我使用ES6):

class DataService { 
    constructor($q, $interval, $injector) { 
    this.$q = $q; 
    this.$interval = $interval; 
    this.$injector = $injector; 

    this.subscriptions = []; 
    this.callbacks = []; 

    this.poll(); 
    } 

    poll() { 
    let reqs = []; 
    angular.forEach(this.subscriptions, (sub, i) => { 
     let service = this.$injector.get(sub.service); 
     let deferred = this.$q.defer(); 

     reqs.push(deferred); 
     service.get(sub.request).then((result) => { 
      this.callbacks[i](result); 
      deferred.resolve(result); 
     }, (result) => { 
      deferred.reject(result); 
     }); 
    }); 

    this.$q.all(reqs).then(() => { 
     this.$interval(poll, this.pollInterval || 10000); 
    }); 
    } 

    register(request, callback) { 
    this.subscriptions.push(request); 
    this.callbacks.push(callback); 
    } 
} 

angular.module('DataService', []).service('DataService', DataService); 

,我有麻煩搞清楚如何實現這件作品是「數據變換」部分。據我所知,有真的只有兩個地方我可以看到這個數據轉換可以發生:

  1. 在組件內部
  2. 裏面的各個API服務

第一種方式沒有按這對我來說似乎不是一個可行的選擇,因爲它打破了組件應該有點「愚蠢」的慣例。該組件不應處理轉換RESTful API返回的數據:它應該按原樣使用數據。

但是第二種方式也帶來了另一個問題,那就是每個RESTful API服務都必須爲我創建的每個組件類型都有轉換函數。這對我來說似乎並不「乾淨」。

有沒有另一種方法可以設計我的應用程序來實現這個目標?任何洞察力將不勝感激。

回答

0

只是一個建議:使用角度的內置事件系統。

//Constructor 
constructor($q, $interval, $injector, $rootScope) { 
this.$q = $q; 
this.$interval = $interval; 
this.$injector = $injector; 
this.$rootScope = $rootScope; 
this.listeners = []; 
//No idea how its written in Angular2 but cleanup the event listeners when this is destroyed 
//Example in 1.5.x: 
//$scope.$on('$destroy',() => angular.forEach(this.listeners, l => l()); 
this.poll(); 
} 

//The new register method 
register(ev, callback) { 
//When cleaning up - iterate over listeners and invoke each destroy function - see constructor 
this.listeners.push(this.$rootScope.$on(ev, callback)); 
} 

//The new poll method 
poll() { 
    let reqs = []; 
    angular.forEach(this.subscriptions, (sub, i) => { 
     let service = this.$injector.get(sub.service); 
     let deferred = service.get(sub.request).then((response) => { 
     //responseToEventsMapper should map and parse response to list of events to fire. 
     //Lets say the response is an authentication response for login attempt, 
     //then the triggered events will be 'Auth:stateChange' and 'Auth:login' with 
     //response.user as data. configure responseToEventsMapper upfront. 
     let events = this.responseToEventsMapper(response); 
     angular.forEach(events, event => this.$rootScope.$emit(event.type, event.data)); 
     }); 
     reqs.push(deferred); 
    }); 

    this.$q.all(reqs).then(() => { 
     this.$interval(poll, this.pollInterval || 10000); 
    }); 
    } 
+0

感謝您的提示。我沒有意識到你可以用這種方式使用$ emit和$(或者$ on返回一個註銷函數,特別方便)。對於responseToEventsMapper,我的問題仍然是映射器是應該在服務中還是在組件中定義?假設我有兩個API,apiA和apiB。他們都以完全不同的格式返回響應,jsonA和jsonB。但是該組件要求數據採用不同的格式,jsonC。responseToEventsMapper應該執行這個轉換,但是在哪裏定義一個適當的位置? – snusnu

+0

您可以在註冊階段爲每個用戶提供自己的映射器。 –

相關問題