💻

knockout.js でページの再読み込みに対応する

2022/01/01に公開

はじめに

前回の記事の続きです。

https://zenn.dev/karamem0/articles/2012_07_19_000000

前回の状態だと、ページを再読み込みすると、検索結果がすべて消えて初期状態に戻ってしまうという問題点がありました。それではやはり使い勝手が悪いので、修正してみます。簡単に言ってしまうと、データをどこかに保存しておけばいいのですが、今回はサーバー側に保存します。

実装方法

Controllers/HomeController.cs

前回からの変更点として、検索されたときにパラメーターをセッションに入れているのと、初期表示でセッションにデータがあれば ViewBag に入れるところが追加されています。

public class HomeController : Controller
{

    public ActionResult Index()
    {
        // セッションがあれば ViewBag に入れる
        var person = this.Session["Person"] as Person;
        if (person != null)
        {
            this.ViewBag.Person = person;
        }
        return View();
    }

    [HttpPost()]
    public JsonResult Index(Person person)
    {
        // パラメーターをセッションに格納する
        this.Session["Person"] = person;

        var data = new[]
        {
            new Person() { Id = "1", Name = "佐藤太郎", Age = 30, },
            new Person() { Id = "2", Name = "山田次郎", Age = 15, },
            new Person() { Id = "3", Name = "高橋三郎", Age = 60, },
            new Person() { Id = "4", Name = "田中四郎", Age = 55, },
            new Person() { Id = "5", Name = "鈴木五郎", Age = 45, },
        };
        return this.Json(
            data.Where(x => string.IsNullOrEmpty(person.Id) || x.Id == person.Id)
                .Where(x => string.IsNullOrEmpty(person.Name) || x.Name.Contains(person.Name))
                .Where(x => person.Age == null || x.Age == person.Age)
        );
    }
}

Views/Home/Index.cshtml

ViewBag に入れられたパラメーターを Json.Encode ヘルパーメソッドで JavaScript から読めるようにします。あとはそれをフォームに突っ込んで再検索します。

<script type="text/javascript">
    $(function () {
        var viewModel = {
            items: ko.observableArray([]),
            search: function () {
                var self = this;
                var param = {};
                $("form :input").each(function () {
                    var name = $(this).attr("name");
                    var val = $(this).val();
                    param[name] = val;
                });
                var callback = function (data) {
                    self.items.removeAll();
                    $.each(data, function (i, e) {
                        self.items.push(e);
                    });
                };
                $.post("@Url.Action("Index")", param, callback, "json");
            }
        };
        ko.applyBindings(viewModel);

        // ViewBag からデータをもらう
        var person = @Html.Raw(Json.Encode(ViewBag.Person));
        if (person != null) {
            // フォームにデータを入れる
            $("form :input").each(function () {
                var name = $(this).attr("name");
                var val = person[name];
                if (val != null) {
                    $(this).val(val);
                }
            });
            // 再検索
            viewModel.search();
        }
    });
</script>

おわりに

これで再読み込みをしても元の状態を復元できました。

Discussion