【问题标题】:IList binding Razor PagesIList 绑定 Razor 页面
【发布时间】:2021-05-26 23:59:06
【问题描述】:

尝试绑定 IList 以便我可以更新我拥有的字段。但是,以 OnPostAsync 的空列表结束。不知道我错过了什么。

我的代码如下:

[BindProperty]
public IList<Runbook_Serverlist_Plus> RunbookServerListPlus { get; set; }

该列表使用以下代码填充了 OnGetAsync 函数:

public async Task OnGetAsync()
{
   var listRunbookServerList = await _context.Runbook_Serverlist.ToListAsync();
   RunbookServerListPlus = listRunbookServerList.Select(item => new Runbook_Serverlist_Plus(item)).ToList();
}

因此,我首先从我的模型中获取 IList,然后为 Runbook_Serverlist_Plus 创建一个新列表。 想法是有一个 Runbook_Serverlist 的基类,然后在上面放一个 Runbook_Serverlist_Plus,我可以在其中设置特定的字段,以后可以使用这些字段来更新某些字段。

见下面的代码:

  public class Runbook_Serverlist_Plus
  {
    [BindProperty]
    public Runbook_Serverlist Bc {get; set; }

    public Runbook_Serverlist_Plus(Runbook_Serverlist bsBc)
    {
      Bc = bsBc;
      CheckCompleted = false;
    }
    
    public bool CheckCompleted { get; set; }
  }

在我的 cshmtl 中代码如下:

<form method="post">
<table class="table">
  <thead>
  <tr>
    <th>
      @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Servername)
    </th>
    <th>
      @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Status)
    </th>
    <th>
      @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Cluster)
    </th>
    <th>
      @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.StatusChange)
    </th>
    <th>
      @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.PreRun)
    </th>
    <th>
      @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Ordering)
    </th>
    <th></th>
  </tr>
  </thead>
  <tbody>
  @for (var i = 0; i < Model.RunbookServerListPlus.Count; i++)
  {
    var item = Model.RunbookServerListPlus[i];
    <tr>
      <td>
        @Html.DisplayFor(modelItem => item.Bc.Servername)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Bc.Status)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Bc.Cluster)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Bc.StatusChange)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Bc.PreRun)
      </td>
      <td>
        @Html.DisplayFor(modelItem => item.Bc.Ordering)
      </td>
      <td>
        <input hidden asp-for="@item.Bc.Servername" class="form-control" />
        <input asp-for="@item.CheckCompleted"  class="form-control"/>
      </td>
    </tr>
  }
  </tbody>
</table>
  <div class="form-group">
    <input type="submit" value="Update" class="btn btn-primary" />
  </div>
</form>

所以我有一个 CheckCompleted 项目的复选框,在发帖时,我想查看所有标记的复选框。 当我提交/发布时,我希望 RunbookServerListPlus 被填写。但是,这个一直是空的。

我错过了什么?

Post 功能暂时没有别的了:

      public async Task<IActionResult> OnPostAsync()
      {
        if (!ModelState.IsValid)
        {
          return Page();
        }

        return RedirectToPage("./Index");
      }

【问题讨论】:

    标签: c# asp.net-core razor razor-pages


    【解决方案1】:

    首先,你可以添加隐藏的输入来绑定模型数据,表单post会传递输入的值。和.net核心绑定模型名称属性。如果你想用列表绑定数据,你需要将名称设置为@987654329 @。

    如果你只想在勾选CheckCompleted时通过Runbook_Serverlist_Plus,你可以在表单发布之前使用js将隐藏输入的名称更改为正确的格式。这里有一个演示。

    型号:

    public class Runbook_Serverlist_Plus
        {
            [BindProperty]
            public Runbook_Serverlist Bc { get; set; }
            public Runbook_Serverlist_Plus(Runbook_Serverlist bsBc)
            {
                Bc = bsBc;
                CheckCompleted = false;
            }
            public Runbook_Serverlist_Plus()
            {
            }
            public bool CheckCompleted { get; set; }
        }
        public class Runbook_Serverlist
        {
            public string Servername { get; set; }
            public string Status { get; set; }
            public string Cluster { get; set; }
            public string StatusChange { get; set; }
            public string PreRun { get; set; }
            public string Ordering { get; set; }
    
    
        }
    

    cshtml:

    <form method="post">
        <table class="table">
            <thead>
                <tr>
                    <th>
                        @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Servername)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Status)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Cluster)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.StatusChange)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.PreRun)
                    </th>
                    <th>
                        @Html.DisplayNameFor(model => model.RunbookServerListPlus[0].Bc.Ordering)
                    </th>
                    <th></th>
                </tr>
            </thead>
            <tbody>
                @for (var i = 0; i < Model.RunbookServerListPlus.Count; i++)
                {
                    var item = Model.RunbookServerListPlus[i];
                    <tr>
                        <td>
                            @Html.DisplayFor(modelItem => item.Bc.Servername)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Bc.Status)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Bc.Cluster)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Bc.StatusChange)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Bc.PreRun)
                        </td>
                        <td>
                            @Html.DisplayFor(modelItem => item.Bc.Ordering)
                        </td>
                        <td>
                            <input asp-for="@item.CheckCompleted" class="form-control" name="RunbookServerListPlus[index].CheckCompleted" />
                            <input hidden asp-for="@item.Bc.Servername" class="form-control" name="RunbookServerListPlus[index].Bc.Servername" />
                            <input hidden asp-for="@item.Bc.Status" class="form-control" name="RunbookServerListPlus[index].Bc.Status" />
                            <input hidden asp-for="@item.Bc.Cluster" class="form-control" name="RunbookServerListPlus[index].Bc.Cluster" />
                            <input hidden asp-for="@item.Bc.StatusChange" class="form-control" name="RunbookServerListPlus[index].Bc.StatusChange" />
                            <input hidden asp-for="@item.Bc.PreRun" class="form-control" name="RunbookServerListPlus[index].Bc.PreRun" />
                            <input hidden asp-for="@item.Bc.Ordering" class="form-control" name="RunbookServerListPlus[index].Bc.Ordering" />
    
                        </td>
                    </tr>
                }
            </tbody>
        </table>
        <div class="form-group">
            <input type="submit" value="Update" class="btn btn-primary" />
        </div>
    </form>
    <script>
        $("form").submit(function () {
            var index = 0;
            $("tbody tr").each(function () {
                var lasttd = $(this).find('td:last-child');
                
                if (lasttd.find("input")[0].checked) {
                    lasttd.find("input").each(function () {
                        $(this).attr("name", $(this).attr("name").replace("index",index));
                    })
                    index++;
                }
            })
        })
    </script>
    

    cshtml.cs(我用假数据测试):

    [BindProperty]
            public List<Runbook_Serverlist_Plus> RunbookServerListPlus { get; set; }
            public void OnGet()
            {
                RunbookServerListPlus = new List<Runbook_Serverlist_Plus> {
                    new Runbook_Serverlist_Plus { Bc = new Runbook_Serverlist { Cluster = "c1", Ordering = "1", PreRun="p1", Servername="sname1", Status="status1", StatusChange="statuschange1" } },
                    new Runbook_Serverlist_Plus { Bc = new Runbook_Serverlist { Cluster = "c2", Ordering = "2", PreRun="p2", Servername="sname2", Status="status2", StatusChange="statuschange2" } },
                    new Runbook_Serverlist_Plus { Bc = new Runbook_Serverlist { Cluster = "c3", Ordering = "3", PreRun="p3", Servername="sname3", Status="status3", StatusChange="statuschange3" } }
    
                };
            }
            public async Task<IActionResult> OnPostAsync()
            {
                if (!ModelState.IsValid)
                {
                    return Page();
                }
    
                return RedirectToPage("./Index");
            }
    

    结果:

    更新(传递整个列表):

    首先,去掉第一个demo中的js。

    然后像这样改变 td:

    <td>
                        <input asp-for="@item.CheckCompleted" class="form-control" name="RunbookServerListPlus[@i].CheckCompleted" />
                        <input hidden asp-for="@item.Bc.Servername" class="form-control" name="RunbookServerListPlus[@i].Bc.Servername" />
                        <input hidden asp-for="@item.Bc.Status" class="form-control" name="RunbookServerListPlus[@i].Bc.Status" />
                        <input hidden asp-for="@item.Bc.Cluster" class="form-control" name="RunbookServerListPlus[@i].Bc.Cluster" />
                        <input hidden asp-for="@item.Bc.StatusChange" class="form-control" name="RunbookServerListPlus[@i].Bc.StatusChange" />
                        <input hidden asp-for="@item.Bc.PreRun" class="form-control" name="RunbookServerListPlus[@i].Bc.PreRun" />
                        <input hidden asp-for="@item.Bc.Ordering" class="form-control" name="RunbookServerListPlus[@i].Bc.Ordering" />
    
                    </td>
    

    结果:

    检查传递给处理程序的数据:

    【讨论】:

    • 感谢您的回答和演示!但是,如果我将代码复制到一个新项目,我仍然会得到一个空的“RunbookServerListPlus”。与您的代码相比,不确定我缺少什么。由于我稍后想添加更多字段而不仅仅是 CheckCompleted,是否有可能取回整个初始化列表(实际上是来自 SQL 的列表)和复选框?
    • 对于您的空列表,您可以分享您的代码吗?以便我可以尝试找到您的列表为空的原因。` 因为我稍后想添加更多字段而不仅仅是 CheckCompleted,会不会是有可能取回整个初始化列表(实际上是一个来自 SQL 的列表)和复选框?`你的意思是即使 CheckCompleted 为假,你也想获得整个列表?
    • 是的,我想要整个列表,即使 CheckCompleted 为假(因为稍后我想添加更多项目,例如 CheckCompleted)。但是在再次阅读您的评论并将我的代码更改为:&lt;input asp-for="RunbookServerListPlus[i].CheckCompleted" class="form-control" /&gt; 之后,它似乎有效!非常感谢您的提示!
    • 关于演示,我创建了一个新项目,添加了一个名为 TestModel 的新 cshtml,并将您的代码粘贴到该 cshtml 中。但是当我调试 OnPost 时,我在选中其中一个复选框后看到一个空的 RunbookServerListPlus。
    • 我已经用演示更新了我的答案。` 但是当我调试 OnPost 时,我在选中其中一个复选框后看到一个空的 RunbookServerListPlus。 `可以分享一下你在请求中传递的数据吗
    【解决方案2】:

    每个请求仅触发一个处理程序,具体取决于用于发出请求的 HTTP 动词。 OnGet 在使用 HTTP Get 方法请求页面时执行。 OnPost 由 POST 方法执行。

    网络是无状态的。这意味着在一个请求上初始化的变量不可用于另一个请求。如果要在 OnPost 方法中使用集合,则需要在 OnPost 处理程序中再次实例化它。

    我的网站上的更多详细信息:https://www.learnrazorpages.com/razor-pages/handler-methods

    【讨论】:

    • 感谢您的回复和您网站的链接(对我非常有用:))。我的想法是通过表单发布,我再次发布整个表格,包括文本框。该怎么做?
    猜你喜欢
    • 2019-03-12
    • 1970-01-01
    • 1970-01-01
    • 2021-03-07
    • 2021-05-15
    • 2020-05-30
    • 2020-11-16
    • 2023-04-06
    • 2023-03-24
    相关资源
    最近更新 更多