背景(領域外)をクリックしたら閉じる、とか

ドロップダウンなどを表示したときに、領域外をクリックしたら閉じたい。 HTMLだと、どのように実装するのが一般的なのかわからなかったのでAngularのUI Bootstrapを参考にしてみたよ。

Dropdown
documentにイベントハンドラを登録。

// https://github.com/angular-ui/bootstrap/blob/v1.1.0/src/dropdown/dropdown.js#L13
$document.on('click', closeDropdown);

// ...

var closeDropdown = function(evt) {
  // ...
  // dropdown内をクリックかつ'outsideClick'が設定されている場合は閉じない
  var dropdownElement = openScope.getDropdownElement();
  if (evt && openScope.getAutoClose() === 'outsideClick' && 
  dropdownElement && dropdownElement[0].contains(evt.target)) {
    return;
  }
  // ...
  openScope.isOpen = false;
  // ...
};

補足: dropdownは複数開くことができないようになっている。uibDropdownServiceが管理している。

Modal
自身(全領域カバーしている)にイベントハンドラを登録。

// https://github.com/angular-ui/bootstrap/blob/v1.1.0/src/modal/modal.js#L165
element.on('click', scope.close);

documentに登録する方法だとこんな感じでしょうか。

class Controller {

  closeHandler: () => void;

  /*@ngInject*/
  constructor(
    private $document: ng.IDocumentService,
    private $element: ng.IAugmentedJQuery,
    private $scope: ng.IScope
    ) {
  }

  $onInit() {
    this.closeHandler = () => {
      this.close();
      this.$scope.$apply();
    };
    this.$element.on('click', ($event) => {

      // this.$document.on を無効にするため
      $event.stopPropagation();
    });
  }

  $onDestroy() {
    this.close();
  }

  open() {

    // 何かの処理
    // ...

    this.$document.on('click', this.closeHandler);
  }

  close() {

    // 何かの処理
    // ...

    this.$document.off('click', this.closeHandler);
  }
}

const components: ng.IComponentOptions = {
  templateUrl: 'foo.html',
  controller: Controller,
  bindings: {}
};

export default components;