2016-11-10 5 views
3

한 번에 최대 1000 개의 항목 목록을 반환하는 REST 끝점이 있습니다. 항목이 1000 개 이상인 경우 응답의 HTTP 상태는 206이고 더 많은 항목을 가져 오는 다음 요청에 사용할 수있는 Next-Range 헤더가 있습니다.각도 2 Http, Observables 및 재귀 요청

각도 2 응용 프로그램에 노력하고있어 이것을 HttpObservable으로 구현하려고합니다. 내 문제는 내가 모른다는 것입니다. Observable 얼마나 많은 페이지의 항목이 있는지에 따라 이 마침내 내 구성 요소를 구독 할 수있는 Observable 중 하나를 반환합니다. 내 현재 타이프 라이터 구현에있어 어디 여기

는 다음과 같습니다

// NOTE: Non-working example! 

getAllItems(): Observable<any[]> { 
    // array of all items, possibly received with multiple requests 
    const allItems: any[] = []; 

    // inner function for getting a range of items 
    const getRange = (range?: string) => { 
    const headers: Headers = new Headers(); 
    if (range) { 
     headers.set('Range', range); 
    } 

    return this.http.get('http://api/endpoint', { headers }) 
     .map((res: Response) => { 
     // add all to received items 
     // (maybe not needed if the responses can be merged some other way?) 
     allItems.push.apply(allItems, res.json()); 

     // partial content 
     if (res.status === 206) { 
      const nextRange = res.headers.get('Next-Range'); 

      // get next range of items 
      return getRange(nextRange); 
     } 

     return allItems; 
     }); 
    }; 

    // get first range 
    return getRange(); 
} 

그러나이 작동하지 않습니다. 올바르게 이해하면 Observable이 항목 배열이 아닌 Observable의 초기 값으로 반환됩니다.

답변

7

확장 연산자를 사용하여 구현할 수 있습니다. 실제로하고 싶은 것은 재귀 flatmap을 만드는 것입니다. 그것이 연산자 확장이 생성 된 바로 그 것입니다. 여기

이 작동하는 방법의 코드입니다 :

let times = true; 
// This is a mock method for your http.get call 
const httpMock =() => { 
    if(times) { 
    times = false; 
    return Rx.Observable.of({items: ["1", "2", "3"], next: true}); 
    } else { 
    return Rx.Observable.of({items: ["4", "5", "6"], next: false}); 
    } 
} 

httpMock() 
    .expand(obj => { 
    // In your case, the obj will be the response 
    // implement your logic here if the 206 http header is found 
    if(obj.next) { 
     // If you have next values, just call the http.get method again 
     // In my example it's the httpMock 
     return httpMock(); 
    } else { 
     return Rx.Observable.empty(); 
    } 
    }) 
    .map(obj => obj.items.flatMap(array => array)) 
    .reduce((acc, x) => acc.concat(x), []); 
    .subscribe((val) => console.log(val)); 

이란 것은 않습니다이다 모의 사실에 '다음'속성을 갖는 제 1 HTTP 요청. 이것은 206 헤더와 일치합니다. 그런 다음 'next'속성이 false 인 두 번째 호출을 만듭니다.

결과는 두 요청의 결과가 모두 포함 된 배열입니다. 확장 연산자 덕분에 더 많은 요청을 처리 할 수 ​​있습니다. jsbin 예를 들어 작업

여기에서 찾을 수 있습니다 : http://jsbin.com/wowituluqu/edit?js,console

편집 : 배열에서 배열하고 최종 결과를 반환하는 HTTP 호출과 함께 작동하도록 업데이트는 모든 요소가 배열을 형성 포함하는 하나의 배열입니다.

요청의 별도 배열이 포함 된 배열을 결과 안에 포함하려면 플랫 맵을 제거하고 직접 항목을 반환하십시오. 업데이트 여기 codepen : http://codepen.io/anon/pen/xRZyaZ?editors=0010#0

+0

어떤 이유로이 기능이 올바르게 작동하지 않습니다. 간단한 코드 샘플을 추가하고 여기에 더 많은 의견을 남깁니다. https : //gist.github.com/roxeteer/76789931e82f38061b0d33d4fdc06c70 –

+0

JSBIN을 코드로 업데이트하려고 시도했지만 예상대로 작동하지 않는 것 같습니다 (HTTP 조롱에 대한 사소한 변경 사항). http://jsbin.com/nosohom/edit?js,console 이것이 작동하지 않는다면, 잘못된 jsbin 예제를 제게 제공 할 수 있습니까? – KwintenP

+0

이상한. 코드가 비슷해 보이지만 각도 2에서 다르게 작동했습니다. 구독자를 수정하여 "완료된"핸들러를 사용하도록 수정했습니다. 내 대답보기 : http://stackoverflow.com/a/40543794/587337 –

2

내가 KwintenP의 예에 사소한 조작 작업을 가지고 :

다음 Observable에 가입 한 구성 요소에서

// service.ts 

getAllItems(): Observable<any[]> { 
    const getRange = (range?: string): Observable<any> => { 
    const headers: Headers = new Headers(); 
    if (range) { 
     headers.set('Range', range); 
    } 

    return this.http.get('http://api/endpoint', { headers }); 
    }; 

    return getRange().expand((res: Response) => { 
    if (res.status === 206) { 
     const nextRange = res.headers.get('Next-Range'); 

     return getRange(nextRange); 
    } else { 
     return Observable.empty(); 
    } 
    }).map((res: Response) => res.json()); 
} 

, 나는 완성 된 처리기를 추가했다

// component.ts 

const temp = []; 

service.getAllItems().subscribe(
    items => { 
    // page received, push items to temp 
    temp.push.apply(temp, items); 
    }, 
    err => { 
    // handle error 
    }, 
() => { 
    // completed, expose temp to component 
    this.items = temp; 
    } 
); 
+0

항상 이런 식으로하면 안됩니다. 관측 가능 상태에서 외부 상태를 사용 중입니다. 그건 큰 노 - 아니야. 오류를주는 plnkr을 제공 할 수 있다면 기꺼이 살펴 보겠습니다. – KwintenP

+0

끝 점이 배열의 배열을 반환하면 실패한 것처럼 보입니다. 내 CodePen 참조 : http://codepen.io/roxeteer/pen/vyLaEd?editors=0010#0 –

+0

이 코드가 작동하지 않습니까? 나는 9 개의 아이템으로 결과를 보았다 ... – KwintenP

0

위의 답변은 유용합니다. 재귀 적으로 페이징 API를 사용하여 데이터를 가져와야했고 계승을 계산하는 code snippet 을 만들었습니다.