asp.net-core-mvc - 创建视图以添加具有列表属性的新空模型
问题描述
我的 MVC 应用程序的用户能够创建新的“事件”。每个“事件”都有一些属性,例如名称、位置……每个“事件”也有一个或多个“时间范围”。当用户想要创建新的“事件”时,AddEvent 视图默认为 1 个时间范围,但用户可以添加额外的时间范围。视图看起来像这样:
(来源:telnet.be)
我可以通过结合使用 Taghelpers 和 Jquery 来完成这项工作。
模型:
public class Event
{
public Event()
{
Timeframes = new List<TimeFrame>();
Participants = new List<Participant>();
}
public int Id { get; set; }
[Required]
[Display(Name="Event Name")]
[MaxLength(50, ErrorMessage ="The name you've entered is too long")]
public string Name { get; set; }
[Required]
[MaxLength(500, ErrorMessage = "The description you've entered is too long")]
public string Description { get; set; }
[Required]
[Range(1,int.MaxValue, ErrorMessage ="Enter a valid number larger than 0")]
public int WantedAmountOfParticipants { get; set; }
public List<TimeFrame> Timeframes { get; set; }
public Location Location { get; set; }
public List<Participant> Participants { get; set; }
public bool IsCancelled { get; set; }
}
看法:
<form method="post">
<partial name="Partials/_EventBasicInputDetails" model="Model" />
<div id="TimeFramesToAdd">
@for (var i = 0; i < Model.Timeframes.Count; i++)
{
<div class="timeframes" id="Timeframe_@i">
<label asp-for="Timeframes[i].EventDate"></label>
<input asp-for="Timeframes[i].EventDate" min="@DateTime.Today" />
<span asp-validation-for="Timeframes[i].EventDate"></span>
<label asp-for="Timeframes[i].Starttime"></label>
<input asp-for="Timeframes[i].Starttime" min="0" max="24" />
<span asp-validation-for="Timeframes[i].Starttime"></span>
<label asp-for="Timeframes[i].Endtime"></label>
<input asp-for="Timeframes[i].Endtime" min="0" max="24" />
<span asp-validation-for="Timeframes[i].Endtime"></span>
<button type="button" class="DeleteTimeframeButton" data-id="@i">Delete Timeframe</button>
</div>
}
</div>
<a href="#" id="addTimeframe">Add Timeframe</a>
<div>
<a asp-action="AllUpcomingEvents">Cancel</a>
<input type="submit" name="Add" value="Add" />
</div>
</form>
jQuery
//Add empty timeframes when adding event
$("#addTimeframe").click(function (e) {
e.preventDefault();
//Set counter for dynamical generation of ID attributes for modelbinding
var i = $(".timeframes").length;
//Html element to be added
var newTimeframe = `<div class="timeframes" id="Timeframe_` + i + `">
<label for= "Timeframes_` + i + `__EventDate" > Event Date</label >
<input type="date" data-val="true" data-val-required="The Event Date field is required." id="Timeframes_` + i + `__EventDate" name="Timeframes[` + i + `].EventDate" />
<span class="field-validation-valid" data-valmsg-for="Timeframes[` + i + `].EventDate" data-valmsg-replace="true"></span>
<label for="Timeframes_` + i + `__Starttime">Start</label>
<input min="0" max="24" type="number" data-val="true" data-val-range="Invalid hour" data-val-range-max="24" data-val-range-min="0" data-val-required="The Start field is required." id="Timeframes_` + i + `__Starttime" name="Timeframes[` + i + `].Starttime" value="0" />
<span class="field-validation-valid" data-valmsg-for="Timeframes[` + i + `].Starttime" data-valmsg-replace="true"></span>
<label for="Timeframes_` + i + `__Endtime">End</label>
<input min="0" max="24" type="number" data-val="true" data-val-range="Invalid hour" data-val-range-max="24" data-val-range-min="0" data-val-required="The End field is required." id="Timeframes_` + i + `__Endtime" name="Timeframes[` + i + `].Endtime" value="0" />
<span class="field-validation-valid" data-valmsg-for="Timeframes[` + i + `].Endtime" data-valmsg-replace="true"></span>
<button type="button" id="DeleteTimeframeButton_` + i + `" class="DeleteTimeframeButton" data-id=` + i + `>Delete Timeframe</button>
</div>`
//Set click event on generated button
$("#TimeFramesToAdd").append(newTimeframe);
var button = $("#DeleteTimeframeButton_" + i);
button.click(removeTimeframe);
});
//***Helper Functions***
function removeTimeframe() {
if ($(".timeframes").length > 1) {
var timeframeToRemove = "#Timeframe_" + $(this).data('id');
$(timeframeToRemove).remove();
}
}
这工作得很好,但请注意用于创建新时间框架的 HTML 元素的巨大魔术字符串。这似乎不是处理这个问题的最佳方法。有什么建议么?
解决方案
使用 jQuery 生成 TimeFrame 元素无需使用这么多魔术字符串。最简单的方法是重用服务器端函数来生成部分表单:
首先,创建一个部分视图/Views/Shared/_TimeFrames.cshtml
:
@model App.Models.Event
@{
// add a blank one for rendering
if(Model.Timeframes==null){
Model.Timeframes= new List<TimeFrame>(){};
}
if(Model.Timeframes.Count==0){
Model.Timeframes.Add(new TimeFrame());
}
var i = 0;
}
<div class="timeframes">
<label asp-for= "@Model.Timeframes[i].EventDate" ></label>
<input asp-for= "@Model.Timeframes[i].EventDate" />
<span class="field-validation-valid" asp-validation-for="@Model.Timeframes[i].EventDate" ></span>
<label asp-for="@Model.Timeframes[i].Starttime">Start</label>
<input asp-for="@Model.Timeframes[i].Starttime" />
<span class="field-validation-valid" asp-validation-for="@Model.Timeframes[i].Starttime" ></span>
<label asp-for="@Model.Timeframes[i].Endtime">End</label>
<input asp-for="@Model.Timeframes[i].Endtime" />
<span class="field-validation-valid" asp-validation-for="@Model.Timeframes[i].Endtime"></span>
<button type="button" class="DeleteTimeframeButton" onclick="$(this).parent().remove();return false;"> Delete Timeframe</button>
</div>
如您所见,我们现在能够以TimeFrame
强类型的方式生成 的字段。名称、ID、DisplayNames 和验证规则是自动生成的。您可以自由添加自己的规则。
现在我们可以将其渲染TimeFrame
到客户端模板中,并TimeFrame
在有人单击“#addTimeframe”按钮时重用它来生成 html 元素:
<script id="timeframe-template-rendered" type="text/plain" >
@Html.Partial("/Views/Shared/_TimeFrames.cshtml",new App.Models.Event())
</script>
<!-- a helper that renders the client side template -->
<script>
function partialFormRenderer(templateStr,index=0){
var itemTpl = templateStr
.replace("_"+index+"__","${i}")
.split(/\$\{(.+?)\}/g);
return function render(model){
return itemTpl.map((token,idx)=> idx%2 ===0 ? token : model[token]).join('');
};
}
// create a render function with the client side template
var render = partialFormRenderer(document.getElementById("timeframe-template-rendered").innerHTML);
</script>
<script>
$("#addTimeframe").click(function (e) {
e.preventDefault();
var i = $(".timeframes").length;
var newTimeframe = render(i);
$("#TimeFramesToAdd").append(newTimeframe);
});
</script>
推荐阅读
- javascript - Office JavaScript Web 插件未更新
- android - 是材料设计,colorPrimary = 500,colorPrimaryDark 必须是 700?
- react-native - 当组件不属于堆栈导航器时的 props.navigation
- cmake - 无法在 Windows 10 上安装 Theano libgpuarray
- python - 在 Django 中构建 Firebase 谷歌登录
- python - 将编码更改为utf8mb4后mysql的字符串值不正确
- c++ - 为什么我在使用 for 循环和 cout 命令时没有打印出向量
- javascript - 如何从表单中获取数据并将输入添加到 Mysql 表中。使用 JQuery
- python-3.x - 蟒蛇 | 将文件从共享文件夹复制到本地文件夹
- css - 离子网格布局对齐不正确