创建用于添加具有列表属性的新空模型的视图

时间:2019-04-26 09:48:02

标签: asp.net-core-mvc

我的MVC应用程序的用户可以创建新的“事件”。每个“事件”都有一些属性,例如名称,位置等。每个“事件”也都有一个或多个“时间范围”。当用户想要创建一个新的“事件”时,AddEvent视图默认为1个时间范围,但是用户可以添加额外的时间范围。视图看起来像这样:

Create view http://users.telenet.be/evdes/Capture.PNG

我可以结合使用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元素的巨大魔术字符串。这似乎不是解决此问题的最佳方法。有什么建议吗?

1 个答案:

答案 0 :(得分:0)

无需使用太多魔术字符串即可通过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,DisplayName和验证规则是自动生成的。您可以自由添加自己的规则。

现在我们可以将TimeFrame渲染到客户端模板中,并在有人单击“ #addTimeframe”按钮时重新使用它来生成TimeFrame 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>