Благодаря многим исследованиям, и я до сих пор не до конца уверен, что это правильный способ сделать это, но он работает.Поэтому, если вам нужен каскадный выпадающий список с редактированием, я так и сделал.
Я начну с модели представления.
public class EditAddressViewModel
{
public Guid AddressUI { get; set; }
[Display(Name = "Billing Address?")]
[UIHint("_IsStatus")]
public bool IsBilling { get; set; }
[Display(Name = "Shipping Address?")]
[UIHint("_IsStatus")]
public bool IsShipping { get; set; }
[Display(Name = "Location Name")]
[Required(ErrorMessage = "Location name is required")]
public string LocationName { get; set; }
[Display(Name = "Contact Name")]
[Required(ErrorMessage = "Contact name is required")]
public string ContactName { get; set; }
[Display(Name = "Address")]
public string Line1 { get; set; }
[Display(Name = "Address 2")]
[Required(ErrorMessage = "Address line 2 is required - Should be your address or PO Box")]
public string Line2 { get; set; }
[Display(Name = "Country")]
[Required(ErrorMessage = "Country name is required")]
public int Country { get; set; }
public IEnumerable<SelectListItem> Countries { get; set; }
[Display(Name = "State")]
[Required(ErrorMessage = "State name is required")]
public int State { get; set; }
public IEnumerable<SelectListItem> States { get; set; }
[Display(Name = "City")]
[Required(ErrorMessage = "City name is required")]
public int City { get; set; }
public IEnumerable<SelectListItem> Cities { get; set; }
[Display(Name = "ZipCode")]
public string ZipCode { get; set; }
[Display(Name = "Contact Email")]
[Required(ErrorMessage = "Email contact is required")]
[DataType(DataType.EmailAddress)]
[StringLength(320)]
[RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", ErrorMessage = "Enter a valid email address")]
public string EmailAddress { get; set; }
[Display(Name = "Phone Number")]
[Required(ErrorMessage = "Phone number is required")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
[RegularExpression(@"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}", ErrorMessage = "Enter a valid phone number")]
public string PhoneNumber { get; set; }
[Display(Name = "Fax Number")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
[RegularExpression(@"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}", ErrorMessage = "Enter a valid phone number")]
public string FaxNumber { get; set; }
public int CompanyId { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd HH:mm}", ApplyFormatInEditMode = false)]
public DateTime CreatedDate { get; set; }
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd HH:mm}", ApplyFormatInEditMode = false)]
public DateTime LastUpdated { get; set; }
}
Следующая вещь - это контроллер.
// Customer Input
// GET: Addresses/Edit?guid=56A792FE-28D1-4D1D-8F59-21DE1EABA2FB
// TO DO - Create Route in APP_Start RouteConfig for better looking link.
[Authorize(Roles = "CompanyAdmin")]
public ActionResult UserEditAddress(Guid guid)
{
if (guid == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
AddressEdit addresses = db.AddressEdit.Find(guid);
if (addresses == null)
{
return HttpNotFound();
}
var model = new EditAddressViewModel();
model.AddressUI = addresses.AddressUI;
model.Line1 = addresses.Line1;
model.Line2 = addresses.Line2;
model.Country = addresses.Country;
model.State = addresses.State;
model.City = addresses.City;
model.ZipCode = addresses.ZipCode;
model.Countries = new SelectList(db.Countries, "CountryId", "CountryName", addresses.Country);
model.States = new SelectList(db.States, "StateId", "StateName", addresses.State);
model.Cities = new SelectList(db.Cities, "CityId", "CityName", addresses.City);
return View(model);
}
// POST: Addresses/Edit?guid=56A792FE-28D1-4D1D-8F59-21DE1EABA2FB
// TO DO - Create Route in APP_Start RouteConfig for better looking link.
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UserEditAddress([Bind(Include = "AddressUI,Line1,Line2,Country,State,City,ZipCode,CompanyId")] AddressEdit addresses)
{
var userId = User.Identity.GetUserId();
if (ModelState.IsValid)
{
db.Entry(addresses).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index", "Customer", new { UserId = userId });
}
return View(addresses);
}
// Get States
public JsonResult GetStates(string countryId)
{
int Id;
Id = Convert.ToInt32(countryId);
var states = from a in db.States where a.CountryId == Id select a;
return Json(states);
}
// Get Cities
public JsonResult GetCities(string stateId)
{
int Id;
Id = Convert.ToInt32(stateId);
var cities = from a in db.Cities where a.StateId == Id select a;
return Json(cities);
}
Обратите внимание, что я использую Guid.Это было сделано для того, чтобы клиент не мог увидеть «идентификатор» записи и изменить его в ссылке для просмотра других данных клиента.Я также реализовал представление SQL по 2 причинам.Идентификатор используется для других процедур и в рамках сущности должен быть ключом.Поэтому я создал представление SQL, чтобы я мог использовать прикрепленную к нему модель и поставить Guid в качестве ключа.Также используется для целей обновления только части информации в таблице при редактировании, а не всех полей, поэтому у меня есть только поля в модели, которые необходимо обновить.
Представление SQL - Модель
namespace MyProject.BusinessModels.Entities
{
public class AddressEdit
{
[Key]
public Guid AddressUI { get; set; }
[Display(Name = "Address")]
public string Line1 { get; set; }
[Display(Name = "Address 2")]
public string Line2 { get; set; }
[Display(Name = "Country")]
public int Country { get; set; }
[Display(Name = "State")]
public int State { get; set; }
[Display(Name = "City")]
public int City { get; set; }
[Display(Name = "ZipCode")]
public string ZipCode { get; set; }
}
}
А вот Страница бритвы с выпадающими списками для страны, штата и города.Эта настройка возвращает страницу редактирования с уже выбранными значениями в базе данных.Они целые.В раскрывающихся списках отображаются значения String из 3 отдельных таблиц, содержащих имена данных и соответствующие им идентификаторы.Функции javascript / ajax не будут работать, просто удаляя списки, потому что текущее состояние уже получило полный список каждой из 3 таблиц.Поэтому мне пришлось добавить кнопку очистки, охватывающую весь сценарий, чтобы он был сфокусирован после очистки.Таким образом, это устанавливает ddl страны на 0 и очищает список для штата и города.Теперь с помощью скрипта работает каскадный эффект, и вы можете изменять значения для обновления.Если пользователь никогда не очищает их и изменяет только другое поле в форме, он сохранит значения «Выбранные».Если они очистят форму и попытаются отправить ее, они получат сообщение об ошибке, поскольку поля обязательны для заполнения.
@model MyProject.Models.EditAddressViewModel
@using Microsoft.AspNet.Identity
@{
ViewBag.Title = "UserEdit";
Layout = "~/Views/Shared/CustomerDashboardLayout.cshtml";
}
<br />
<div class="row">
<div class="col-lg-12">
<p>
@{ var userId = User.Identity.GetUserId(); }
@Html.ActionLink("Back to List", "Index", "Customer", new { UserId = userId }, new { @class = "btn btn-primary" })
</p>
</div>
<!-- /.col-lg-12 -->
</div>
<div class="row">
<div class="col-lg-6">
<div class="tile">
<h3 class="tile-title">Edit Address</h3>
<div class="tile-body">
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.AddressUI)
<div class="form-group row">
@Html.LabelFor(model => model.Line1, htmlAttributes: new { @class = "control-label col-md-3" })
<div class="col-md-8">
@Html.EditorFor(model => model.Line1, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Line1, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group row">
@Html.LabelFor(model => model.Line2, htmlAttributes: new { @class = "control-label col-md-3" })
<div class="col-md-8">
@Html.EditorFor(model => model.Line2, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Line2, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group row">
@Html.LabelFor(model => model.Country, htmlAttributes: new { @class = "control-label col-md-3" })
<div class="col-md-8">
@Html.DropDownListFor(model => Model.Country, Model.Countries, "Select Country", new { @class = "form-control", @id = "ddlCountry" })
@Html.ValidationMessageFor(model => model.Country, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group row">
@Html.LabelFor(model => model.State, htmlAttributes: new { @class = "control-label col-md-3" })
<div class="col-md-8">
@Html.DropDownListFor(model => model.State, Model.States, "Select State", new { @class = "form-control", @id = "ddlState" })
@Html.ValidationMessageFor(model => model.State, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group row">
@Html.LabelFor(model => model.City, htmlAttributes: new { @class = "control-label col-md-3" })
<div class="col-md-8">
@Html.DropDownListFor(model => model.City, Model.Cities, "Select City", new { @class = "form-control", @id = "ddlCity" })
@Html.ValidationMessageFor(model => model.City, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group row">
@Html.LabelFor(model => model.ZipCode, htmlAttributes: new { @class = "control-label col-md-3" })
<div class="col-md-8">
@Html.EditorFor(model => model.ZipCode, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.ZipCode, "", new { @class = "text-danger" })
</div>
</div>
<div class="tile-footer">
<div class="row">
<div class="col-md-8 col-md-offset-3">
<input type="button" id="btnReset" value="Reset" onclick="Reset();" class="btn btn-default" />
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
<script type="text/javascript">
function Reset() {
document.getElementById('ddlCountry').selectedIndex = 0;
document.getElementById('ddlState').innerHTML = "";
document.getElementById('ddlCity').innerHTML = "";
$(function () {
$('#ddlCountry').change(function () {
$.ajax({
type: "post",
url: "/Addresses/GetStates",
data: { countryId: $('#ddlCountry').val() },
datatype: "json",
traditional: true,
error: function (_, err) {
console.log(_, err)
},
success: function (data) {
$.each(data, function (index, value) {
$('#ddlState').append('<option value="' + value.StateId + '">' + value.StateName + '</option>');
});
}
});
});
$('#ddlState').change(function () {
$.ajax({
type: "post",
url: "/Addresses/GetCities",
data: { stateId: $('#ddlState').val() },
datatype: "json",
traditional: true,
error: function (_, err) {
console.log(_, err)
},
success: function (data) {
$.each(data, function (index, value) {
$('#ddlCity').append('<option value="' + value.CityId + '">' + value.CityName + '</option>');
});
}
});
});
});
}
</script>
Это рабочее решение.Однако в идеальном мире не было бы четкой кнопки.Так что в будущем я буду работать, чтобы найти способ избавиться от этого.Надеюсь, что это поможет кому-то, нуждающемуся в простом способе редактирования и просмотра текущих значений каскадных выпадающих списков