【问题标题】:How to make an ajax dropdown strongly bound to the ViewModel in ASP.Net MVC 5如何在 ASP.Net MVC 5 中使 ajax 下拉列表强绑定到 ViewModel
【发布时间】:2018-02-04 16:27:55
【问题描述】:

所以,我有一份工作申请的推荐表。现在,当求职者从公司下拉列表中选择公司时,我想仅显示该公司的求职信下拉列表(求职信已由候选人从另一个选项卡上传)。现在,为了获得 Microsoft 的推荐,一个人可能有 3 封求职信。

问题:

我想知道如何显示来自 ajax 调用的下拉菜单,并且仍然保持 Coverletter 下拉列表与模型紧密绑定

以下是非 AJAX 强绑定:显示所有求职信,无论选择哪家公司)

查看:

@model Bridge.ViewModels.ReferralViewModel
@using (Html.BeginForm())
{
        <div class="form-group">
            @Html.LabelFor(model => model.CompanyId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(m => m.CompanyId, Model.Companies, new { @class = "form-control js-change", onchange = "companyChanged()" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.CoverLetterId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(m => m.CoverLetterId, new SelectList(Model.CoverLetters, "CoverLetterId", "CoverLetterName", Model.CoverLetters), new { @class = "form-control" })
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

型号:

   public class ReferralViewModel
    {
        public int ReferralViewModelId { get; set; }
        public int CompanyId { get; set; }
        public IEnumerable<SelectListItem> Companies { get; set; }
        public int CoverLetterId { get; set; }
        public IEnumerable<CoverLetter> CoverLetters { get; set; }
    }

控制器:

        public ActionResult Create()
    {
        var viewModel = new ReferralViewModel
        {
            var candidateId = User.Identity.GetUserId();
            Companies = _context.Companies.Select(x => new SelectListItem
            {
                Text = x.CompanyName,
                Value = x.CompanyId.ToString()

            }),
            CoverLetters = _context.CoverLetters.Where(r => r.CandidateId == candidateId).ToList()
        };
    return View(viewModel);
}

现在 AJAX 尝试:

控制器动作

public JsonResult ListOfCoverLetterByCompanyId(int companyId)
        {
            var coverletters = _context.CoverLetters
                .Where(c => c.CompanyId == companyId)
                .ToList();

            var dropdown = new List<SelectListItem>();
            foreach (var cl in coverletters)
            {
                dropdown.Add(new SelectListItem { Text = cl.CoverLetterName, Value = cl.CoverLetterId.ToString() });
            }
            return Json(dropdown, JsonRequestBehavior.AllowGet);
        }

新视图

@model Bridge.ViewModels.ReferralViewModel
@using (Html.BeginForm())
{
            @Html.LabelFor(model => model.CompanyId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(m => m.CompanyId, Model.Companies, new { @class = "form-control js-change", onchange = "companyChanged()" })
            </div>
        </div>
        @* Dropdown will appear here*@
        <select id="CoverLetterId" name="CoverLetterId"></select>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

@section scripts{
    <script>
        function companyChanged() {
            var companyId = $(".js-change").val();
            $.ajax({
                url: "/Referral/ListOfCoverLetterByCompanyId",
                data: { companyId: companyId },
                contentType: "application/json; charset-utf-8",
                success: function (datas) {
                        $("#CoverLetterId").html("");
                    $.each(datas, function (i, data) {
                        $("#CoverLetterId ").append('<option value="' + data.Value + '">' + data.Text + '</option>');
                    });
                },
                error: function () {}
            });
        }
    </script>
    <script>
        companyChanged();
    </script>
}

新视图模型

   public class ReferralViewModel
    {
        public int ReferralViewModelId { get; set; }
        public int CompanyId { get; set; }
        public IEnumerable<SelectListItem> Companies { get; set; }
        public int CoverLetterId { get; set; }
    }

我认为通过遵循当前代码,我失去了强绑定 Razor 视图的美感。下拉列表不绑定到任何属性。我可以以某种方式使其强绑定并使用 @Html.DropdownListFor

【问题讨论】:

  • 您需要将第二个下拉列表绑定到CoverLetterId ,并且您的 veiw 模型需要一个属性 public IEnumerable&lt;SelectListItem&gt; CoverLetters { get; set; },该属性最初将设置为空集合
  • 所以,首先,我将在 viewModel 中添加该属性,然后我可以添加这个问题的答案中给出的代码。我想你的意思是对的?
  • 没问题.....
  • @StephenMuecke:另外,先生,如果您发现代码有任何其他改进,请告诉我。可以这么说,您(作为旁注)可以帮助像我这样的初学者了解更多信息。

标签: c# ajax asp.net-mvc razor asp.net-mvc-5


【解决方案1】:

您的原始视图模型是正确的,尽管您的CoverLetters 属性最好是public IEnumerable&lt;SelectListItem&gt; CoverLetters { get; set; },并且CompanyIdCoverLetterId 属性都应该是int?(可为空)

在视图中,使用强绑定到您的模型

@Html.DropDownListFor(m => m.CoverLetterId, Model.CoverLetters, "Please select", new { @class = "form-control" })

在您的控制器中,添加一个初始化两个 SelectList 的私有方法。如果CompanyId 有一个值,则从数据库中填充CoverLetters,否则将其初始化为一个空集合。然后,您可以在 GET 方法中调用该方法,如果 ModelState 无效,则在 POST 方法中调用该方法

private void ConfigureViewModel(ReferralViewModel model)
{
    // Populate companies always
    model.Companies = _context.Companies.Select(x => new SelectListItem
    {
        Text = x.CompanyName,
        Value = x.CompanyId.ToString()
    });
    // Populate cover letters only if a company has been selected
    // i.e. if your editing and existing Referral, or if you return the view in the POST method
    if (model.CompanyId.HasValue)
    {
        model.CoverLetters = _context.CoverLetters.Where(x => x.CompanyId == model.CompanyId.Value).Select(x => new SelectListItem
        {
            Value = x.CoverLetterId.ToString(),
            Text = x.CoverLetterName
        });
    }
    else
    {
        model.CoverLetters  = new SelectList(Enumerable.Empty<SelectListItem>());
    }
}

public ActionResult Create()
{
    ReferralViewModel model = new ReferralViewModel();
    ConfigureViewModel(model);
    return View(model);
}

public ActionResult Create(ReferralViewModel model)
{
    if (!ModelState.IsValid())
    {
        ConfigureViewModel(model);
        return View(model);
    }
    // Initialize data model, map properties from view model, save and redirect
}

【讨论】:

  • 我还将在大约 20 分钟后在我们的一个聊天会话中添加一些关于 ajax 调用的注释 - 它只是次要的,并且与您希望 CoverLetter 是可选的这一事实有关随后的问题(但您没有在此处包含该信息,因此不适合将其包含在此处)
  • 这个 configureviewmodel 对我来说是一个很好的学习。当 ModelState 无效时,救了我再次编写相同的代码(重新初始化 viewModel)。 :)
  • 注意,刚刚发现model.CoverLetters = _context.CoverLetters... 代码行中的错字 - 现在已更正
  • 如果model.CompanyId.HasValue,我仍然怀疑那行。我在聊天会话中 ping 了你。有空的时候看看。谢谢。
  • 绝对在视图模型上,但将其添加到两者都很好。并且使用if (viewModel.CoverLetterId.HasValue) {.. 是正确的
【解决方案2】:

如果您想要的只是生成select html 的强类型,您可以使用空选项调用DropDownListFor

@Html.DropDownListFor(m => m.CoverLetterId, new List<SelectListItem>(), new { id = "CoverLetterId",  @class = "form-control" })

然后重置代码保持不变

创建的select 将具有正确的名称,这意味着模型绑定将正常工作

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多