質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

  • C#

    7662questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Visual Studio

    1977questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • Webサイト

    1125questions

    一つのドメイン上に存在するWebページの集合体をWebサイトと呼びます。

  • ASP.NET MVC Framework

    69questions

    ASP.NET MVC Frameworkは、MVCパターンをベースとした、マイクロソフトのウェブアプリケーション開発用のフレームワークです。

  • Razor

    22questions

    RazorはASP.NET Web PagesとASP.NET MVCで使われているビュー・エンジンです。HTMLマークアップとC#またはVisual Basicのコードに対応しています。マークアップとコードの間の切り替えは"@"で記されています。

Ajax.BeginFormでの部分ビュー更新について

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,383

nepia

score 5

いつもお世話になっております。
ASP.NET MVCの部分ビューの動的更新について、皆様のお力をお貸しいただきたいです。

開発環境
OS : Windows10
.NET FrameWork : 4.5.2
Visual Studio : 2015 Professonal
Visual Studioプロジェクト : ASP.NET Web Application(.NET FrameWork)
プロジェクトテンプレート : MVCを指定
実行環境 : IIS(Visual Studioでの実行時)
Ajax.BeginFormを使用する為の参照設定 : NuGet => Microsoft.jQuery.Unobtrusive.Ajax 3.2.5
JQueryの読込も正しく行っております。

現在、以下のソースにて、問題が発生しております。

Test/Index.cshtml

<div>
    @Html.Partial("_List", Model)
</div>

Test/_List.cshtml

@using BootstrapSite1.Models.Test
@model TestViewModel 

@using (Ajax.BeginForm("Delete", "Test",
                                        new AjaxOptions
                                        {
                                            InsertionMode = InsertionMode.Replace,
                                            HttpMethod = "POST",
                                            UpdateTargetId = "system-list",

                                        }))
{
    <table>
        <tr>
            <th>id</th>
            <th>name</th>
            <th>削除</th>
        </tr>
        @for(int i = 0; i < Model.SystemList.Count; i++)
        {
            <tr>
                <td>
                    @Html.DisplayFor(m=>m.SystemList[i].Id)
                    @Html.HiddenFor(m=>m.SystemList[i].Id)
                </td>
                <td>@Html.TextBoxFor(m=>m.SystemList[i].Name)</td>
                <td>
                    <button type="submit" name="idx" value="@i">削除</button>
                </td>
            </tr>
        }
    </table>
}

Model

using System.Collections.Generic;
using System.Data;
using System.Text;

namespace BootstrapSite1.Models.Test 
{
    public class SystemModel
    {
        public int Id { get; set; }

        public string Name { get; set; }

    }
    public class TestViewModel 
    {
        public List<SystemModel> SystemList { get; set; }

        public TestViewModel ()
        {
            this.SystemList = new List<SystemModel>();
        }

        public void SetSystemList()
        {
            this.SystemList.Add(new SystemModel { Id = 1, Name = "1" });
            this.SystemList.Add(new SystemModel { Id = 2, Name = "2" });
            this.SystemList.Add(new SystemModel { Id = 3, Name = "3" });
        }
}

Controller

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

namespace BootstrapSite1.Controllers
{
    public class TestController: Controller
    {
        public ActionResult Index()
        {
            TestViewModel model = new TestViewModel ();
            model.SetSystemList();
            return View(model);
        }

        public PartialViewResult Delete(TestViewModel model, int idx)
        {
            List<SystemModel> list = model.SystemList;
            list.RemoveAt(idx);
            model.SystemList = list;
            return PartialView("_List", model);
        }
    }
}

上記のソースを実行した場合、画面には以下の表が表示されます。

id name 削除
1 1 削除
2 2 削除
3 3 削除

しかし、1行目の削除ボタンを実行するした場合

id name 削除
2 1 削除
3 3 削除

上記の様に、部分的に再描画されますが、
@Html.HiddenForまたはTextBoxForなど出力している箇所が、前回の値を参照してしまっているような状態です。
部分ビュー出力時にデバックで追いかけても前回データはModelから削除されている為、前回値が表示されるのが何故か理解できません。

どうすれば、ビューが正しく更新されますでしょうか。

よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2018/07/03 11:52

    意味不明の名前が多々あるのですが・・・ アクションメソッド public ActionResult Index() に対するビューが「View」で、「View」のコードの @Html.Partial("_List", Model) の _List が「部分View」、Model がアクションメソッドの return View(model); の model ですか?

    キャンセル

  • SurferOnWww

    2018/07/03 11:55

    「Ajax.BeginFormを使用する為の参照設定 : NuGet => Microsoft.jQuery.Unobtrusive.Ajax 3.2.5」とのことですが、NuGet パッケージのインストールだけでなく、参照設定も jQuery 都の順番などを含めて間違いなくされていると理解して良いですか?

    キャンセル

  • nepia

    2018/07/03 13:52

    上記のご指摘の件、修正させて頂きました。また、JQueryの読み込み順序もAJaxとして非同期更新が可能なので、問題ないと思われます。

    キャンセル

回答 1

checkベストアンサー

+1

上記のご指摘の件、修正させて頂きました。

まだはっきりしませんが、上の質問に対する先の私のコメント、

アクションメソッド public ActionResult Index() に対するビューが「View」で、「View」のコードの @Html.Partial("_List", Model) の _List が「部分View」、Model がアクションメソッドの return View(model); の model ですか? 

・・・は合っていると理解してレスしておきます。理解が違っていたらどこがどう違うか連絡ください。

たぶん ajax 呼び出しになっていないと思いますが、そこは今回の問題、

@Html.HiddenForまたはTextBoxForなど出力している箇所が、前回の値を参照してしまっているような状態です。

・・・には直接の関係はなさそうなのでちょっと置いときます。(後述します)

[削除]ボタンをクリックした結果で、何故 LabelFor と HiddenFor / TextBoxFor の値が違うかは以下の記事に書いてある通りの理由だと思います。

EditorFor と DisplayFor の違い
http://surferonwww.info/BlogEngine/post/2013/03/27/editorfor-and-displayfor-display-different-values.aspx

HiddenFor / TextBoxFor については、POST された値が ModelState ディクショナリ(model ではない)に格納されていて、Html Helper はまず ModelState ディクショナリを調べて、そこに値があればそれを表示するようになっています。

上の記事にも書いてありますが、試しに Delete アクションメソッドに以下のコードを追加してみてください。(これを解決策としていいかどうかは別の話ですよ)

if (ModelState.IsValid)
{
    ModelState.Clear();
}


これで期待通りになれば上の記事の話が当たりです。

そこが解決できても ajax 呼び出しになっていなそうな点と、Ajax.BeginForm の使い方が正しくない点は訂正が必要だと思います。

また、JQueryの読み込み順序もAJaxとして非同期更新が可能なので、問題ないと思われます。

とのことですが、動いているように見えるだけで ajax を使って非同期更新はできてない様な気がします。

NuGet パッケージのインストールだけでなく、参照設定もきちんとしないとダメです。以下の記事に書いてるように BundleConfig.cs への登録と View での @Scripts.Render("~/bundles/xxx") の追加が必要ですが、きちんとやってますか?

MVC5 で AjaxHelper が働かない
http://surferonwww.info/BlogEngine/post/2018/05/28/ajaxhelpers-do-not-work-on-mvc5-application-created-by-visual-studio-template.aspx

それから、Test/_List.cshtml での Ajax.BeginForm の使い方ですが、UpdateTargetId = "system-list" で指定される部分が書き換わるので、そこをきちんと書かないとダメです。

質問者さんの例では Test/_List.cshtml のコードの table 要素全体を <div id="system-list"> ... </div> で囲うというようにしないと期待した結果は得られないはずです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/03 14:52

    ありがとうございました!
    ModelState.Clear()処理を記入することで、期待通りの動作となりました。

    キャンセル

  • 2018/07/04 00:46

    TextBoxに入力した値が初期化されると言われて困る気がする

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • C#

    7662questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Visual Studio

    1977questions

    Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

  • Webサイト

    1125questions

    一つのドメイン上に存在するWebページの集合体をWebサイトと呼びます。

  • ASP.NET MVC Framework

    69questions

    ASP.NET MVC Frameworkは、MVCパターンをベースとした、マイクロソフトのウェブアプリケーション開発用のフレームワークです。

  • Razor

    22questions

    RazorはASP.NET Web PagesとASP.NET MVCで使われているビュー・エンジンです。HTMLマークアップとC#またはVisual Basicのコードに対応しています。マークアップとコードの間の切り替えは"@"で記されています。