从多级动态集合添加下拉列表



我有这些模型。

项目视图模型

public class ProjectViewModel
{
//some properties..
public IList<ScopeOfWorkViewModel> ScopeOfWork { get; set; }
}

工作范围视图模型

public class ScopeOfWorkViewModel
{
//some properties
public IList<MaterialsViewModel> Materials { get; set; }
}

材料视图模型

public class MaterialsViewModel
{
public int MaterialId { get; set; }
[Display(Name = "Material")]
public string MaterialName { get; set; }
public int? Quantity { get; set; }
public double? Cost { get; set; }
public int? ScopeOfWorkId { get; set; }
// should be a drop down list and get its data from database
public IEnumerable<SelectListItem> CategoryList { get; set; }
}

类别模型

public partial class tblCategory
{
public tblCategory()
{
this.tblMaterials = new HashSet<tblMaterial>();
}
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public virtual ICollection<tblMaterial> tblMaterials { get; set; }
}

这是我的观点

@model MigratingDB.Models.ProjectViewModel
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal" id="ProjectForm">
<h4>ProjectViewModel</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
Dynamically add ScopeOfWork and Materials<br />
<a href="javascript:void(0)" id="addScope">Add Scope of Work</a>
<div id="scopes">
<div class="scope">
<div class="materials">
<div class="material">
</div>
</div>
</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>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>

<div id="newScope" style="display:none">
<div class="scope">
<h3>Scope</h3>
<div class="form-group">
<label for="_#__ScopeOfWorkName" class="control-label col-md-2">Scope Of Work</label>
<div class="col-md-10">
<input class="form-control" type="text" id="_#__ScopeOfWorkName" name="ScopeOfWork[#].ScopeOfWorkName" value="">
</div>
</div>
<input type="hidden" class="scopeindex" name="ScopeOfWork.Index" value="#" />
<div class="materials">
<h4>Material</h4>
<a href="javascript:void(0)" class="addmaterial">Add Material</a>
</div>
</div>
</div>
<div id="newMaterial" style="display:none">
<div class="form-group">
<label for="_#__Materials_%__MaterialName" class="control-label col-md-2">Material</label>
<div class="col-md-2">
<input class="form-control" type="text" id="_#__Materials_%__MaterialName" name="ScopeOfWork[#].Materials[%].MaterialName" value="">
</div>
</div>
<div class="form-group">
<label for="_#__Materials_%__Quantity" class="control-label col-md-2">Quantity</label>
<div class="col-md-1">
<input class="form-control" type="text" id="_#__Materials_%__Quantity" name="ScopeOfWork[#].Materials[%].Quantity" value="">
</div>
</div>
<div class="form-group">
<label for="_#__Materials_%__Cost" class="control-label col-md-2">Cost</label>
<div class="col-md-1">
<input class="form-control" type="text" id="_#__Materials_%__Cost" name="ScopeOfWork[#].Materials[%].Cost" value="">
</div>
</div>
//build a category drop down list here
<input type="hidden" class="materialindex" name="ScopeOfWork[#].Materials.Index" value="%" />
</div>
<script>
var form = $('form');
var scope = $('#newScope');
var material = $('#newMaterial');
form.on('click', '.addmaterial', function () {
var clone = material.clone();
var scopeIndex = $(this).closest('.scope').find('.scopeindex').val();
clone.html($(clone).html().replace(/#/g, scopeIndex));
var materialIndex = new Date().getTime();
clone.html($(clone).html().replace(/%/g, materialIndex));
$(this).closest('.materials').append(clone.html());
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});
$('#addScope').click(function () {
var clone = scope.clone();
var scopeIndex = new Date().getTime();
clone.html($(clone).html().replace(/#/g, scopeIndex));
$('#scopes').append(clone.html());
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});
</script>

请帮助我在每次创建 MaterialViewModel 对象并将其发布到我的数据库时为类别构建下拉列表。我有一个类别表,我想在其中传递其值以生成下拉列表。我更喜欢使用强类型模型而不是使用ViewBag

您的ProjectViewModel需要一个属性IEnumerable<SelectListItem>(或包含选项值和文本的 2 个属性的类的IEnumerable),以便您可以将选项值传递给视图(如果没有现有的MaterialsViewModel)。您的MaterialsViewModel还需要一个属性来将所选类别绑定到。

public class ProjectViewModel
{
// some properties..
public IEnumerable<SelectListItem> CategoryList { get; set; }
public IList<ScopeOfWorkViewModel> ScopeOfWork { get; set; }
}
....
public class MaterialsViewModel
{
public int MaterialId { get; set; }
....
// public int? ScopeOfWorkId { get; set; } this is not required
public int SelectedCategory { get; set; }
public IEnumerable<SelectListItem> CategoryList { get; set; }
}

然后在GET方法中,初始化视图模型并填充CategoryList,例如

IEnumerable categories = db.tblCategory; // select all categories
ProjectViewModel model = new ProjectViewModel()
{
CategoryList = new SelectList(categories, "CategoryId", "CategoryName"),
.... set other properties as required
};
return View(model);

在视图中,包含一个脚本,用于将CategoryList转换为 javascript 数组

<script>
var form = $('form');
....
var categories = @Html.Raw(Json.Encode(Model.CategoryList));
form.on('click', '.addmaterial', function () {
....

然后在模板(在 ' 元素中)中,为 select 控件添加 html(但如果需要,除了标签选项之外没有任何选项)。记下要选择的其他类名。

<div class="form-group">
<label for="_#__Materials_%__SelectedCategory" class="control-label col-md-2">Cost</label>
<div class="col-md-1">
<select class="form-control category" id="_#__Materials_%__SelectedCategory" name="ScopeOfWork[#].Materials[%].SelectedCategory">
<option value="">Please select a category</option>
</select>
</div>
</div>

并修改脚本以根据 JavaScript 数组中的值添加选项。

form.on('click', '.addmaterial', function () {
var clone = material.clone();
....
clone.html($(clone).html().replace(/%/g, materialIndex));
// Add the options
var select = clone.find('.category');
$.each(categories, function(index, item) {
select.append($('<option></option>').val(item.Value).text(item.Text));
});
$(this).closest('.materials').append(clone.html());
form.data('validator', null);
$.validator.unobtrusive.parse(form);
});

请注意,您不会为现有项目呈现任何html,因此如果有任何内容无效并且您返回视图,则用户动态添加的所有数据都将丢失 - 您需要嵌套for循环。并且您不会渲染 html 以验证动态添加的元素。

最新更新