web-dev-qa-db-ja.com

BeginCollectionItemを使用したMVC5動的行

ボタンがクリックされたときにテーブルに行を追加/削除するための最良の方法は何ですか? ChildClassプロパティから作成された行が必要です(子クラスはメインクラス/モデル内のリストです)。

現在、RenderPartialを使用して部分ビューを参照するビュー(モデルはMyMain)があります。

部分ビューには、モデルのプロパティが表示されます。これは、MyMain内のオブジェクトリストであるMyChildというクラスです。

部分ビュー内に保持されている行を動的に追加するための追加ボタンと削除ボタンが必要です。

したがって、リストの行を増やすためにMyChildを繰り返し追加します。これは可能ですか?または、これに部分的なビューを使用するべきではありませんか?

更新されたコード

以下は、現在使用しているクラスとビューです。BeginCollectionItemヘルパーを実装しようとしていますが、ifステートメントで新しいインスタンスを作成するように指示されているにもかかわらず、部分ビューをロードしようとするとnullrefが発生します。子クラスが存在しない場合、これが無視されるのはなぜですか?

メインビュー

    @using (Html.BeginForm())
{
    <table>
        <tr>
            <th>MyMain First</th>
            <th>MyChild First</th>
        </tr>
        <tr>
            <td>
                @Html.EditorFor(m => m.First)
            </td>
            <td>
                @if (Model.child != null)
                {
                    for (int i = 0; i < Model.child.Count; i++)
                    {
                        Html.RenderPartial("MyChildView");
                    }
                }        
                else
                {
                    Html.RenderPartial("MyChildView", new MvcTest.Models.MyChild());
                }       
            </td>
        </tr>
        @Html.ActionLink("Add another", "Add", null, new { id = "addItem" })
    </table>
}

部分図

@model MvcTest.Models.MyChild

@using (Html.BeginCollectionItem("myChildren"))
{
    Html.EditorFor(m => m.Second);
}

モデル

public class MyMain
{
    [Key]
    public int Id { get; set; }
    public string First { get; set; }
    public List<MyChild> child { get; set; }
}

public class MyChild
{
    [Key]
    public int Id { get; set; }
    public string Second { get; set; }
}

コントローラー

public class MyMainsController : Controller
{
    // GET: MyMains
    public ActionResult MyMainView()
    {
        return View();
    }

    [HttpPost]
    public ActionResult MyMainView(IEnumerable<MyChild> myChildren)
    {
        return View("MyMainView", myChildren);
    }

    public ViewResult Add()
    {
        return View("MyChildView", new MyChild());
    }
}
9
PurpleSmurph

更新された回答-元のコードは[〜#〜] not [〜#〜]「動的」に当てはまりますが、質問パラメータ内で行う必要のあるすべてのことを可能にします。

最初は、質問のコメントでスティーブンのBCIの提案を機能させることができませんでした。更新されたセクションの以下のコードは、コピーして貼り付けると機能しますが、GITからBCIを手動でダウンロードするか、Visual Studioのパッケージマネージャーコンソールで_PM> Install-Package BeginCollectionItem_を使用する必要があります。

複雑で、以前にMVCを実行したことがないため、BCIを使用するさまざまな点で問題が発生しました- ここclass.property(type class).property(type class).propertyへのアクセスの処理に関する詳細情報です。

元の回答-質問よりも明確な例を以下に示しましたが、すぐに混乱しすぎました。

2つの部分ビューを使用します。1つは従業員のリスト用で、もう1つは新しい従業員の作成用で、すべて会社のオブジェクトと従業員オブジェクトのリストを含むcompanyemployeeのビューモデルに含まれています。このようにして、複数の従業員をリストに追加、編集、またはリストから削除できます。

うまくいけば、この答えが似たようなものを探している人に役立つでしょう、これはそれを機能させるのに十分なコードを提供し、少なくとも正しい方向にあなたをプッシュするはずです。

コンテキストクラスとイニシャライザークラスは最初にコードにのみ当てはまるため、必要に応じて追加できるため、省略しました。

助けてくれたすべての人に感謝します。

モデル-ビューモデルであるCompanyEmployee

_public class Company
{
    [Key]
    public int id { get; set; }
    [Required]
    public string name { get; set; }
}

public class Employee
{
    [Key]
    public int id { get; set; }
    [Required]
    public string name { get; set; }
    [Required]
    public string jobtitle { get; set; }
    [Required]
    public string number { get; set; }
    [Required]
    public string address { get; set; }
}

public class CompanyEmployee
{
    public Company company { get; set; }
    public List<Employee> employees { get; set; }
}
_

インデックス

_@model MMV.Models.CompanyEmployee
@{
    ViewBag.Title = "Index";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<h2>Index</h2>
<fieldset>
    <legend>Company</legend>
    <table class="table">
        <tr>
            <th>@Html.LabelFor(m => m.company.name)</th>
        </tr>
        <tr>
            <td>@Html.EditorFor(m => m.company.name)</td>
        </tr>
    </table>
</fieldset>
<fieldset>
    <legend>Employees</legend>

        @{Html.RenderPartial("_employeeList", Model.employees);}

</fieldset>
<fieldset>
    @{Html.RenderPartial("_employee", new MMV.Models.Employee());}
</fieldset>
<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <input type="submit" value="Submit" class="btn btn-default" />
    </div>
</div>
_

従業員リストのPartialView

_@model IEnumerable<MMV.Models.Employee>
@using (Html.BeginForm("Employees"))
{
    <table class="table">
        <tr>
            <th>
                Name
            </th>
            <th>
                Job Title
            </th>
            <th>
                Number
            </th>
            <th>
                Address
            </th>
            <th></th>
        </tr>
        @foreach (var emp in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => emp.name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => emp.jobtitle)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => emp.number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => emp.address)
                </td>
                <td>
                    <input type="submit" formaction="/Employees/Edit/@emp.id" value="Edit"/>
                    <input type="submit"formaction="/Employees/Delete/@emp.id" value="Remove"/>
                </td>
            </tr>
        }
    </table>
}
_

Partial View Create Employee

_@model MMV.Models.Employee

@using (Html.BeginForm("Create","Employees"))
{
    <table class="table">

        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <tr>
            <td>
                @Html.EditorFor(model => model.name)
                @Html.ValidationMessageFor(model => model.name, "", new { @class = "text-danger" })
            </td>
            <td>
                @Html.EditorFor(model => model.jobtitle)
                @Html.ValidationMessageFor(model => model.jobtitle)
            </td>
            <td>
                @Html.EditorFor(model => model.number)
                @Html.ValidationMessageFor(model => model.number, "", new { @class = "text-danger" })
            </td>
            <td>
                @Html.EditorFor(model => model.address)
                @Html.ValidationMessageFor(model => model.address, "", new { @class = "text-danger" })
            </td>
        </tr>
    </table>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
}
_

Controller-複数使用しましたが、すべて1つにまとめることができます

_public class CompanyEmployeeController : Controller
{
    private MyContext db = new MyContext();

    // GET: CompanyEmployee
    public ActionResult Index()
    {
        var newCompanyEmployee = new CompanyEmployee();
        newCompanyEmployee.employees = db.EmployeeContext.ToList();
        return View(newCompanyEmployee);
    }

    [HttpPost, ActionName("Delete")]
    public ActionResult DeleteConfirmed(int id)
    {
        Employee employee = db.EmployeeContext.Find(id);
        db.EmployeeContext.Remove(employee);
        db.SaveChanges();
        return RedirectToAction("Index", "CompanyEmployee");
    }

    [HttpPost]
    public ActionResult Create([Bind(Include = "id,name,jobtitle,number,address")] Employee employee)
    {
        if (ModelState.IsValid)
        {
            db.EmployeeContext.Add(employee);
            db.SaveChanges();
            return RedirectToAction("Index", "CompanyEmployee");
        }

        return View(employee);
    }
}
_

更新されたコード-BeginCollectionItemを使用-動的な追加/削除

学生部分

_@model UsefulCode.Models.Person
<div class="editorRow">
    @using (Html.BeginCollectionItem("students"))
    {
        <div class="ui-grid-c ui-responsive">
            <div class="ui-block-a">
                <span>
                    @Html.TextBoxFor(m => m.firstName)
                </span>
            </div>
            <div class="ui-block-b">
                <span>
                    @Html.TextBoxFor(m => m.lastName)
                </span>
            </div>
            <div class="ui-block-c">
                <span>
                    <span class="dltBtn">
                        <a href="#" class="deleteRow">X</a>
                    </span>
                </span>
            </div>
        </div>
    }
</div>
_

ティーチャーパーシャル

_@model UsefulCode.Models.Person
<div class="editorRow">
    @using (Html.BeginCollectionItem("teachers"))
    {
        <div class="ui-grid-c ui-responsive">
            <div class="ui-block-a">
                <span>
                    @Html.TextBoxFor(m => m.firstName)
                </span>
            </div>
            <div class="ui-block-b">
                <span>
                    @Html.TextBoxFor(m => m.lastName)
                </span>
            </div>
            <div class="ui-block-c">
                <span>
                    <span class="dltBtn">
                        <a href="#" class="deleteRow">X</a>
                    </span>
                </span>
            </div>
        </div>
    }
</div>
_

レジスターコントローラー

_public ActionResult Index()
{
    var register = new Register
    {
        students = new List<Person>
        {
            new Person { firstName = "", lastName = "" }
        },
        teachers = new List<Person> 
        {
            new Person { lastName = "", firstName = "" }
        }
    };

    return View(register);
}
_

登録および個人モデル

_public class Register
{
    public int id { get; set; }
    public List<Person> teachers { get; set; }
    public List<Person> students { get; set; }
}

public class Person
{
    public int id { get; set; }
    public string firstName { get; set; }
    public string lastName { get; set; }
}
_

インデックス

_@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@model UsefulCode.Models.Register
<div id="studentList">
@using (Html.BeginForm())
{
    <div id="editorRowsStudents">
        @foreach (var item in Model.students)
        {
            @Html.Partial("StudentView", item)
        }
    </div>
    @Html.ActionLink("Add", "StudentManager", null, new { id = "addItemStudents", @class = "button" });
}
</div>

<div id="teacherList">
@using (Html.BeginForm())
{
    <div id="editorRowsTeachers">
        @foreach (var item in Model.teachers)
        {
            @Html.Partial("TeacherView", item)
        }
    </div>
    @Html.ActionLink("Add", "TeacherManager", null, new { id = "addItemTeachers", @class = "button" });
}
</div>


@section scripts {
    <script type="text/javascript">
    $(function () {
        $('#addItemStudents').on('click', function () {
            $.ajax({
                url: '@Url.Action("StudentManager")',
                    cache: false,
                    success: function (html) { $("#editorRowsStudents").append(html); }
                });
                return false;
            });
            $('#editorRowsStudents').on('click', '.deleteRow', function () {
                $(this).closest('.editorRow').remove();
            });
            $('#addItemTeachers').on('click', function () {
                $.ajax({
                    url: '@Url.Action("TeacherManager")',
                    cache: false,
                    success: function (html) { $("#editorRowsTeachers").append(html); }
                });
                return false;
            });
            $('#editorRowsTeachers').on('click', '.deleteRow', function () {
                $(this).closest('.editorRow').remove();
            });
        });
    </script>
}
_

StudentManagerアクション:

_public PartialViewResult StudentManager()
{
    return PartialView(new Person());
}
_
10
PurpleSmurph

部分ビューを使用できますが、問題は、EditorForを使用してIdプロパティを生成すると、重複が生成されることです。

私のために働いたのは、メインビューのjavascript内でvar view = @Html.Raw(@Html.Partial('Your partial'))を使用することでした。

この変数にはデフォルトのIDのビューがあり、idプロパティとnameプロパティをid=YourMainListName_{ItemNumber}__Propertyname=YourMainListName_{ItemNumber}__Propertyに置き換えます。

ここで、{ItemNumber}はリスト内の新しいアイテムのインデックスになります。

これを正しく機能させるには多くのJavaScriptが必要ですが、IdプロパティとNameプロパティが正しく設定されている限り、ページをポストバックするときのモデルバインディングを含め、すべてが正しく機能するはずです。

2
3dd