使用 ASP.NET Core MVC 编辑 Cascade DropDownList

Posted

技术标签:

【中文标题】使用 ASP.NET Core MVC 编辑 Cascade DropDownList【英文标题】:Edit Cascade DropDownList using ASP.NET Core MVC 【发布时间】:2017-12-02 01:49:59 【问题描述】:

我无法根据我希望编辑的所选客户 ID 从数据库中检索/显示 CityId 值到 City 下拉列表。

当我选择要编辑的客户时,它会正确填充数据库中的数据,但城市下拉列表除外。城市下拉列表将显示“选择城市”以及与州下拉列表中的州相关的所有城市。

如果我选择另一个州,那么它会正确加载所选州的所有城市。

问题是它没有像我第一次根据所选客户 ID 加载页面时那样显示城市下拉列表的城市值。

我是 jQuery/AJAX 的新手,有人帮我编写级联下拉列表的 jQuery 代码。

我在下面提供了我现在正在使用的 ViewModel、Controller 和 Edit View:

客户模型

public class Customer

    public int CustomerId  get; set; 
    public string FirstName  get; set; 
    public string LastName  get; set; 

    public int CityId  get; set; 
    public City City  get; set; 

    public int LocalityId  get; set; 
    public Locality Locality  get; set; 

    public int SubLocalityId  get; set; 
    public SubLocality SubLocality  get; set; 

城市模型

public class City

    public int ID  get; set; 
    public string Name  get; set; 

    public List<Customer> Customers  get; set; 
    public List<Locality> Localities  get; set; 

局部模型

public class Locality

    public int ID  get; set; 
    public string Name  get; set; 

    public int CityId  get; set; 
    public City City  get; set; 

    public List<Customer> Customers  get; set; 
    public List<SubLocality> SubLocalities  get; set; 

子区域模型

public class SubLocality

    public int ID  get; set; 
    public string Name  get; set; 

    public int LocalityId  get; set; 
    public Locality Locality  get; set; 

    public List<Customer> Customers  get; set; 

WebAppDbContext

public class WebAppDbContext : DbContext

    public WebAppDbContext(DbContextOptions<WebAppDbContext> options) : base(options)
     

    public DbSet<Customer> Customers  get; set; 
    public DbSet<City> Cities  get; set; 
    public DbSet<Locality> Localities  get; set; 
    public DbSet<SubLocality> SubLocalities  get; set; 

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    
        modelBuilder.Entity<Customer>()
            .HasKey(c => c.CustomerId);

        modelBuilder.Entity<Customer>()
            .Property(c => c.FirstName)
            .HasColumnType("varchar(50)")
            .HasMaxLength(50)
            .IsRequired();

        modelBuilder.Entity<Customer>()
            .Property(c => c.LastName)
            .HasColumnType("varchar(50)")
            .HasMaxLength(50)
            .IsRequired();

        modelBuilder.Entity<City>()
            .HasKey(ci => ci.ID);

        modelBuilder.Entity<City>()
            .Property(ci => ci.Name)
            .HasColumnType("varchar(50)")
            .HasMaxLength(50)
            .IsRequired();

        modelBuilder.Entity<City>()
            .HasMany(ci => ci.Customers)
            .WithOne(c => c.City)
            .HasForeignKey(c => c.CityId);

        modelBuilder.Entity<City>()
            .HasMany(l => l.Localities)
            .WithOne(ci => ci.City)
            .HasForeignKey(ci => ci.CityId);

        modelBuilder.Entity<Locality>()
            .HasKey(l => l.ID);

        modelBuilder.Entity<Locality>()
            .Property(l => l.Name)
            .HasColumnType("varchar(50)")
            .HasMaxLength(50)
            .IsRequired();

        modelBuilder.Entity<Locality>()
            .HasMany(l => l.Customers)
            .WithOne(c => c.Locality)
            .HasForeignKey(c => c.LocalityId);

        modelBuilder.Entity<Locality>()
            .HasMany(sl => sl.SubLocalities)
            .WithOne(l => l.Locality)
            .HasForeignKey(l => l.LocalityId);

        modelBuilder.Entity<SubLocality>()
            .HasKey(sl => sl.ID);

        modelBuilder.Entity<SubLocality>()
            .Property(sl => sl.Name)
            .HasColumnType("varchar(50)")
            .HasMaxLength(50)
            .IsRequired();

        modelBuilder.Entity<SubLocality>()
            .HasMany(sl => sl.Customers)
            .WithOne(c => c.SubLocality)
            .HasForeignKey(c => c.SubLocalityId);
    

CustomerFormVM

public class CustomerFormVM

    [Required(ErrorMessage = "Please enter a First Name")]
    [Display(Name = "First Name")]
    public string FirstName  get; set; 

    [Required(ErrorMessage = "Please enter a Last Name")]
    [Display(Name = "Last Name")]
    public string LastName  get; set; 

    [Required(ErrorMessage = "Please select a city")]
    [Display(Name = "City")]
    public int? SelectedCity  get; set; 
    [Required(ErrorMessage = "Please select a locality")]

    [Display(Name = "Locality")]
    public int? SelectedLocality  get; set; 
    [Required(ErrorMessage = "Please select a sub locality")]
    [Display(Name = "Sub Locality")]
    public int? SelectedSubLocality  get; set; 

    public SelectList CityList  get; set; 
    public SelectList LocalityList  get; set; 
    public SelectList SubLocalityList  get; set; 

客户控制器

public class CustomersController : Controller

    private readonly WebAppDbContext _context;

    public CustomersController(WebAppDbContext context)
    
        _context = context;    
    


    // GET: Customers
    public async Task<IActionResult> Index()
    
        var webAppDbContext = _context.Customers.Include(c => c.City).Include(c => c.Locality).Include(c => c.SubLocality);
        return View(await webAppDbContext.ToListAsync());
    


    // GET: Customers/Details/5
    public async Task<IActionResult> Details(int? id)
    
        if (id == null)
        
            return NotFound();
        

        var customer = await _context.Customers
            .Include(c => c.City)
            .Include(c => c.Locality)
            .Include(c => c.SubLocality)
            .SingleOrDefaultAsync(m => m.CustomerId == id);

        if (customer == null)
        
            return NotFound();
        

        return View(customer);
    


    // GET: Customers/Create
    [HttpGet]
    public ActionResult Create()
    
        CustomerFormVM model = new CustomerFormVM();
        ConfigureViewModel(model);
        return View(model);
    


    // POST: Customers/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(CustomerFormVM vm)
    
        if (ModelState.IsValid)
        
            var customer = new Customer();
            
                customer.FirstName = vm.FirstName;
                customer.LastName = vm.LastName;
                customer.CityId = vm.SelectedCity.Value;
                customer.LocalityId = vm.SelectedLocality.Value;
                customer.SubLocalityId = vm.SelectedSubLocality.Value;
            
            _context.Customers.Add(customer);
            _context.SaveChanges();
            return RedirectToAction("Index");
        

        else
        
            ConfigureViewModel(vm);
            return View(vm);
        
    


    [HttpGet]
    public JsonResult FetchLocalities(int ID)
    
        var data = _context.Localities
            .Where(l => l.CityId == ID)
            .Select(l => new  val = l.ID, text = l.Name );
        return Json(data);
    


    [HttpGet]
    public JsonResult FetchSubLocalities(int ID)
    
        var data = _context.SubLocalities
            .Where(l => l.LocalityId == ID)
            .Select(l => new  val = l.ID, text = l.Name );
        return Json(data);
    


    private void ConfigureViewModel(CustomerFormVM model)
    
        List<City> cities = _context.Cities.ToList();
        model.CityList = new SelectList(cities, "ID", "Name");
        if (model.SelectedCity.HasValue)
        
            IEnumerable<Locality> localities = _context.Localities.Where(l => l.CityId == model.SelectedCity.Value);
            model.LocalityList = new SelectList(localities, "ID", "Name");
        
        else
        
            model.LocalityList = new SelectList(Enumerable.Empty<SelectListItem>());
        
        if (model.SelectedLocality.HasValue)
        
            IEnumerable<SubLocality> subLocalities = _context.SubLocalities.Where(l => l.LocalityId == model.SelectedLocality.Value);
            model.SubLocalityList = new SelectList(subLocalities, "ID", "Name");
        
        else
        
            model.SubLocalityList = new SelectList(Enumerable.Empty<SelectListItem>());
        
    


    public ActionResult Edit(int? id)
    
        if (id == null)
        
            return NotFound();
        

        var customervm = new CustomerFormVM();
        
            Customer customer = _context.Customers.SingleOrDefault(c => c.CustomerId == id);

            if (customer == null)
            
                return NotFound();
            

            customervm.CustomerId = customer.CustomerId;
            customervm.FirstName = customer.FirstName;
            customervm.LastName = customer.LastName;
        
        return View(customervm);
    


    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(CustomerFormVM vmEdit)
    
        if (ModelState.IsValid)
        
            Customer customer = _context.Customers.SingleOrDefault(c => c.CustomerId == vmEdit.CustomerId);

            if (customer == null)
            
                return NotFound();
            

            customer.FirstName = vmEdit.FirstName;
            customer.LastName = vmEdit.LastName;

            _context.Entry(customer).State = EntityState.Modified;
            _context.SaveChanges();
            return RedirectToAction("Index");
        
        return View(vmEdit);
    


    // GET: Customers/Delete/5
    public async Task<IActionResult> Delete(int? id)
    
        if (id == null)
        
            return NotFound();
        

        var customer = await _context.Customers
            .Include(c => c.City)
            .Include(c => c.Locality)
            .Include(c => c.SubLocality)
            .SingleOrDefaultAsync(m => m.CustomerId == id);
        if (customer == null)
        
            return NotFound();
        

        return View(customer);
    


    // POST: Customers/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> DeleteConfirmed(int id)
    
        var customer = await _context.Customers.SingleOrDefaultAsync(m => m.CustomerId == id);
        _context.Customers.Remove(customer);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    

    private bool CustomerExists(int id)
    
        return _context.Customers.Any(e => e.CustomerId == id);
    

创建视图

@using (html.BeginForm("Create", "Customers"))

    <div class="form-group">
        @Html.LabelFor(c => c.FirstName)
        @Html.TextBoxFor(c => c.FirstName, new  @class = "form-control" )
    </div>

    <div class="form-group">
        @Html.LabelFor(c => c.LastName)
        @Html.TextBoxFor(c => c.LastName, new  @class = "form-control" )
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.SelectedCity)
        @Html.DropDownListFor(m => m.SelectedCity, Model.CityList, "Please select", new  @class = "form-control" )
        @Html.ValidationMessageFor(m => m.SelectedCity)
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.SelectedLocality)
        @Html.DropDownListFor(m => m.SelectedLocality, Model.LocalityList, "", new  @class = "form-control" )
        @Html.ValidationMessageFor(m => m.SelectedLocality)
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.SelectedSubLocality)
        @Html.DropDownListFor(m => m.SelectedSubLocality, Model.SubLocalityList, "", new  @class = "form-control" )
        @Html.ValidationMessageFor(m => m.SelectedSubLocality)
    </div>

    <div class="form-group">
        <input type="submit" value="Save" class="btn btn-default" />
    </div>



<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts 
    @await Html.RenderPartialAsync("_ValidationScriptsPartial");
    
    <script type="text/javascript">
			var localityUrl = '@Url.Action("FetchLocalities")';
			var subLocalityUrl = '@Url.Action("FetchSubLocalities")';
            var localities = $('#SelectedLocality');
            var subLocalities = $('#SelectedSubLocality');
            $('#SelectedCity').change(function() 
				localities.empty();
				subLocalities.empty();
				$.getJSON(localityUrl,  ID: $(this).val() ,function (data) 
					if (!data) 
						return;
					
					localities.append($('<option></option>').val('').text('Please select'));
					$.each(data, function(index, item) 
						localities.append($('<option></option>').val(item.val).text(item.text));
					);
				);
			)
            $('#SelectedLocality').change(function() 
				subLocalities.empty();
                $.getJSON(subLocalityUrl,  ID: $(this).val() ,function (data) 
					if (!data) 
						return;
					
                    subLocalities.append($('<option></option>').val('').text('Please Select'));
					$.each(data, function(index, item) 
						subLocalities.append($('<option></option>').val(item.val).text(item.text));
					);
				);
			)

</script>

编辑视图

@using (Html.BeginForm("Edit", "Customers"))

    <div class="form-group">
        @Html.LabelFor(c => c.FirstName)
        @Html.TextBoxFor(c => c.FirstName, new  @class = "form-control" )
    </div>

    <div class="form-group">
        @Html.LabelFor(c => c.LastName)
        @Html.TextBoxFor(c => c.LastName, new  @class = "form-control" )
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.SelectedCity)
        @Html.DropDownListFor(m => m.SelectedCity, Model.CityList, "Please select", new  @class = "form-control" )
        @Html.ValidationMessageFor(m => m.SelectedCity)
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.SelectedLocality)
        @Html.DropDownListFor(m => m.SelectedLocality, Model.LocalityList, "", new  @class = "form-control" )
        @Html.ValidationMessageFor(m => m.SelectedLocality)
    </div>

    <div class="form-group">
        @Html.LabelFor(m => m.SelectedSubLocality)
        @Html.DropDownListFor(m => m.SelectedSubLocality, Model.SubLocalityList, "", new  @class = "form-control" )
        @Html.ValidationMessageFor(m => m.SelectedSubLocality)
    </div>

    @Html.HiddenFor(m => m.CustomerId)

    <div class="form-group">
        <input type="submit" value="Save" class="btn btn-default" />
    </div>


<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts 
    @await Html.RenderPartialAsync("_ValidationScriptsPartial");

<script type="text/javascript">
			var localityUrl = '@Url.Action("FetchLocalities")';
			var subLocalityUrl = '@Url.Action("FetchSubLocalities")';
            var localities = $('#SelectedLocality');
            var subLocalities = $('#SelectedSubLocality');
            $('#SelectedCity').change(function() 
				localities.empty();
				subLocalities.empty();
				$.getJSON(localityUrl,  ID: $(this).val() ,function (data) 
					if (!data) 
						return;
					
					localities.append($('<option></option>').val('').text('Please select'));
					$.each(data, function(index, item) 
						localities.append($('<option></option>').val(item.val).text(item.text));
					);
				);
			)
            $('#SelectedLocality').change(function() 
				subLocalities.empty();
                $.getJSON(subLocalityUrl,  ID: $(this).val() ,function (data) 
					if (!data) 
						return;
					
                    subLocalities.append($('<option></option>').val('').text('Please Select'));
					$.each(data, function(index, item) 
						subLocalities.append($('<option></option>').val(item.val).text(item.text));
					);
				);
			)

</script>

【问题讨论】:

您确定 JQUERY 工作正常吗?在视图中,我在部分脚本中放置了这个标记 (更改正确的版本)。 是的,jQuery 代码在我这边工作。 jQuery 2.2.0 我的 Create 方法有相同的 jQuery 代码,它工作正常,唯一的问题是我无法根据为 Edit 方法选择的 CustomerId 检索 CityId。 为什么需要这个`$("#StateId").trigger('change');`?您的页面将使用您拥有的服务器代码在下拉列表中加载所选城市。 建议您参考this answer了解如何正确处理 【参考方案1】:

可能你在视图上错过了这个指令:

@using (Html.BeginForm("ActionName", "ControllerName", FormMethod.Post, new  @class = "form-horizontal", role = "form" ))

【讨论】:

我用你提供的东西替换了我拥有的东西,但我得到了相同的结果。

以上是关于使用 ASP.NET Core MVC 编辑 Cascade DropDownList的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 SelectListItem 无法编辑 ASP.NET Core MVC

如何在 ASP.NET Core MVC 中使用 select 标签动态编辑数据库表?

ASP.NET Core MVC:在发布编辑方法之前删除多对多条目

ASP.NET CORE MVC使用SCD(独立部署)发布

ASP.NET Core MVC 2.x 全面教程_ASP.NET Core MVC 17. 基于Claim和Policy的授权 上

ASP.NET MVC或者.net Core mvc 页面使用富文本控件的 保存问题