Re:インクリメンタルサーチをjQueryで実装

http://moto-mono.net/2009/07/03/incremental-search-with-jquery.html

これを自分なりに実装してみる。

ソースコード

あんまり変え過ぎるのもアレなので、全体の流れは元記事のサンプルと同じにした。

jQuery(function($) {

    // 対象のtr達
    var tr = $('tr', '#item_table tbody');

    // 入力がある度評価
    $('#incrementalSearch').keyup(function() {
        // 検索クエリ
        var query = $(this).val()
            // 前後の空白文字をトリムして、
            .replace(/^\s+|\s+$/g, '')
            // 1個以上の空白文字を半角スペースにして、
            .replace(/\s+/g, ' ')
            // 半角スペースで区切って配列化
            .split(' ');

        // 検索クエリが無ければtrを全部表示して終了
        if (query[0] === '') {
            tr.show();
            return;
        }

        // コレくらいの単純処理ならeachで回してもいいよね?いいよね!
        // しかもeachで回すと無条件にjQueryっぽくなるおまけ付き!(主観)
        tr.each(function() {
            // 現在のtr
            var self = $(this);
            // 商品名
            var itemName = $('td:nth-child(2)', self).text();
            // 検索クエリの数だけ回す
            for (var i = 0, len = query.length; i < len; i++) {
                // 検索クエリにマッチしなかったら非表示にして次のtrへ
                if (!itemName.match(new RegExp(query[i], 'i'))) {
                    self.hide();
                    return;
                }
            }
            // 検索クエリ全てにマッチしたら表示
            self.show();
        });
    });

});

変更点

検索クエリの処理

要らない部分を消してから分割。

  1. 入力文字列の前後の空白文字は要らないので消す
  2. 半角スペースの連続は空要素がモリモリ増えちゃうので一個にする
    • ついでに他の空白文字(全角スペースとかタブ文字とか)も半角スペースにする
  3. 最後にモリっと分割

2番目のタイミングで、半角スペース以外の空白文字で区切っても検索出来るようになる。

対象要素をeachで回す

対象要素はjQueryオブジェクトだからeachで回したかった。それだけ><

ifのネストは避けれたら避けたい

条件分岐をネストすると、たいていの場合見難くなる。

ネストを避けれそうなら避けた方がいいような気がした。

プログラミングに正解は無い

状況ごとの正解(デファクトスタンダード)はあるけど、「Aの仕様ならBのように書かなければならない」と言うのは無いと思う。

だから皆さんも気張らずにドンドン書いてドンドン公開しちゃいましょう!

公開したコードは誰かの役に立つかも知れないし、運が良ければ誰かが添削してくれるかも知れないですよ!

おまけ

OR検索の場合は多分最後を反対にすればいける。

// 検索クエリの数だけ回す
for (var i = 0, len = query.length; i < len; i++) {
    // 検索クエリにマッチしたら表示して次のtrへ
    if (itemName.match(new RegExp(query[i], 'i'))) {
        self.show();
        return;
    }
}
// 検索クエリ全てにマッチしなかったら非表示
self.hide();

JavaScript面白い。

JavaScriptで10の練習問題 #6

ちょっと間があいてしまったけど続きを。

テキストを入れると語尾が赤ちゃん言葉に

「語尾が」って言うのが難易度を一気に上げている。

ちょっと面倒なので、さ行を全部変換する感じで行ってみよう。

function BabyTalk() {
    /**
     * 'さ' : 'ちゃ',
     * 'す' : 'ちゅ',
     * 'せ' : 'ちぇ',
     * 'そ' : 'ちょ',
     * 'し' : 'ち'
     */
    this.words = {
        '\u3055' : '\u3061\u3083',
        '\u3059' : '\u3061\u3085',
        '\u305b' : '\u3061\u3047',
        '\u305d' : '\u3061\u3087',
        '\u3057' : '\u3061'
    }
}
BabyTalk.prototype = {
    setWords : function (words) {
        this.words = words;
    },
    baby : function (str) {
        for (var word in this.words)
            str = str.replace(eval('/'+ word +'/g'), this.words[word]);
        return str;
    },
    adult : function (str) {
        for (var word in this.words)
            str = str.replace(eval('/'+ this.words[word] +'/g'), word);
        return str;
    }
}

逆の変換で行けば 元の言葉に戻せるんじゃないかと思って adult を付けたけど、原文に ちゃ、ち、ちゅ、ちぇ、ちょ が含まれてるとお終いですね。

余談

育児で今回の赤ちゃん言葉(ちゃ、ち、ちゅ、ちぇ、ちょ)を使うのは、言葉の発育に良く無いので使わない方がいいですよ。

JavaScriptで10の練習問題 #5

キーワードを入れてYahoo!の検索結果を出力

究極に楽をするならiframeのsrcに検索クエリ付きのURLを渡す。
でも、それではあまり勉強にならないので、今回はJSONPを使ってみることにする。
Yahoo Developer NetworkAPIキーを取得して開始。

function yahooSearch(apiKey) {
    this.apiKey = apiKey;
}
yahooSearch.prototype = {
    init: function () {
        var self = this;
        self.form   = document.MyForm;
        self.input  = self.form.text;
        self.submit = self.form.submit;
        self.view   = document.getElementById('view');
        self.form.onsubmit = function () {
            self.jsonp();
            return false;
        };
    },
    param: function () {
        return [
            'http://api.search.yahoo.com/WebSearchService/V1/webSearch',
            '?appid='+ encodeURIComponent(this.apiKey),
            '&results=10',
            '&format=html',
            '&language=ja',
            '&output=json',
            '&callback=callbackFunc',
            '&query='+ encodeURIComponent(this.input.value)
        ].join('');
    },
    jsonp: function () {
        // submitを無効にする
        this.submit.disabled = true;
        // <script type="text/javascript" src="Request URL"></script>をねじ込む
        var script = document.createElement('script');
        script.setAttribute('type', 'text/javascript');
        script.setAttribute('src', this.param());
        document.body.appendChild(script);
    },
    render: function (r) {
        // 例外処理とか適当
        if (r.Error) {
            this.view.innerHTML = 'Error: 検索結果がありません!';
            this.submit.disabled = false;
            return false;
        }
        // 表示
        var items = r.ResultSet.Result;
        var array = [];
        for (var i = 0, len = items.length; i < len; i++) {
            array[i] = '<a href="'+ items[i].Url +'">'+ items[i].Title +'</a>';
        }
        this.view.innerHTML = array.join('<br>');
        // submitを有効にする
        this.submit.disabled = false;
    }
}

var study_05 = new yahooSearch('API Key');

window.onload = function () {
    (function () {
        study_05.init();
    })();
}

// この関数で受け取る
function callbackFunc(r) {
    (function () {
        study_05.render(r);
    })();
}

JSONPって名前だけしか知らなかったけど、こう言うことだったんですね。
面白い。

今回使用したHTML

<form name="MyForm">
  <input type="text" name="text" value="">
  <input type="submit" name="submit" value="検索">
</form>
<div id="view"></div>

JavaScriptで10の練習問題 #4

簡易電卓

0で割ったときの処理を作り込むのは、本質的では無いのでやめておく。

function Calculator(display) {
    this.display = display;
    this.display.value = 0;
    this.input  = 0;
    this.total  = 0;
    this.tmpOpe = '';
    this.tFlag  = false;
}
Calculator.prototype = {
    setEvent : function (item) {
        switch (item.value) {
            case '+':
            case '-':
            case '*':
            case '/': this.eventOperator(item.value); break;
            case '=': this.eventTotal(); break;
            case 'C': this.eventAllClear(); break;
            default:  this.eventNumber(item.value);
        }
    },
    eventNumber : function (v) {
        if (v == 0 && this.input == 0) {
            return;
        }
        this.input = this.input == 0 ? v : this.input + v;
        this.display.value = this.input;
    },
    eventOperator : function (v) {
        if (this.input) {
            this.total = this.tmpOpe ? this.getTotal() : this.input;
        }
        this.input = '';
        this.tmpOpe = v;
        this.display.value = this.total;
    },
    eventTotal : function () {
        if (this.tmpOpe === '') {
            return;
        }
        this.display.value = this.total = this.getTotal();
        this.input  = 0;
        this.tFlag  = true;
    },
    eventAllClear : function () {
        this.display.value = this.input  = 0;
        this.total  = 0;
        this.tmpOpe = null;
    },
    getTotal : function () {
        var total = Number(this.total);
        var input = Number(this.input);
        return this.tmpOpe === '+' ? total + input
             : this.tmpOpe === '-' ? total - input
             : this.tmpOpe === '*' ? total * input
             : this.tmpOpe === '/' ? total / input
             : this.display.value;
    }
}

var study_04 = function () {
    var calc  = new Calculator(document.getElementById('calcDisplay'));
    var items = document.getElementById('calc').getElementsByTagName('button');
    for (var i = 0, len = items.length; i < len; i++) {
        items[i].onclick = function () { calc.setEvent(this); }
    }
}

オブジェクトとprototypeを何となく理解したので使ってみた。

小数点が無かったり電卓としては不便だけど、この練習問題で得たものは多かったので良し。

今回使ったHTML

<div><input type="text" id="calcDisplay" value=""></div>
<table id="calc">
	<tbody>
		<tr>
			<td><button value="7">7</button></td>
			<td><button value="8">8</button></td>
			<td><button value="9">9</button></td>
			<td><button value="*">×</button></td>
		</tr>
		<tr>
			<td><button value="4">4</button></td>
			<td><button value="5">5</button></td>
			<td><button value="6">6</button></td>
			<td><button value="/">÷</button></td>
		</tr>
		<tr>
			<td><button value="1">1</button></td>
			<td><button value="2">2</button></td>
			<td><button value="3">3</button></td>
			<td><button value="-"></button></td>
		</tr>
		<tr>
			<td><button value="0">0</button></td>
			<td><button value="C">C</button></td>
			<td><button value="=">=</button></td>
			<td><button value="+"></button></td>
		</tr>
	</tbody>
</table>

JavaScriptで10の練習問題 #3

複数の数値を入力させ、昇順に並び替え、最大値と最小値を出す

var study_03 = function () {
    document.getElementById('MyForm').onsubmit = function () {
        var result = [],
            length = this.elements.length;
        // フォームの値取得
        for (var i = 0; i < length; i++) {
            var item  = this.elements[i],
                value = Number(item.value);
            // テキストフィールドの値が数値で0より大きい
            if (item.type === 'text' && value > 0) {
                result.push(value);
            }
        }
        // 結果が0
        if (result.length === 0) {
            alert('数値を入力して下さい。');
            return false;
        }
        // 昇順ソート
        result.sort(function (a, b) {
            return a - b;
        });
        // 結果
        alert(result);
        alert("[max]"+ result.pop() +"\n[min]"+ result[0]);
        return false;
    };
};
  1. form#MyFormのinputから値を動的取得
  2. Numberで数値にして、0より大きいかどうかの比較でNaNも同時に見分ける
  3. 後はソートして最高値と最小値を表示して終わり

数値に変換できる値なら全て通るので16進数(0x0000FFなど)も通る。

2進数や8進数はそのまま10進数になる。

だんだん解ってきたので楽しくなってきました。次も頑張りたいと思います。

JavaScriptで10の練習問題 #2

前回に引き続き、言語習得用の練習問題。

現在時刻にあわせてやる気のでるメッセージを出力

やる気のでるメッセージを考えるのが億劫なので、とある1日の行動記録を時間別に出力。

var study_02 = function () {
    var msg = [];
    msg[8]  = '8時:起床';
    msg[9]  = '9時:出社';
    msg[19] = '19時:退社';
    msg[20] = '20時:夕飯';
    msg[22] = '22時:何かしらの作業に入る';
    msg[23] = '23時:頑張る';
    msg[0]  = '0時:コーヒーを入れて頑張る';
    msg[1]  = '1時:まだ頑張る';
    msg[2]  = '2時:まだまだ頑張る';
    msg[3]  = '3時:まだまだまだ頑張る';
    msg[4]  = '4時:歯を磨いて寝る';
    var date = new Date();
    var now  = date.getHours();
    alert(msg[now] ? msg[now] : '寝てるか仕事中');
};

new Arrayで配列のインスタンス作るのと[]だけでやるのって、文字数以外に違いがあったりするのだろうか。

まぁ、この辺の細かい部分はおいおいということで。

JavaScriptで10の練習問題 #1

言語習得用の練習問題を、JavaScriptで出来るところだけ(仕様的な意味で)やってみます。

新しくプログラミング言語を覚えたいときに行うべき10の練習問題

自分ルール

  • 実行速度は気にしない・最適化しない
  • コードの短さ・綺麗さは気にしない
  • ネタ元の練習問題はあくまでもネタ元

こんな感じでゆる〜く。

まずは、一つ目

ナベアツに似ている。取り敢えずナベアツがやってみたいのでナベアツにする。

3の倍数と3が付く数字の時にアホになるオーソドックスなタイプ(数字は40で終る)。

  • ループで1〜40まで回す
  • 数値を文字列にせず頑張る
  • 2パターン考える

こんな感じでいってみましょー。

1.配列で無理やり感タップリなパターン
var study_01_a = function () {
    var ahos = [], str = '';
    ahos[3]  = 'さぁ〜ん';
    ahos[6]  = 'ろぉ〜く';
    ahos[9]  = 'きゅ〜う';
    ahos[12] = 'じゅ〜に';
    ahos[13] = 'じゅ〜さん';
    ahos[15] = 'じゅ〜ご';
    ahos[18] = 'じゅ〜はち';
    ahos[21] = 'にっじゅいち';
    ahos[24] = 'にっじゅし';
    ahos[27] = 'にっじゅなな';
    ahos[30] = 'さ〜んじゅ〜';
    ahos[31] = 'さ〜んじゅいち';
    ahos[32] = 'さ〜んじゅに';
    ahos[33] = 'さ〜んじゅさん';
    ahos[34] = 'さ〜んじゅし';
    ahos[35] = 'さ〜んじゅご';
    ahos[36] = 'さ〜んじゅろく';
    ahos[37] = 'さ〜んじゅしち';
    ahos[38] = 'さ〜んじゅはち';
    ahos[39] = 'さ〜んじゅきゅ';
    ahos[40] = 'よんじゅ〜!';
    for (i = 1; i <= 40; i++) {
        str += (ahos[i] ? ahos[i] : i) +"\n";
    }
    alert(str);
};

個人的にはこれがしっくり来る。

2.40以下が絶対条件のパターン
var study_01_b = function () {
    var aho, str = '';
    for (i = 1; i <= 40; i++) {
        aho = i - 30 >= 0 && i - 30 <= 9 ? 'すーぱーあほたいむ'
            : i % 3 == 0                 ? '倍数のあほ'
            : i - 10 == 3 || i - 20 == 3 ? '3が付くあほ'
            : '';
        str += i +':'+ aho +"\n";
    }
    alert(str);
};

40以下じゃないと即破綻する。


こんな感じで次回も頑張ってみたいと思います。