弊社ではangularを使っているのですが、
利用している外部サービスのjavascriptで、
処理完了したらglobal上に定義した指定の名前の関数を通して処理結果を返す
というものがあり、どうしても以下のような流れで組む必要がありました。
1.angularから外部のライブラリを呼び出す。その際、callbackのメソッド名を指定しておく
↓
2.外部ライブラリは処理完了したら、global上に定義された"1"のcallbackの名前のfunctionを呼び出す
↓
3.global上の定義されたfunctionからangularに戻ってくる
更に"1"~"3"までの処理をひとまとまりとしてobservableな感じで使いたい。
という場合、以下のようにしたらなんとかなった。
SampleService.ts
declare const window: any; // tslint回避のため
@Injectable()
export class SampleService{
private isDone = false;
private response;
public constructor(...) {
window.SampleService = this; // thisでglobal上に渡す。
}
/**
* これが目的のメソッド。一旦外部ライブラリになげるが、Observableとして扱いたい。
*/
public exec(): Observable<...> {
const params = ...;
// これが外部提供のライブラリ。 global上に定義された"callbackFunctionName"が呼び出される。
// 同等のものを自前実装しようかとも思ったが、結構ヘビーだったのと、内部で仕様変更があった時に追随するのが大変なので諦めて使うことにした。
OtherCompanyLibrary.call(params, "callbackFunctionName");
return Observable
.interval(100)
.timeInterval() // 100ms毎のinterval
.filter(() => {
return this.isDone;
})
.take(1)
.map(() => {
return this.response;
});
}
public callback(response) {
this.response = response;
this.isDone = true;
}
}
index.html
<script>
function callbackFunctionName(response) {
window.SampleService.callback(response);
}
</script>
windowを介してServiceクラスをやり取りするのと、
Observableのintervalをつかって、処理が完了するのを待つのがポイント。