【Javascript】select要素の開いた/閉じたイベントを実装した話
はじめに
前回の記事の続き
前回の話は、セレクトボックスを選択した時(値が決まった時)にモーダルを表示するという機能を作成したけれども、
onchangeイベントを使っていたため、同じ値を選択したときにモーダルが表示されない問題点があった。
調べてみてもあまりコレだ!とくる内容のサイト・記事が見つからなかった
なので、セレクトボックスに「開かれた」、「閉じた」、「値が変わらなかった」という独自イベントを作成した話
実装
動作するイベントを調べた結果、「開くとき」に発生するイベントは「click」で「閉じるとき」に発生するイベントは「click blur keyup」ということがわかった(Chromeで調査)
今回はjQueryとAngularJSを使って実装
HTML
<div ng-app="App" ng-controller="Sample"> <select ng-model="Sample.selectValue" ng-select-event expanded="Sample.onOpened()" unexpanded="Sample.onClosed()" nonchanged="Sample.onNonChanged()" ng-change="Sample.onChanged()"> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> {{Sample.selectValue}} </div>
Javascript(jQuery、AngularJS)
(function(window, jQuery, angular) { 'use strict'; var module = angular.module('App', []); module.controller('Sample', [ '$scope', function($scope) { $scope.Sample = this; this.selectValue = '1'; this.onOpened = function() { window.console.log('おーぷん'); }; this.onClosed = function() { window.console.log('しまった'); }; this.onChanged = function() { window.console.log('変わった'); }; this.onNonChanged = function() { window.console.log('変わってない'); }; } ]); /** * 普通のselect要素では、「リストボックスが開かれた」、「リストボックスが閉じた」、 * 「値が変わらなかった」等のイベントが無いため作成 * * 以下のイベントを発生させる * ・リストボックスが開かれた * ・リストボックスが閉じた * ・値が変わらなかった */ module.directive('ngSelectEvent', [ '$timeout', function($timeout) { return { restrict: 'A', scope: { expanded: '&', unexpanded: '&', nonchanged: '&' }, link: function(scope, element, atts, ctrl) { var jQueryElement = jQuery(element); var WATCH_EXPAND_EVENTS = 'click'; var WATCH_UNEXPAND_EVENTS = 'click blur keyup'; jQueryElement.data('expanded', false); var __expanding = function() { jQueryElement.off(WATCH_EXPAND_EVENTS, __expanding); jQueryElement.data('expanded', true); jQueryElement.data('oldvalue', jQueryElement.val()); jQueryElement.on(WATCH_UNEXPAND_EVENTS, __unexpanding); (scope.expanded)(); }; var __unexpanding = function() { jQueryElement.off(WATCH_UNEXPAND_EVENTS, __unexpanding); jQueryElement.data('expanded', false); jQueryElement.on(WATCH_EXPAND_EVENTS, __expanding); (scope.unexpanded)(); var oldValue = jQueryElement.data('oldvalue'); $timeout(function() { var newValue = jQueryElement.val(); if (oldValue == newValue) { (scope.nonchanged)(); } }, 0); }; jQueryElement.on(WATCH_EXPAND_EVENTS, __expanding); } }; } ]); })(window, window.jQuery, window.angular);
今後の自分のためにも、AngularJSを使用しないソースコードも作ろうと思ったけど面倒くさくなったでござる
問題点?
見直しでjsfiddleで動作確認したところ、「ESC」キーを押したときの挙動がイマイチかも
「ESC」キー押してもイベントが走るように、「keyup」イベントを監視するようにしているけれども、2回押さないと反応してくれない・・・
他のキー(数字の1とか)を押した後だと、1回でイベントが呼ばれる感じ
keyupイベントは別処理にして、押されたキーのチェックをしたほうが良いかもしれない