albatrosary's blog

UI/UXとエンタープライズシステム

Angular1.5 + RxJS

Angular2で利用されているRxJSですが、もちろんAngular1でも利用可能です。「rx.angular.js」というのがあります。

github.com

RxJSをあまり触っていないので、リポジトリにあるサンプルをささっと見てみる。

モジュールのインストール

ルータや$resourceなど通常利用するモジュールを登録します。

npm install angular@1.5.0 --save
npm install angular-resource@1.5.0 --save
npm install bootstrap@3.3.6 --save
npm install jquery@2.1.4 --save
npm install ngcomponentrouter@1.4.1 --save

Rxをインストール。rx-angularでRxJSとRxJS用のディレクティブがダウンロードされます。

npm install rx-angular --save

HTMLにパスを設定する

  <script src="node_modules/jquery/dist/jquery.min.js"></script>
  <script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
  <script src="node_modules/angular/angular.min.js"></script>
  <script src="node_modules/ngcomponentrouter/angular_1_router.js"></script>
  <script src="node_modules/angular-resource/angular-resource.min.js"></script>
  <script src="node_modules/rx/dist/rx.all.js"></script>
  <script src="node_modules/rx-angular/dist/rx.angular.js"></script>

サンプルコード

wikipediaからリストを取るサンプルです。コンポーネントをrxとする

components/rx/rx.html
components/rx/rx.js

各ファイルの中身はこちら

(components/rx/rx.html)

<h2>Reactive Angular - Wikipedia Example</h2>
<input type="text" ng-model="$ctrl.search">
<button ng-click="$ctrl.submit($ctrl.search)">Search</button>

<ul>
  <li ng-repeat="result in $ctrl.results">
    {{ result }}
  </li>
</ul>

(components/rx/rx.js)

/* global angular */
(function () {
  'use strict';

  angular
    .module('TodoApp.components.rx', ['rx'])
    .component('rx', {
      controller: Controller,
      templateUrl: 'components/rx/rx.html'
    });

  Controller.$inject = ['$rootScope', '$http', 'rx'];
  
  function Controller($rootScope, $http, rx) {
    console.log('Todo detail Controller Constructor');
    ctrl = this;
    ctrl.$rootScope = $rootScope;
    ctrl.$http = $http;
    ctrl.rx = rx;
    ctrl.search = '';
    ctrl.results = [];
  }
 
  var ctrl;
  
  Controller.prototype.$onInit = function() {
    console.log('onInit()');

    ctrl.rx.createObservableFunction(ctrl, 'submit')
      .map(term => term)
      .flatMapLatest(searchWikipedia)
      .subscribe(results => {ctrl.$rootScope.$apply(ctrl.results = results);});
  }
  
  function searchWikipedia (term) {
    var deferred = ctrl.$http({
      url: "http://en.wikipedia.org/w/api.php?&callback=JSON_CALLBACK",
      method: "jsonp",
      params: {
        action: "opensearch",
        search: term,
        format: "json"
      }
    });

    return ctrl.rx.Observable
      .fromPromise(deferred)
      .map(response => response.data[1]);
  }
})();

RxJSのサイトにあるサンプルでは$applyが無いのでワンテンポ遅れてUIに反映される。

完成されたコードはgithubを見て下さい。

最後に

Angular2でも利用されているRxJSではあるがAngular1でも普通に利用できます。ECMAScriptの方向性とか考えるとこうした書き方にしていくべきなんでしょうね(まだ慣れませんが)。