ASP.NET Core 6 MVC 页面创建带有复杂对象列表的对象

发布于 2025-01-20 19:20:50 字数 3626 浏览 0 评论 0原文

我有以下模型,需要通过页面创建:

public class Exercise
{
    public Guid Id{ get; set; }
    public string Name { get; set; }
    public string Description{ get; set; }

    public ICollection<ExerciseCategory> Categories
    ...
    public ICollection<Link> Links { get; set; }
}

public class ExerciseCategory
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

public class Link
{
    public string Name { get; set; }
    public string Value { get; set; }
}

我有一个视图,可以让我创建此对象,但我缺少属性 Exercise.Links 的表单控件:

<form id="profile-form" method="post">
<div class="row">
    <div class="col-12 p-sm-2 p-md-3 p-lg-5 bg-custom-white rounded-4">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-floating mt-2 mb-2">
            <input asp-for="Input.Name" class="form-control" />
            <label asp-for="Input.Name" class="form-label"></label>
            <span asp-validation-for="Input.Name" class="text-danger"></span>
        </div>
        <div class="form-floating mt-2 mb-2">
            <input asp-for="Input.Description" class="form-control" />
            <label asp-for="Input.Description" class="form-label"></label>
            <span asp-validation-for="Input.Description" class="text-danger"></span>
        </div>
        <div class="form-floating mt-2 mb-2">
            <select asp-for="Input.CategoryIds" 
                    asp-items="Model.Input.Categories" class="form-control"></select>
            <label asp-for="Input.Categories" class="form-label"></label>
        </div>
        <button id="create-exercise-button" type="submit" class="w-100 btn btn-lg btn-primary">Create</button>
    </div>
</div>
</form>

属性 Exercise.Categories 很简单,因为 Category 是一个单独创建的实体,所以我只有一个列出现有类别的下拉列表。

Link 只是一个值对象,它本身并不持久。因此,用户应该能够从 Exercise 创建/编辑页面创建/删除/编辑Link

我已尝试以下操作:

            @for (var i = 0; i < Model.Input.Links.Count; i++)
            {
                <div>
                    <input asp-for="Input.Links[i].Name">
                    <input asp-for="Input.Links[i].Value">
                </div>
            }

生成以下 HTML:

<div>
  <input type="text" id="Input_Links_0__Name" name="Input.Links[0].Name" value="some link">
  <input type="text" id="Input_Links_0__Value" name="Input.Links[0].Value" value="https://somelink.com">
</div>
<div>
  <input type="text" id="Input_Links_1__Name" name="Input.Links[1].Name" value="some link1">
  <input type="text" id="Input_Links_1__Value" name="Input.Links[1].Value" value="https://somelink1.com">
</div>

但这在回发时不会填充 Input.Links 属性。

我开始认为问题在于我的列表是 Link 列表而不是原始类型列表。为了测试这一点,我向名为 Links1 的输入模型添加了一个测试 List ,并尝试像之前一样填充该列表:

<div class="form-floating mt-2 mb-2">
  <input asp-for="Input.Links1[i]" data-val="true" class="form-control" />
  <label asp-for="Input.Links1[i]" class="form-label"></label>
</div>

这有效。提交表单后,我将填充的列表返回到控制器中,这证实了问题是 List

如何添加表单控件来填充属性 Exercise.链接(这是一个List)?

I have the following model, which needs to be created via a page:

public class Exercise
{
    public Guid Id{ get; set; }
    public string Name { get; set; }
    public string Description{ get; set; }

    public ICollection<ExerciseCategory> Categories
    ...
    public ICollection<Link> Links { get; set; }
}

public class ExerciseCategory
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

public class Link
{
    public string Name { get; set; }
    public string Value { get; set; }
}

I have a view that lets me create this object, but I miss a form control for the property Exercise.Links:

<form id="profile-form" method="post">
<div class="row">
    <div class="col-12 p-sm-2 p-md-3 p-lg-5 bg-custom-white rounded-4">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-floating mt-2 mb-2">
            <input asp-for="Input.Name" class="form-control" />
            <label asp-for="Input.Name" class="form-label"></label>
            <span asp-validation-for="Input.Name" class="text-danger"></span>
        </div>
        <div class="form-floating mt-2 mb-2">
            <input asp-for="Input.Description" class="form-control" />
            <label asp-for="Input.Description" class="form-label"></label>
            <span asp-validation-for="Input.Description" class="text-danger"></span>
        </div>
        <div class="form-floating mt-2 mb-2">
            <select asp-for="Input.CategoryIds" 
                    asp-items="Model.Input.Categories" class="form-control"></select>
            <label asp-for="Input.Categories" class="form-label"></label>
        </div>
        <button id="create-exercise-button" type="submit" class="w-100 btn btn-lg btn-primary">Create</button>
    </div>
</div>
</form>

The property Exercise.Categories is easy as Category is an entity which is created separately, so I just have a dropdown listing the existing categories.

Link is just a value object that is not persisted on its own. Therefore, the user should be able to create/remove/edit Link from the Exercise create/edit page.

I have tried the following:

            @for (var i = 0; i < Model.Input.Links.Count; i++)
            {
                <div>
                    <input asp-for="Input.Links[i].Name">
                    <input asp-for="Input.Links[i].Value">
                </div>
            }

Which results in the following HTML:

<div>
  <input type="text" id="Input_Links_0__Name" name="Input.Links[0].Name" value="some link">
  <input type="text" id="Input_Links_0__Value" name="Input.Links[0].Value" value="https://somelink.com">
</div>
<div>
  <input type="text" id="Input_Links_1__Name" name="Input.Links[1].Name" value="some link1">
  <input type="text" id="Input_Links_1__Value" name="Input.Links[1].Value" value="https://somelink1.com">
</div>

But this doesn't populate the Input.Links property when posting back.

I started thinking that the problem is the fact that my list is a list of Link rather than a list of primitive types. In order to test this, I added a test List<string> to input model called Links1 and tried to populate that list as I did before:

<div class="form-floating mt-2 mb-2">
  <input asp-for="Input.Links1[i]" data-val="true" class="form-control" />
  <label asp-for="Input.Links1[i]" class="form-label"></label>
</div>

This works. I get the populated list back in the controller after submitting the form, which confirms the problem is the List<Link>

How can I add a form control for populating the property Exercise.Link (which is a List<Link>)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

对风讲故事 2025-01-27 19:20:50

阅读这个答案是另一个问题,我弄清楚了问题所在:

link,属性coresot.links取决于其link.name.namelink,依赖于。 .value 属性,因此提交表格时活页夹无法填充它们。

这是由于链接是域模型。在这种情况下,解决方案是创建一个具有public {get;的演示层模型。设置;}并在表单上而不是域模型上使用它。

因此,要正确回答问题,这是您可以编写表单控件来编辑list&lt; link&gt;

        @for (var i = 0; i < Model.Input.Links.Count; i++)
        {
            <div>
                <input asp-for="Input.Links[i].Name">
                <input asp-for="Input.Links[i].Value">
            </div>
        }

After reading this answer to another question, I figured out what the problem was:

The class Link, on which the property Exercise.Links depends, has no setter for its Link.Name and Link.Value properties, so the binder cannot populate them when you submit the form.

This is due to Link being a domain model. The solution in this case was to create a presentation layer model that has public {get; set;} and use that on the form instead of the domain model.

So, to answer the question properly, this is how you could write a form control to edit a List<Link>:

        @for (var i = 0; i < Model.Input.Links.Count; i++)
        {
            <div>
                <input asp-for="Input.Links[i].Name">
                <input asp-for="Input.Links[i].Value">
            </div>
        }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文