我的页面中有一个<select>
元素,我想获得它的值。为了做到这一点,我加入了@bind=
的性质。下面是代码:
<form target="#">
<label for="subject">Vak</label>
<select @bind="@selectedSubject" id="subject">
@foreach (Subject subject in Auth.User.Subjects)
{
<option value="@subject.Uuid">@subject.Name</option>
}
</select><br />
<!-- (more input fields) -->
<button class="button btn-primary mt-3" @onclick="addNote">Toevoegen</button>
</form>
@code {
private String selectedSubject { get; set; }
private String inputTitle { get; set; }
private String inputContent { get; set; }
private void addNote()
{
Console.WriteLine(selectedSubject);
}
}
这不输出任何东西,并试图使用selectedSubject
导致NullReferenceError。其他值(inputTitle
,inputContent
)工作正常
对,<select>
被<option>
正确填充。
我试过切换到任何<EditForm>
是,但它一直给我警告,未能构建。
首先,您根本不需要表单。EditForm的主要目的是验证输入——例如,确保密码的格式正确。
另外,除非你想通过编程设置下拉菜单的值,否则你不需要绑定它——相反,使用@onchange
:
<select @onchange=ProcessSelection>
. . .
@code {
Subject SelectedSubject {get; set;}
async Task ProcessSelection (ChangeEventArgs args){
SelectedSubject = Auth.User.Subjects.Single(s=>s.uuid = args.Value.ToString();
// Process the selection.
}
}
这将(1)为调试提供一个断点的位置。(2)让您更容易地使用SelectedSubject
对象做有用的事情(如从列表中添加/删除它,将其作为参数传递给显示组件等)。
我解决这个问题的方法和别人的答案不一样。
这是一个Razor组件中的所有内容。
- 将数据分离到一个类中。请注意,字段可以为空(您可能不希望它们为空)。
- 使用正常绑定的
EditForm
。然后你可以进行验证。 - 选择列表中的逻辑,以确定是否没有选择值,并显示选择消息。
- 将选择代码分离到单独的RenderFragment块中,以保持代码更干净。如果你想把所有的标记放在一个地方,这是不必要的。
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
<EditForm EditContext="editContext">
<div class="col-12 mb-3">
<label class="form-label small muted">Subject</label>
<select class="form-select" @bind="model.Subject">
@this.SubjectList
</select>
</div>
<div class="col-12 mb-3">
<label class="form-label small muted">Title</label>
<input class="form-control" @bind="model.Title">
</div>
</EditForm>
<div class="alert alert-info m-3">
<div class="m-2">
Subject : @model.Subject
</div>
<div class="m-2">
Title : @model.Title
</div>
<div class="m-2">
Content : @model.Content
</div>
</div>
@code {
//private Note model = new() { Subject="Portugal"};
private Note model = new();
private EditContext? editContext;
protected override void OnInitialized()
=> this.editContext = new EditContext(model);
private IEnumerable<string> Subjects = new List<string> { "France", "Portugal", "Spain" };
private bool noSubjectSelected => !Subjects.Any(item => item == model.Subject);
// Separates out the code into a separate render block
private RenderFragment SubjectList => (__builder) =>
{
if (noSubjectSelected)
{
<option disabled selected value="">-- Select a Subject --</option>
}
foreach (var subject in Subjects)
{
<option value="@subject">@subject</option>
}
};
// Normally separate out into own class file
public class Note
{
public string? Subject { get; set; }
public string? Title { get; set; }
public string? Content { get; set; }
}
}
我把主题作为一个字符串,因为这是你所拥有的。如果它是一个guid,你需要调整Select Code来处理guid/String对。
请记住,源代码是呈现意图的指令,因此您的代码在所有操作情况下的反应并不总是很清楚。
您必须决定是否在任何时候都有选择,或者是否没有材料选择也是有效的。例如,如果您想要一个"选择主题"选项;在列表的顶部,这是默认的,所以用文本和Guid的值设置一个选项。空(全为零)。当处理值时-只需检查所选的Guid不等于Guid。如果您想知道"real"选择主题选项
我对InputSelect使用了以下两种方法。注意,Microsoft渲染器可能会将选择的文本设置为绑定的选项,但可能不会将该选项设置为<;selected">
<InputSelect @bind-Value=MyData>
<option selected value="@Guid.Empty">Select a Subject</option>
@foreach (var i in Subjects)
{
<option value=@i.Id>@i.SubjectName</option>
}
</InputSelect>
如果您希望对选择进行更细粒度的控制,可以使用这个绑定选项。除了绑定到的值之外,还需要一个在更改时调用的函数——SelectChanged——您可以在其中运行其他代码。您应该在此方法中设置绑定值。如果InputSelect在组件中,那么绑定值也应该有一个同名的eventandler,并带有"Changed"你应该在你的SelectChanged函数中调用它。任何绑定到子控件的父控件都将自动更新其数据,并为您调用setstatechange
<InputSelect Value="@MyValue" ValueChanged="@((Guid value) => SelectChanged(value))" ValueExpression="@(() => MyValue)" >
@foreach (var i in MyValues)
{
if (TheSelectedValue == i.TheValue)
{
<option selected value=@i.TheValue>@i.ValueDisplay</option>
}
else
{
<option value=@i.TheValue>@i.ValueDisplay</option>
}
}
</InputSelect>
要解决事物不变的问题,有两种方法可以做到:
- 开始与一个空对象为您的
SelectedSubject
,做一个空检查在您的点击,并有一个虚拟的select
选项,强制您选择一个项目:
.
<select @onchange=ProcessChange>
<option selected disabled>Pick a subject. . . </option>
@foreach (var subject in Auth.User.Subjects) {
<option>. . . </option>
}
</select>
<button @onclick=AddSubject />
@code {
List<Subject> SelectedSubjects = new();
Subject SelectedSubject {get; set; } = null;
async Task ProcessChange (ChangeEventArgs args){. . . }
async Task AddSubject{
if (Subject is not null) SelectedSubjects.Add (SelectedSubject);
}
}
- 在你的数据初始化中预先选择你的第一个选项,然后你不需要虚拟
<option>
或null检查。
.
@code{
async Task OnInitializedAsync (bool IsFirstRender){
Auth.User.Subjects = await LoadSubjectsForUser (Auth.User);
SelectedSubject = Auth.User.Subjects.First();
}
}
在你的用例中,我认为#1可能更好。