Fix selection on <select> box. Fixes #157

This commit is contained in:
Steve Sanderson 2018-03-16 09:37:47 +00:00
parent 03ac95f086
commit a02ac60c8c
3 changed files with 64 additions and 1 deletions

View File

@ -2,6 +2,7 @@
import { getRenderTreeEditPtr, renderTreeEdit, RenderTreeEditPointer, EditType } from './RenderTreeEdit';
import { getTreeFramePtr, renderTreeFrame, FrameType, RenderTreeFramePointer } from './RenderTreeFrame';
import { platform } from '../Environment';
const selectValuePropname = '_blazorSelectValue';
let raiseEventMethod: MethodHandle;
let renderComponentMethod: MethodHandle;
@ -226,8 +227,24 @@ export class BrowserRenderer {
if (isCheckbox(element)) {
(element as HTMLInputElement).checked = value === 'True';
} else {
// Note: this doen't handle <select> correctly: https://github.com/aspnet/Blazor/issues/157
(element as any).value = value;
if (element.tagName === 'SELECT') {
// <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>.
element[selectValuePropname] = value;
}
}
return true;
case 'OPTION':
element.setAttribute('value', 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(parentElement, value);
delete parentElement[selectValuePropname];
}
return true;
default:

View File

@ -5,6 +5,7 @@ using BasicTestApp;
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure;
using Microsoft.AspNetCore.Blazor.E2ETest.Infrastructure.ServerFixtures;
using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using Xunit;
namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
@ -74,5 +75,25 @@ namespace Microsoft.AspNetCore.Blazor.E2ETest.Tests
Assert.False(target.Selected);
Assert.Equal("False", boundValue.Text);
}
[Fact]
public void CanBindSelect()
{
var target = new SelectElement(Browser.FindElement(By.Id("select-box")));
var boundValue = Browser.FindElement(By.Id("select-box-value"));
Assert.Equal("Second choice", target.SelectedOption.Text);
Assert.Equal("Second", boundValue.Text);
// Modify target; verify value is updated
target.SelectByText("Third choice");
Assert.Equal("Third", boundValue.Text);
// Also verify we can add and select new options atomically
// Don't move this into a separate test, because then the previous assertions
// would be dependent on test execution order (or would require a full page reload)
Browser.FindElement(By.Id("select-box-add-option")).Click();
Assert.Equal("Fourth", boundValue.Text);
Assert.Equal("Fourth choice", target.SelectedOption.Text);
}
}
}

View File

@ -22,10 +22,35 @@
<span id="checkbox-initially-checked-value">@checkboxInitiallyCheckedValue</span>
</p>
<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>
}
</select>
<span id="select-box-value">@selectValue</span>
<button id="select-box-add-option" @onclick(AddAndSelectNewSelectOption)>Add and select new item</button>
</p>
@functions {
string textboxInitiallyBlankValue = null;
string textboxInitiallyPopulatedValue = "Hello";
bool checkboxInitiallyUncheckedValue = false;
bool checkboxInitiallyCheckedValue = true;
bool includeFourthOption = false;
enum SelectableValue { First, Second, Third, Fourth }
SelectableValue selectValue = SelectableValue.Second;
void AddAndSelectNewSelectOption()
{
includeFourthOption = true;
selectValue = SelectableValue.Fourth;
}
}