当用户在MVC5和EF6中做出选择时,隐藏一个控件并显示另一个控件

时间:2014-10-08 18:33:34

标签: asp.net asp.net-mvc asp.net-mvc-5 asp.net-mvc-5.1

在我的MVC5控制器中,我在我的ViewModel中填写两个列表,如下所示:

public async Task<ActionResult> Create()
        {
            var db = new ApplicationDbContext();
            var model = new RegisterViewModel()
            {                    
                RegionsList = db.Regions.ToList().Select(x => new SelectListItem()
                {
                    Selected = false,
                    Text = x.Name,
                    Value = x.Name
                }),
                CompanyList = db.Companies.ToList().Select(x => new SelectListItem()
                {
                    Selected = false,
                    Text = x.Name,
                    Value = x.CompanyId.ToString()
                })
            };
            return View(model);
        }

然后,在我的视图中,我将公司显示为DropDownList,将Regions显示为一组复选框:

<div class="form-group">
            @Html.LabelFor(model => model.CompanyList, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(c => c.SelectedCompanyId, Model.CompanyList, new { @class = "form-control" })
            </div>
        </div>
    <div class="form-group">
        @Html.Label("Assign the user to one or more regions", new { @class = "control-label col-md-2" })
            <span class=" col-md-10">
                @foreach (var item in Model.RegionsList)
                {
                    <input type="checkbox" name="SelectedRegionNames" value="@item.Value" checked="@item.Selected" class="checkbox-inline" />
                    @Html.Label(item.Value, new { @class = "control-label" })
                }
            </span>
        </div>

这样可行,但由于所有公司的所有地区都显示出来,所以它有点混乱。我想隐藏一组复选框,直到公司被选中,然后隐藏公司下拉列表并显示region.CompanyId ==所选区域的区域列表。

有人可以教我如何做到这一点吗?

2 个答案:

答案 0 :(得分:3)

如果您想进行服务器端过滤,那么您的操作顺序可能如下所示:

  • 显示所有公司,但没有地区
  • 回应公司表单元素
  • 的更改事件
  • 从AJAX电话中获取相关区域
  • 创建您的区域选择

在第一步中,您所做的一切都不再显示任何区域。所以你在视图模型中不需要它们:

var model = new RegisterViewModel()
{                    
    CompanyList = db.Companies.ToList().Select(x => new SelectListItem()
    {
        Selected = false,
        Text = x.Name,
        Value = x.CompanyId.ToString()
    })
};
return View(model);

但是你需要一种方法来识别将客户端包含它们的HTML元素。 id值适用于此:

<span id="regionsSelection" class="col-md-10"></span>

在第二步中,您将change处理程序附加到拥有公司的select元素。当然,您需要一种方法来识别该元素。例如,如果它的name属性为SelectedCompanyId,那么这应该有效:

$('select[name="SelectedCompanyId"]').change(function () {

});

第三步将涉及在change处理程序内部进行AJAX调用。但在我们能够做到这一点之前,我们需要一个服务器端控制器动作来根据选定的公司获取区域。我主要猜测你的对象模型细节,但结构将是这样的:

public ActionResult GetRegions(int companyId)
{
    var db = new ApplicationDbContext();
    var regions = db.Regions.Where(r => r.Companies.Any(c => c.Id == companyId));
    return Json(regions);
}

我们的想法是获取与提供的公司ID相关联的区域,并将它们作为JSON数组返回。然后,您可以从change处理程序中的客户端代码调用该操作。像这样:

$.ajax({
    url: '@Url.Action("GetRegions", "MyController")',
    type: 'POST',
    dataType: 'json',
    data: { companyId : $('select[name="SelectedCompanyId"]').val()
}).done(function(response) {
    // "response" has the returned data, use it here
}).fail(function(response) {
    // There was an error, handle it here
});

那个(或类似的东西)应该从服务器获取区域。 (请注意,我在这里使用了一些服务器端代码来定义URL。)

然后第四步在AJAX调用的done处理程序中进行,您可以使用响应中的数据创建HTML元素。再一次,我将主要猜测对象的结构。您可能希望在浏览器的调试工具中手动检查实际的JSON响应,以确保它符合您的预期。

如果response成功地成为区域集合,那么使用它可能看起来像这样:

$('#regionSelection').html('');
for (var i = 0; i < response.length; i++) {
    $('#regionSelection').append('<input type="checkbox" name="SelectedRegionNames" value="' + response[i].Name + '" checked="false" class="checkbox-inline" />');
    $('#regionSelection').append('<label class="control-label">' + response[i].Name + '</label>');
}

正如您所看到的,首先我清空span的当前内容(删除之前添加到其中的任何区域复选框。然后我所做的就是将HTML元素附加到手动span,问题中的代码在初始页面渲染过程中附加它们。

我无法100%保证这是一个满足您需求的复制/粘贴解决方案,因为我不太了解您的模型结构或您的UX或用例来实现此功能。但是,从动态获取服务器中的对象列表以驱动客户端UI,这可以解决问题。

答案 1 :(得分:0)

您有两种选择:

  1. 在服务器上过滤(发回表单并返回正确的项目)

    • 用户可以复制URL并通过电子邮件分享过滤后的视图
    • 您网站的响应时间较慢。回发需要时间,特别是在移动连接上
    • 适合大量选择
  2. 在客户端上过滤(第一次发送所有内容并显示/隐藏项目)

    • 网址保持不变(如果您没有做一些特别的事情)
    • 响应时间更快
    • 适合中小型选项
  3. 可以使用适当的ViewModel完成替代方案:

    public class FilteredRegions
    {
        public FilteredRegions()
        {
            Regions = new List<Region>();
        }
    
        public int SelectedCompanyID { get; set; }
        public IEnumerable<SelectListItem> CompanyList { get; set; }
    
        public int SelectedRegionID { get; set; }       
        public virtual ICollection<Topic> Regions { get; set; }
    }
    

    备选方案二(我强烈推荐,基于假设你的地区少于1000个)

    将每个区域放在视图中,并在其上添加一个很好的数据属性:

    <div class="form-group">
    @Html.Label("Assign the user to one or more regions", new { @class = "control-label col-md-2" })
        <span class=" col-md-10">
            @foreach (var item in Model.RegionsList)
            {
                <input type="checkbox" name="SelectedRegionNames" value="@item.Value" checked="@item.Selected" class="checkbox-inline hide" data-company="@item.CompanyId" />
                @Html.Label(item.Value, new { @class = "control-label" })
            }
        </span>
    </div>
    

    然后将事件句柄附加到下拉菜单,执行以下操作:(未测试)

    $('#dropdown').change(function() {
        var companyID = $(this).value;
        $('input[data-company]').hide();
        $('input[data-company="' + companyID + '"]').show();
    })
    

    即。当公司选择发生变化时,隐藏所有复选框并显示所有正确的复选框。 你需要jquery代码片段。