15
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

KnockoutJSでリストの絞り込みとテキストのハイライトを行う

Last updated at Posted at 2014-09-15

動機

リストの絞り込みのサンプルはあったし、テキストをハイライトするサンプルも見つかった。
しかし両方をこなしているサンプルが見つからなかったから作ってみた。

前提

  • データ取得は別なのでデータとなる配列はべた書き
  • 絞り込み時には大文字小文字を区別しない

コード

HTML

index.html
<div class="content">
    <label>検索:
        <input type="text" class="input_highlight" data-bind="value: searchBrand, valueUpdate: 'afterkeydown'">
    </label>

    <ul data-bind="highlightForeach: {data: filteredBrands, search: searchBrand}">
        <li>
            <a data-bind="attr: {href: url}">
                <span data-bind="html: name"></span>
                <span data-bind="html: alias"></span>
            </a>
        </li>
    </ul>
</div>

JavaScript

main.js
ko.bindingHandlers.highlightForeach = {
    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
        ko.bindingHandlers.foreach.init(element, function () { return []; }, allBindings, viewModel, bindingContext);
    },

    update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
        var options = valueAccessor();
        var search = ko.utils.unwrapObservable(options.search);

        var highlight = ko.utils.unwrapObservable(options.data).map(function(value, index) {
            var name, alias;
            if (search.length > 0) {
                name = value['name'].replace(new RegExp(search, 'gi'),  '<span class="yellow">' + '$&' + '</span>');
                alias = value['alias'].replace(new RegExp(search, 'gi'),  '<span class="yellow">' + '$&' + '</span>');
            } else {
                name = value['name'];
                alias = value['alias'];
            }

            return { url: value['url'], name: name, alias: alias};
        });

        ko.bindingHandlers.foreach.update(element, function() { return highlight; }, allBindings, viewModel, bindingContext);
    }
};

var vm = function() {
    var self = this;
    self.searchBrand =  ko.observable('');
    self.brands = ko.observableArray([
        {url: "http://www.sony.jp/", name: "ソニーモバイルコミュニケーションズ", alias: "SONY MC"},
        {url: "http://www.samsung.com/jp/", name: "サムスン電子", alias: "Samsung"},
        {url: "http://www.htc.com/jp/", name: "エイチティーシー", alias: "HTC"},
        {url: "http://www.lg.com/jp", name: "LGエレクトロニクス", alias: "LG Electronics"},
        {url: "http://www.asus.com/jp/", name: "アスース", alias: "ASUSTek"},
        {url: "http://www.huawei.com/jp/", name: "ファーウェイ", alias: "Huawei"},
        {url: "http://www.motorola.co.jp/", name: "モトローラ・モビリティ", alias: "Motorola Mobility"},
        {url: "http://www.sharp.co.jp/", name: "シャープ", alias: "SHARP"},
        {url: "http://jp.fujitsu.com/", name: "富士通", alias: "FUJITSU"},
        {url: "http://www.kyocera.co.jp/", name: "京セラ", alias: "KYOCERA"},
        {url: "https://www.apple.com/jp/", name: "アップル", alias: "Apple"},
        {url: "http://www.nokia.com/global/", name: "ノキア", alias: "Nokia"}
    ]);

    self.filteredBrands = ko.computed(function() {
        var filter = self.searchBrand().toLowerCase();
        if (!filter) {
            return self.brands();
        } else {
            return ko.utils.arrayFilter(self.brands(), function(brand) {
                if (brand['name'].toLowerCase().indexOf(filter) !== -1) {
                    return true;
                } else if (brand['alias'].toLowerCase().indexOf(filter) !== -1) {
                    return true;
                }

                return false;
            });
        }
    });
};
ko.applyBindings(new vm());

簡単な解説

HTMLもJavaScriptも大きく2つに分けられる。
filteredBrandsの部分とhightlightForeachの部分である。

self.filteredBrandsではdata-bind="value: searchBrand”としているsearchBrandの値を見て、空であれば元々の値を、そうでなければko.utils.arrayFilterを使ってフィルタリングを行っている。
ko.utils.arrayFiltertrueが返った要素のみko.computedによって表示が行われる。

ko.bindingHandlers.highlightForeachではKnockoutJSにあるforeachを拡張する形で新たなハンドラを定義している。
updatesearchBrandが更新された際にupdateが呼ばれ、highlightという値でfoeachでループを回す前に値
を正規表現で置き換えしている。

動作例

JSFiddleを使って動かせるようにしてみた。
http://jsfiddle.net/nana4gonta/t85ywshv/

参考資料

15
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?