【问题标题】:Set razor view variable according to checkbox checked根据选中的复选框设置剃刀视图变量
【发布时间】:2018-02-19 13:50:37
【问题描述】:

我正在使用 ASP.NET MVC 开发一个在线库。 这是我的图书馆管理页面的视图模型:

public class ManageViewModel
{
    public IPagedList<ManageBookViewModel> WholeInventory;
    public IPagedList<ManageBookViewModel> CurrentInventory;
    public bool OldInventoryIsShown { get; set; } = false;
}

在相应的视图中,我有一个是否显示旧库存的复选框和一个局部变量modelList,如果选中该复选框,我想将其设置为Model.WholeInventory,否则设置为Model.CurrentInventory。我使用modelList 显示一个包含所有书籍的表格,并且每次我(取消)选中复选框时都需要重置它的值,以便正确显示列表。 这可能吗?我该怎么做呢?

在我看来,我目前有:

<label class="switch">
    <input id="OldInventoryIsShown" name="OldInventoryIsShown" type="checkbox" />
    <span class="slider round"></span>
</label>
@{
    var modelList = Model.OldInventoryIsShown ? Model.WholeInventory : Model.CurrentInventory;
}      
@using (Html.BeginForm())
{
    <table id="bookInventory" class="table table-hover">
        <thead>
            <tr>
                <th>Author</th>
                <th>Title</th>
                ....
            </tr>
        </thead>
        @foreach (var entry in modelList)
        {
            <tr>
                <td>@Html.DisplayFor(modelItem => entry.Author)</td>
                <td>@Html.DisplayFor(modelItem => entry.Title)</td>
                ....
            </tr>
        }
    </table>

    <p>Page @(modelList.PageCount < modelList.PageNumber ? 0 : modelList.PageNumber) of @modelList.PageCount</p>    
    @Html.PagedListPager(modelList, page => Url.Action("Manage",  page }))
}

控制器动作:

public ActionResult Manage(int? page)
{
    var wholeInventory = _bookService.GetBooksIncludingDisabled().Select(b => Mapper.Map<Book, ManageBookViewModel>(b));
    var currentInventory = _bookService.GetBooks().Select(b => Mapper.Map<Book, ManageBookViewModel>(b));
    int pageSize = 3;
    int pageNumber = page ?? 1;
    var model = new ManageViewModel
    {
        WholeInventory = wholeInventory.ToPagedList(pageNumber, pageSize),
        CurrentInventory = currentInventory.ToPagedList(pageNumber, pageSize)
    };
    return View(model);
}

型号:

书籍.cs

public class Book
{
    public int BookId { get; set; }
    [Required]
    [MinLength(1)]
    public string Title { get; set; }
    [Required]
    [MinLength(1)]
    public string Author { get; set; }
    ....
    public bool IsDisabled { get; set; } = false;
    public virtual ICollection<UserBook> UserBooks { get; set; }
}

ManageBookViewModel.cs

public class ManageBookViewModel
{
    public int BookId { get; set; }
    [Required(AllowEmptyStrings = false, ErrorMessage = "Enter the book title")]
    public string Title { get; set; }
    [Required(AllowEmptyStrings = false, ErrorMessage = "Enter the book author.")]
    public string Author { get; set; }
    ....
    public bool IsDisabled { get; set; }
}

【问题讨论】:

  • 为什么你有 2 个IPagedList&lt;ManageBookViewModel&gt; 属性?由于您需要在服务器中填充它,那么您只需要一个属性(并根据OldInventoryIsShown 的值分配其值)
  • 从您的角度分享所有相关部分。不清楚你用modelList 做什么
  • @StephenMuecke 嗨,最初我对如何显示图书库存有其他计划,只有两个列表。现在我添加了 OldInventoryIsShown,但我不确定在模型中使用此属性还是仅使用 ViewBag 属性或其他类型的变量是否是个好主意... WholeInventory 包括当前和旧库存。
  • 但是你应该只有一个集合属性。这与使用 PagedList 的任何其他过滤没有什么不同 - 你有一个 &lt;form&gt; 包括你 @Html.CheckBoxFor() 并使 GET 进入你的控制器方法,你根据复选框的值设置 IPagedList&lt;ManageBookViewModel&gt; Inventory 的值(和您在路由参数中包含 OldInventoryIsShown 的值,以便在视图中分页时保留它)
  • 你还需要显示控制器方法

标签: c# asp.net-mvc razor checkbox


【解决方案1】:

您的ManageViewModel 只需要包含一个用于分页列表的属性,它应该是IPagedList&lt;Book&gt;(请参阅下面的说明)

public class ManageViewModel
{
    public IPagedList<Book> Inventory;
    [Display(Name = "Include old inventory")]
    public bool OldInventoryIsShown { get; set; }
    ... // any other search/filter properties
}

并且您的视图需要在&lt;form&gt; 元素中包含复选框,并且表单应该对您的控制器方法进行GET。那么还需要将OldInventoryIsShown的当前值作为路由值包含在@Html.PagedListPager()方法中,这样在分页时就可以保留当前的过滤器。

@model ManageViewModel
...
@using (Html.BeginForm("Manage", "ControllerName", FormMethod.Get))
{
    @Html.CheckBoxFor(m => m.OldInventoryIsShown)
    @Html.LabelFor(m => m.OldInventoryIsShown)
    ... // any other search/filter properties
    <input type="submit" value="search" />
}
<table id="bookInventory" class="table table-hover">
    ....
</table>
<p>Page @(modelList.PageCount < modelList.PageNumber ? 0 : modelList.PageNumber) of @modelList.PageCount</p>
@Html.PagedListPager(modelList, page => 
    Url.Action("Manage", new { page = page, oldInventoryIsShown = Model.OldInventoryIsShown })) // plus any other search/filter properties

最后,在控制器方法中,您需要为 bool 属性的值设置一个参数,然后根据该值修改您的查询。

public ActionResult Manage(int? page, bool oldInventoryIsShown)
{
    int pageSize = 3;
    int pageNumber = page ?? 1;
    IQueryable<Book> inventory = db.Books;
    if (!oldInventoryIsShown)
    {
        inventory = inventory.Where(x => !x.IsDisabled);
    }
    ManageViewModel model = new ManageViewModel
    {
        Inventory = inventory.ToPagedList(pageNumber, pageSize),
        OldInventoryIsShown = oldInventoryIsShown
    };
    return View(model);
}

您当前的控制器代码效率极低。假设您的表有 10,000 条 Book 记录,其中 5,000 条被“禁用”(存档)。您当前的代码首先获取所有 10,0000 条记录并将它们添加到内存中。然后将所有映射到视图模型。然后,您调用另一个查询来获取另外 5,0000 条记录(它们只是您已有的记录的副本),您将它们添加到内存并映射到视图模型。但是视图中你想要的只是 3 条记录(pageSize 的值),所以你已经做了数千次额外的不必要的处理。

在您的情况下,不需要视图模型(尽管如果您确实需要,您可以使用 StaticPagedList 方法 - 请参阅 this answer 示例)。您的查询应该使用您的数据库上下文来生成IQueryable&lt;Book&gt;,以便只从数据库返回您需要的结果(在内部,ToPagedList() 方法使用.Skip().Take() IQueryable&lt;T&gt;

【讨论】:

  • 嗨。谢谢您的回答。我实际上希望旧的库存过滤器与搜索分开(在选中/取消选中该框时应该应用/删除过滤器,而无需按下按钮)。那可能吗?我尝试了几件事,但没有成功。示例:提取表单外的复选框,将 id 添加到包含搜索的表单中,在复选框上单击在 javascript 中的表单上调用提交。
  • 是的,当然,尽管在这种情况下,您需要 javascript 来处理复选框的 .click() 事件。但这不是正常的预期行为(以及糟糕的用户界面),因此最好只点击一个链接(您将显示(例如)“显示全部”或“仅显示当前”链接,具体取决于是什么当前显示)并且该链接将调用相同的Manage 方法
  • 我已经设法通过添加一个类型为 submit 的输入和一个隐藏类和一个 id 来使其工作,并在单击复选框时触发其上的单击事件。最初我为表单添加了一个 id 并在其上调用了提交,但这没有用。我仍然遇到滑块样式问题,但我为此添加了另一个问题。谢谢你:)
  • 您并不需要隐藏输入。您可以只使用$('#yourCheckBoxId').click(function() { $(this).closest('form').submit(); }) - 但在表单元素上触发提交被认为是不好的做法
  • 确实,没有隐藏字段我也可以做到。我本可以将 id 添加到我已经存在的搜索按钮中,尽管我想你的方法更优雅。我坚持将复选框设置为滑块的原因是因为我希望在打开滑块后会立即发生某些事情,而不是经典的复选框。但我会记住你的建议,以备将来使用。这只是一个培训项目,所以我正在尝试以适合我的方式构建它。可能会将其部署到 Azure 并在完成后将其提交给一些可用性测试:))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-11
  • 1970-01-01
  • 2020-12-04
  • 2017-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多