Ajax【最後にonkeyupされてからn秒間次の入力が無かった場合にインクリメンタルサーチを実行】
インクリメンタル検索は、テキストボックスとかで文字を入力すると勝手にテキストボックスの下とかに表示される入力候補みたいなやつ。
これをwebで実装しようと企みました。(すでによくありますが)
環境は
クライアント:javascript(jqueryライブラリを使用します)
サーバー:php(今回は特に記載しません)
以降はjqueryをベースに書いていきます。
どのようにインクリメンタル検索を実装しているのか色々調べていると、IEとFirefoxのkeyupイベントの実行タイミングが違うからkeypressを使用するとか、focus中にsetIntervalで一定間隔で実行とか、エンターが押されたタイミングで実行するとかあったけど、自分がやりたかったのはこれ。
「キーが離されてからn秒間次のキーの入力が無かった場合に検索実行」
keyupの都度検索実行していたのではサーバーの負荷が心配。
keyupやkeypressを使い分けたり、keycodeを取ってくる処理は面倒だし今後のブラウザの仕様の変更によっては調べた努力が烏有と化す。
setIntervalを用いた一定間隔で実行するのはfocusの処理、blur時のclearIntervalの処理、focus放置プレーに備えて検索クエリの文字の変化が無かった場合は問い合わせないなどの処理が面倒くさい。
要は面倒くさがりなんです。。。
なのでちょっとラグがありますが、シンプルそうな上記方法でやろうと思います。
タイピングが早い人だと1秒間に5~8回、ゆっくりなひとでも1~2回ほどキーを入力できることを鑑みると、キーアップされてからまあお茶でも飲んで1秒ぐらい待ってもらってから検索結果を表示しましょうと独断で待ち時間を設定した。
早速その方法
function test($searchbox){ var me = this; this.$oj = $searchbox;//keyupイベントを設定するtextbox this.keyup_stack = [];//keyup時にpush、setTimeout時にpopを行うスタック this.bindShowCand = function(){ me.$oj.keyup(function(){ me.keyup_stack.push(1); setTimeout((function(me_){ return function(){ me_.keyup_stack.pop(); //以下が重要、スタックが空になったらサーバーへ問い合わせ実行 if(me_.keyup_stack.length == 0){ me_.showCandidate(); } }; })(me),1000);//1秒間待ち }); }; this.showCandidate = function(){ //ここにAjaxの処理を書いていく $.post(...); }; me.bindShowCand(); } var hoge = new test($(":text.searchbox"));
ポイントはスタックが空になったら実行するっていう処理。
keyupされるたびにスタックに1をpushしていきsetTimeoutで匿名関数が実行されるたびにpopしていく。まあこれならわざわざスタックにしなくてもスカラの数値のインクリメントとデクリメントを繰り返していっても同じことはできるが。
(ただし、最後かどうかを判定する入れ物が配列じゃないと、関数の引数に渡しても参照渡しにならないので、注意が必要かも)
オブジェクト指向でsetTimeoutから自身のメソッドやプロパティを呼び出す処理に苦戦したけどこれで希望通りの実装が出来た。
エクセルVBAからパワーポイントのオブジェクト型を宣言する
エクセル上のクロス集計表から1万個以上の円グラフを作ってそれをパワーポイントのひな形にはりつけてくれみたいな依頼があり、VBAでパワーポイントを操作した時のメモ。
VBAは本当によくわからないんだけど、こういった処理をやるにはやっぱ欠かせない。
エクセルVBAでグラフを作るまでの処理は、エクセル上でできるからいいとして、問題はパワーポイントをどうやってエクセルから操作するか。
まず参照設定でパワーポイントのオブジェクトライブラリーを参照する。
これは必須。これによりVBE上に入力候補が表示されるようになる。かつ、よりVBAぽい書き方ができるようになる。
参照設定をしないでCreateObjectを使ってもできるが、その場合は型の宣言や操作ができない。
まず、パワーポイントのインスタンスを作る。
Dim myppt As PowerPoint.Application
Set myppt = New PowerPoint.Application
ここでエラーがでるようなら参照設定が上手く行っていない。
そして次にプレゼンテーションの宣言
Dim mypst As Presentation
Set mypst = myppt.Presentations.Open("C:\User\xxxxxxx.pptx")
相対パスの場合はカレントディレクトリを参照する。
これでプレゼンテーションが立ち上がる。
この後ハマったのがエクセルVBAからのパワーポイントのオブジェクト型の宣言。
Shape型の宣言について
Dim myShape As Shape
としても例えば
For Each myShape In mypst.Slide(1).Shapes
でエラーとなる。
これは
Dim myShape As PowerPoint.Shape
とPowerPointをShapeの前に加える必要がある。
どうもいろいろ調べたところ参照設定でエクセルとパワーポイントのオブジェクトライブラリを参照しているから、エクセルのShapeか、パワーポイントのShapeかを区別しなくてはいけないらしい。
PresentationオブジェクトやSlideオブジェクトはパワーポイント特有のオブジェクトなので特に
Dim mypst As PowerPoint.Presentation
としなくても
Dim mypst As Presentation
でいいようだ。
もちろん前者でも問題ない。
これでエクセルからパワーポイントのオブジェクト型の操作ができるようになる。
よくわからない場合は
DIm myShape As Object
を使ってしまえば楽ちんなんだけど、いかにもパワーポイントのことはよく知りませんみたいな感じで嫌いなので。これでVBAぽく書ける。