前回でひとまず並べ替えができたので、検索機能(フィルタ機能)をつけてみます。

codeprojectのサンプルだと、フィールド毎のフィルタリングをしているようですが、こういう検索ってあんまり使わないんですよねー。検索ボックスひとつで主要なフィールドを検索してくれたほうが都合が良い事が多い気がします。

今回は、検索ボックスひとつだけパターンで実装します。(けっしてめんどくさいわけではありません)

controller

検索とか言っても、要はLINQのWhere句を足すだけなので、

ロジックはcontrollerをちょっと変更するだけです。

(ほんとはレポジトリクラスとかでやるのかな)

1
2
3
4
5
6
7
8
public ActionResult Index(string sort,string filter)   //filter追加
        {
            var query = db.Articles.AsQueryable();  //データソース
            // filterロジック
            if(!string.IsNullOrEmpty(filter)) {
                query = query.Where(a => a.Title.Contains(filter) || a.Description.Contains(filter));
            }
 ...

actionの引数にfilterを追加して、データソースとなるクエリにwhereを足してます。

検索対象はTitleとDeacription.

Viewには検索用のフォームを追加します。

1
2
3
4
5
@using (Html.BeginForm(new { sort = SortDef.SortKey })) {
    @Html.TextBox("filter","test")
    <input type="submit" value="search" />

}

動かすとかんな感じです。

Sortとfilterパラメータの保持

一見いけているように見えますが、ソートすると検索フィルタがクリアされてしまいます。

ソート用のActionLinkにフィルター情報が無いからですね。

ひとまずViewBagでフィルター情報をViewに渡すようにします。

controller

1
2
3
4
ViewBag.SortDef = sort_def;     //リンク作成用にソート定義を渡す
            ViewBag.InputedFilter = filter; //入力されたフィルター       ←追加
            return View(query.ToList());    //ソート済み結果をViewに返す。
        }

View

ViewではViewBagの内容をStringに詰め替えて各ソートリンクのrouteValueにセットします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
@{
    ViewBag.Title = "Index";
    SortDefinition<Article> SortDef = ViewBag.SortDef;   //型付け
    string InputedFilter = ViewBag.InputedFilter; //ユーザー入力フィルタ               ←追加
}

...
...
            @Html.ActionLink(
         Html.DisplayNameFor(model => model.Url).ToString(),
         "Index", new { sort = SortDef.GetNextSortKey(model => model.Url) , filter = InputedFilter})

一応、意図した動きをしているようですが、なんか書き方が冗長な気がします。

後でもう少し簡潔に書けるように変更するかも。

その前に、やる気が出たらページングを追加します。