This commit is contained in:
parent
fd9ad7f8c5
commit
4df198dfaa
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -238,6 +238,17 @@ export class BrowserRenderer {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We handle setting 'value' on a <select> in two different ways:
|
||||
// [1] When inserting a corresponding <option>, in case you're dynamically adding options
|
||||
// [2] After we finish inserting the <select>, in case the descendant options are being
|
||||
// added as an opaque markup block rather than individually
|
||||
// Right here we implement [2]
|
||||
if (newDomElementRaw instanceof HTMLSelectElement && selectValuePropname in newDomElementRaw) {
|
||||
const selectValue = newDomElementRaw[selectValuePropname];
|
||||
newDomElementRaw.value = selectValue;
|
||||
delete newDomElementRaw[selectValuePropname];
|
||||
}
|
||||
}
|
||||
|
||||
private insertComponent(batch: RenderBatch, parent: LogicalElement, childIndex: number, frame: RenderTreeFrame) {
|
||||
|
|
@ -317,7 +328,8 @@ export class BrowserRenderer {
|
|||
// <select> is special, in that anything we write to .value will be lost if there
|
||||
// isn't yet a matching <option>. To maintain the expected behavior no matter the
|
||||
// element insertion/update order, preserve the desired value separately so
|
||||
// we can recover it when inserting any matching <option>.
|
||||
// we can recover it when inserting any matching <option> or after inserting an
|
||||
// entire markup block of descendants.
|
||||
element[selectValuePropname] = value;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -330,10 +342,11 @@ export class BrowserRenderer {
|
|||
element.removeAttribute('value');
|
||||
}
|
||||
// See above for why we have this special handling for <select>/<option>
|
||||
const parentElement = element.parentElement;
|
||||
if (parentElement && (selectValuePropname in parentElement) && parentElement[selectValuePropname] === value) {
|
||||
this.tryApplyValueProperty(batch, parentElement, attributeFrame);
|
||||
delete parentElement[selectValuePropname];
|
||||
// Note that this is only one of the two cases where we set the value on a <select>
|
||||
const selectElem = this.findClosestAncestorSelectElement(element);
|
||||
if (selectElem && (selectValuePropname in selectElem) && selectElem[selectValuePropname] === value) {
|
||||
this.tryApplyValueProperty(batch, selectElem, attributeFrame);
|
||||
delete selectElem[selectValuePropname];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -353,6 +366,18 @@ export class BrowserRenderer {
|
|||
}
|
||||
}
|
||||
|
||||
private findClosestAncestorSelectElement(element: Element | null) {
|
||||
while (element) {
|
||||
if (element instanceof HTMLSelectElement) {
|
||||
return element;
|
||||
} else {
|
||||
element = element.parentElement;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private insertFrameRange(batch: RenderBatch, componentId: number, parent: LogicalElement, childIndex: number, frames: ArrayValues<RenderTreeFrame>, startIndex: number, endIndexExcl: number): number {
|
||||
const origChildIndex = childIndex;
|
||||
for (let index = startIndex; index < endIndexExcl; index++) {
|
||||
|
|
|
|||
|
|
@ -214,6 +214,19 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests
|
|||
Assert.Equal("Fourth choice", target.SelectedOption.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanBindSelectToMarkup()
|
||||
{
|
||||
var target = new SelectElement(Browser.FindElement(By.Id("select-markup-box")));
|
||||
var boundValue = Browser.FindElement(By.Id("select-markup-box-value"));
|
||||
Assert.Equal("Second choice", target.SelectedOption.Text);
|
||||
Assert.Equal("Second", boundValue.Text);
|
||||
|
||||
// Modify target; verify value is updated
|
||||
target.SelectByText("Third choice");
|
||||
Browser.Equal("Third", () => boundValue.Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanBindTextboxInt()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -145,18 +145,32 @@
|
|||
<h2>Select</h2>
|
||||
<p>
|
||||
<select id="select-box" @bind="selectValue">
|
||||
<option value=@SelectableValue.First>First choice</option>
|
||||
<option value=@SelectableValue.Second>Second choice</option>
|
||||
<option value=@SelectableValue.Third>Third choice</option>
|
||||
@if (includeFourthOption)
|
||||
{
|
||||
<option value=@SelectableValue.Fourth>Fourth choice</option>
|
||||
}
|
||||
<optgroup label="Some choices"> <!-- Show it also works with optgroup -->
|
||||
<option value=@SelectableValue.First>First choice</option>
|
||||
<option value=@SelectableValue.Second>Second choice</option>
|
||||
<option value=@SelectableValue.Third>Third choice</option>
|
||||
@if (includeFourthOption)
|
||||
{
|
||||
<option value=@SelectableValue.Fourth>Fourth choice</option>
|
||||
}
|
||||
</optgroup>
|
||||
</select>
|
||||
<span id="select-box-value">@selectValue</span>
|
||||
<button id="select-box-add-option" @onclick="AddAndSelectNewSelectOption">Add and select new item</button>
|
||||
</p>
|
||||
|
||||
<h2>Select (markup block)</h2>
|
||||
<p>
|
||||
<select id="select-markup-box" @bind="selectMarkupValue">
|
||||
<optgroup label="Some choices">
|
||||
<option value="First">First choice</option>
|
||||
<option value="Second">Second choice</option>
|
||||
<option value="Third">Third choice</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
<span id="select-markup-box-value">@selectMarkupValue</span>
|
||||
</p>
|
||||
|
||||
@code {
|
||||
string textboxInitiallyBlankValue = null;
|
||||
string textboxInitiallyPopulatedValue = "Hello";
|
||||
|
|
@ -187,6 +201,7 @@ Guid textboxGenericGuidValue = Guid.Empty;
|
|||
bool includeFourthOption = false;
|
||||
enum SelectableValue { First, Second, Third, Fourth }
|
||||
SelectableValue selectValue = SelectableValue.Second;
|
||||
SelectableValue selectMarkupValue = SelectableValue.Second;
|
||||
|
||||
void AddAndSelectNewSelectOption()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue