Razor Page Partial 呈现 Input 和隐藏的 Input

Razor Page Partial renders Input and hidden Input

我在使用 ASP .net core 2.2 Razor Pages 时遇到了一个非常奇怪的行为。

假设我有一个标准的 Razor Page。用户可以通过该页面发送请求,以获取应配置的新团队。我有一些字段,例如 DisplayName 等,用户可以自由编辑这些字段,还有一个下拉菜单供他选择 select 他想从哪个现有团队克隆一些设置。在用户 select 编辑它之后,我使用 Ajax 在视图的右侧呈现部分视图,用户还可以 select 一些额外的选项。直到这里我都很好,到目前为止一切正常。我预计,如果用户单击保存/提交按钮,所有内容都将包含在 post 请求中,即使是部分视图数据。在四处挖掘和排除故障后,我发现我必须设置 ViewData.TemplateInfo.HtmlFieldPrefix 来命名父视图中​​的所有内容,以免弄乱绑定。也适用。

奇怪的行为是,在呈现局部视图后,在 HTML 两个 输入字段中生成。一种是用户可以 select 的,另一种是隐藏的。我将展示我的代码以及呈现的 HTML 文件,以便大家可以自己制作一张照片。现在发生的是,隐藏字段具有默认值或空值,这些将包含在请求中。我不知道它们来自哪里和/或如何修复它或我做错了什么?

我会稍微缩短我的代码,但我会包含必要的部分。

团队请求模型

public class TeamRequestModel
    {
        public string DisplayName { get; set; }
        public string Description { get; set; }
        public string Visibility { get; set; }
        public List<string> Owners { get; set; }
        public string CloneTeamID { get; set; }
        public TeamCloneSettings TeamCloneSettings { get; set; }

        public TeamRequestModel()
        {
            TeamCloneSettings = new TeamCloneSettings();
        }
    }

团队克隆设置(用户只能设置部件

    public class TeamCloneSettings
    {
        [JsonProperty(PropertyName = "id")]
        public string Id { get; set; }
        public string PartitionKey;
        public string DisplayName { get; set; }
        public bool Released { get; set; }
        public bool FixedVisibility { get; set; }
        public string Visibility { get; set; }
        public bool CloneEverything { get; set; }
        public TeamCloneParts Parts { get; set; }

        public TeamCloneSettings()
        {
            Parts = new TeamCloneParts();
        }
    }

    public class TeamCloneParts
    {
        public bool CloneApps { get; set; }
        public bool CloneChannels { get; set; }
        public bool CloneTabs { get; set; }
        public bool CloneSettings { get; set; }
    }
}

主要"Team Request View"

@page
@model iwDashboard.Pages.Teams.TeamRequest
@{
    ViewData["Title"] = Model.Title;
}

@{
    ViewBag.PageTitle = Model.Title;
}

<style>
    textarea {
        resize: none;
    }
</style>

<section class="content">
    <form method="post" asp-page-handler="SaveTeamRequest" class="col-md-12">
        <div class="row">
            <div class="col-md-3">
                <div class="card card-primary">
                    <div class="card-header">
                        <h3 class="card-title">Team Details</h3>
                    </div>
                    <div class="card-body">
                        <div class="form-group">
                            <label for="displayName">Display Name</label>
                            <input id="displayName" asp-for="@Model.teamRequest.DisplayName" type="text" class="form-control" required />
                        </div>
                        ... More fields
                        <div style="float: left; width: 40%">
                            <button type="button" onclick="history.go(-1)" data-toggle="tooltip" title="Back" class="btn btn-primary btn-block btn-sm"><i class="fa fa-arrow-circle-left"></i><b>  Back</b></button>
                        </div>
                        <div style="float: right; width: 40%">
                            <button type="submit" data-toggle="tooltip" title="Save" class="btn btn-success btn-block btn-sm"><i class="fas fa-save"></i><b>  Save</b></button>
                        </div>
                    </div>
                    <!-- /.card-body -->
                </div>
                <!-- /.card -->
            </div>
            <div class="col-md-6">
                <div class="card card-secondary">
                    <div class="card-header">
                        <h3 class="card-title">Team Settings</h3>
                    </div>
                    <div class="card-body">
                        <!--partial comes here-->
                        <div id="partialDiv"></div>
                    </div>
                    <!-- /.card-body -->
                </div>
                <!-- /.card -->
            </div>
        </div>
    </form>
</section>

@section Scripts
{
    <script>
        function GetTeamTemplateProperties() {
            var selectedTeam = $('#teamTemplateSelection').val();
            $.ajax({
                type: "Get",
                beforeSend: function (xhr) {
                    xhr.setRequestHeader("XSRF-TOKEN",
                        $('input:hidden[name="__RequestVerificationToken"]').val());
                },
                url: '/Teams/TeamRequest?handler=TeamTemplateProperties',
                data: {
                    SelectedTeam: selectedTeam
                },
                success: function (result) {
                    $("#partialDiv").after(result);
                }
            })
        };
    </script>
}

获取由 Ajax

调用的模板属性 Post
public async Task<IActionResult> OnGetTeamTemplateProperties(string SelectedTeam)
        {
            TeamCloneSettings teamCloneSettings = new TeamCloneSettings();
            teamRequest = new TeamRequestModel();
            if (!string.IsNullOrEmpty(SelectedTeam))
            {
                teamCloneSettings = await _teamCloneSettingService.GetTeamCloneSettingByIdAsync(SelectedTeam);
                teamRequest.TeamCloneSettings = teamCloneSettings;
            }

            ViewData.TemplateInfo.HtmlFieldPrefix = "teamRequest";
            SelectedValue = SelectedTeam;
            return new PartialViewResult
            {
                ViewName = "_TeamCloneSettingsPartial",
                ViewData = new ViewDataDictionary<TeamRequestModel>(ViewData, teamRequest)
            };
        }

查看模型 BindProperty

...More Code

[BindProperty]
public TeamRequestModel teamRequest { get; set; }
[BindProperty]
public string SelectedValue { get; set; }

...More Code

_TeamCloneSettingsPartial

@model iwDashboard.Models.TeamRequestModel

@{
    <!--
        Check if fixed visibility is enabled and
        disable selection of visibility if it is
    -->
    string disabled = null;
    string options = null;
    if (Model.TeamCloneSettings.FixedVisibility)
    {
        disabled = "disabled";
        options = Model.Visibility;
    }
}
<div class="form-group">
    <input type="checkbox" hidden id="cloneEverthing" checked=@Model.TeamCloneSettings.CloneEverything>
    <ul class="list-group list-group-unbordered mb-3">
        <li class="list-group-item">
            <label for="visibility">Visibility</label>
            <select class="form-control @disabled custom-select" asp-for="TeamCloneSettings.Visibility" required>
                @if (!string.IsNullOrEmpty(disabled))
                {
                    <option readonly selected>@Model.TeamCloneSettings.Visibility</option>
                }
                else
                {
                    <option>Public</option>
                    <option>Private</option>
                }
            </select>
        </li>
        <!-- Checkbox parts here
            Javascript will check if "CloneEverything"
            is enabled and will disable all of the following checkboxes
        -->
        <li class="list-group-item">
            <div class="form-group">
                <div class="custom-control custom-switch">
                    <input type="checkbox" class="custom-control-input" id="cloneApps" checked=@Model.TeamCloneSettings.Parts.CloneApps asp-for="TeamCloneSettings.Parts.CloneApps">
                    <label class="custom-control-label" for="cloneApps">Clone Apps</label>
                </div>
            </div>
        </li>
        <li class="list-group-item">
            <div class="form-group">
                <div class="custom-control custom-switch">
                    <input type="checkbox" class="custom-control-input" id="cloneChannels" checked=@Model.TeamCloneSettings.Parts.CloneChannels asp-for="TeamCloneSettings.Parts.CloneChannels">
                    <label class="custom-control-label" for="cloneChannels">Clone Channels</label>
                </div>
            </div>
        </li>
        <li class="list-group-item">
            <div class="form-group">
                <div class="custom-control custom-switch">
                    <input type="checkbox" class="custom-control-input" id="cloneSettings" checked=@Model.TeamCloneSettings.Parts.CloneSettings asp-for="TeamCloneSettings.Parts.CloneSettings">
                    <label class="custom-control-label" for="cloneSettings">Clone Settings</label>
                </div>
            </div>
        </li>
        <li class="list-group-item">
            <div class="form-group">
                <div class="custom-control custom-switch">
                    <input type="checkbox" class="custom-control-input" id="cloneTabs" checked=@Model.TeamCloneSettings.Parts.CloneTabs asp-for="TeamCloneSettings.Parts.CloneTabs">
                    <label class="custom-control-label" for="cloneTabs">Clone Tabs</label>
                </div>
            </div>
        </li>
    </ul>
</div>

呈现奇怪的输入字段

https://i.stack.imgur.com/aZtUD.png

如您所见,Input 被渲染了两次,只有隐藏的值会被传输。但这只发生在部分视图中的输入字段,所有其他字段都很好。

有什么想法吗?会很棒:-).

非常感谢!!

在复选框上使用 asp-for 标签助手时,生成 2 个输入字段是正常的。它将创建复选框本身,但也会为模型活页夹创建一个隐藏的输入字段,以发送用户选择的值。

只有标签助手生成的隐藏字段才会被用来发送数据。

在这里找到了解决方案:

asp.net mvc: why is Html.CheckBox generating an additional hidden input

可能不是最好的,但对我有用:

检查 Javascript 是否选中复选框,然后设置隐藏字段的值:

if ($('[name="foo"]:checked').length > 0)
    $('[name="foo"]:hidden').val(true);

谢谢大家!