Add support for passing parameters to UI event handlers (e.g., which key was pressed)
This commit is contained in:
parent
23f7120b75
commit
04c582647a
|
|
@ -91,7 +91,16 @@ function applyAttribute(componentId: string, toDomElement: Element, attributeNod
|
|||
|
||||
switch (attributeName) {
|
||||
case 'onclick':
|
||||
toDomElement.addEventListener('click', () => raiseEvent(componentId, attributeNodeIndex, 'click'));
|
||||
toDomElement.addEventListener('click', () => raiseEvent(componentId, attributeNodeIndex, 'mouse', { Type: 'click' }));
|
||||
break;
|
||||
case 'onkeypress':
|
||||
toDomElement.addEventListener('keypress', evt => {
|
||||
// This does not account for special keys nor cross-browser differences. So far it's
|
||||
// just to establish that we can pass parameters when raising events.
|
||||
// We use C#-style PascalCase on the eventInfo to simplify deserialization, but this could
|
||||
// change if we introduced a richer JSON library on the .NET side.
|
||||
raiseEvent(componentId, attributeNodeIndex, 'keyboard', { Type: evt.type, Key: (evt as any).key });
|
||||
});
|
||||
break;
|
||||
default:
|
||||
// Treat as a regular string-valued attribute
|
||||
|
|
@ -103,7 +112,7 @@ function applyAttribute(componentId: string, toDomElement: Element, attributeNod
|
|||
}
|
||||
}
|
||||
|
||||
function raiseEvent(componentId: string, uiTreeNodeIndex: number, eventName: string) {
|
||||
function raiseEvent(componentId: string, uiTreeNodeIndex: number, eventInfoType: EventInfoType, eventInfo: any) {
|
||||
if (!raiseEventMethod) {
|
||||
raiseEventMethod = platform.findMethod(
|
||||
'Microsoft.Blazor.Browser', 'Microsoft.Blazor.Browser', 'Events', 'RaiseEvent'
|
||||
|
|
@ -114,7 +123,9 @@ function raiseEvent(componentId: string, uiTreeNodeIndex: number, eventName: str
|
|||
// it first if necessary. Until then we have to send it as a string.
|
||||
platform.callMethod(raiseEventMethod, null, [
|
||||
platform.toDotNetString(componentId),
|
||||
platform.toDotNetString(uiTreeNodeIndex.toString())
|
||||
platform.toDotNetString(uiTreeNodeIndex.toString()),
|
||||
platform.toDotNetString(eventInfoType),
|
||||
platform.toDotNetString(JSON.stringify(eventInfo))
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
@ -130,3 +141,5 @@ function clearElement(element: Element) {
|
|||
element.removeChild(childNode);
|
||||
}
|
||||
}
|
||||
|
||||
type EventInfoType = 'mouse' | 'keyboard';
|
||||
|
|
|
|||
|
|
@ -73,7 +73,7 @@ namespace Microsoft.Blazor.Browser
|
|||
return _uITreeBuilder.GetNodes();
|
||||
}
|
||||
|
||||
public void RaiseEvent(int uiTreeNodeIndex)
|
||||
public void RaiseEvent(int uiTreeNodeIndex, UIEventInfo eventInfo)
|
||||
{
|
||||
var nodes = _uITreeBuilder.GetNodes();
|
||||
var eventHandler = nodes.Array[nodes.Offset + uiTreeNodeIndex].AttributeEventHandlerValue;
|
||||
|
|
@ -82,7 +82,7 @@ namespace Microsoft.Blazor.Browser
|
|||
throw new ArgumentException($"Cannot raise event because the specified {nameof(UITreeNode)} at index {uiTreeNodeIndex} does not have any {nameof(UITreeNode.AttributeEventHandlerValue)}.");
|
||||
}
|
||||
|
||||
eventHandler.Invoke();
|
||||
eventHandler.Invoke(eventInfo);
|
||||
RenderToDOM();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Blazor.Browser.Interop;
|
||||
using Microsoft.Blazor.UITree;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Blazor.Browser
|
||||
{
|
||||
// Invoked by the Microsoft.Blazor.Browser.JS code when a DOM event occurs
|
||||
internal static class Events
|
||||
{
|
||||
public static void RaiseEvent(string domComponentID, string uiTreeNodeIndex)
|
||||
public static void RaiseEvent(string domComponentID, string uiTreeNodeIndex, string eventInfoType, string eventInfoJson)
|
||||
{
|
||||
// We're receiving the uiTreeNodeIndex as a string only because there's not
|
||||
// yet a way to pass ints (or construct boxed ones) from JS with the current Mono
|
||||
// runtime. When there's a supported way to do that, this can be simplified.
|
||||
var renderState = DOMComponentRenderState.FindByDOMComponentID(domComponentID);
|
||||
renderState.RaiseEvent(int.Parse(uiTreeNodeIndex));
|
||||
var eventInfo = ParseEventInfo(eventInfoType, eventInfoJson);
|
||||
renderState.RaiseEvent(int.Parse(uiTreeNodeIndex), eventInfo);
|
||||
}
|
||||
|
||||
private static UIEventInfo ParseEventInfo(string eventInfoType, string eventInfoJson)
|
||||
{
|
||||
switch (eventInfoType)
|
||||
{
|
||||
case "mouse":
|
||||
return Json.Deserialize<UIMouseEventInfo>(eventInfoJson);
|
||||
case "keyboard":
|
||||
return Json.Deserialize<UIKeyboardEventInfo>(eventInfoJson);
|
||||
default:
|
||||
throw new ArgumentException($"Unsupported value '{eventInfoType}'.", nameof(eventInfoType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,5 +6,5 @@ namespace Microsoft.Blazor.UITree
|
|||
/// <summary>
|
||||
/// Handles an event raised for a <see cref="UITreeNode"/>.
|
||||
/// </summary>
|
||||
public delegate void UIEventHandler();
|
||||
public delegate void UIEventHandler(UIEventInfo eventInfo);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.Blazor.UITree
|
||||
{
|
||||
/// <summary>
|
||||
/// Supplies information about an event that is being raised.
|
||||
/// </summary>
|
||||
public class UIEventInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the type of the event.
|
||||
/// </summary>
|
||||
public string Type { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supplies information about a mouse event that is being raised.
|
||||
/// </summary>
|
||||
public class UIMouseEventInfo : UIEventInfo
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supplies information about a keyboard event that is being raised.
|
||||
/// </summary>
|
||||
public class UIKeyboardEventInfo : UIEventInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// If applicable, gets or sets the key that produced the event.
|
||||
/// </summary>
|
||||
public string Key { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -60,6 +60,23 @@ namespace Microsoft.Blazor.E2ETest.Tests
|
|||
appElement.FindElement(By.TagName("p")).Text);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CanTriggerKeyPressEvents()
|
||||
{
|
||||
var appElement = MountTestComponent<KeyPressEventComponent>();
|
||||
|
||||
Assert.Empty(appElement.FindElements(By.TagName("li")));
|
||||
|
||||
appElement.FindElement(By.TagName("input")).SendKeys("a");
|
||||
Assert.Collection(appElement.FindElements(By.TagName("li")),
|
||||
li => Assert.Equal("a", li.Text));
|
||||
|
||||
appElement.FindElement(By.TagName("input")).SendKeys("b");
|
||||
Assert.Collection(appElement.FindElements(By.TagName("li")),
|
||||
li => Assert.Equal("a", li.Text),
|
||||
li => Assert.Equal("b", li.Text));
|
||||
}
|
||||
|
||||
private IWebElement MountTestComponent<TComponent>() where TComponent: IComponent
|
||||
{
|
||||
var componentTypeName = typeof(TComponent).FullName;
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
// Arrange
|
||||
var builder = new UITreeBuilder();
|
||||
UIEventHandler eventHandler = () => { };
|
||||
UIEventHandler eventHandler = eventInfo => { };
|
||||
|
||||
// Act
|
||||
builder.OpenElement("myelement"); // 0: <myelement
|
||||
|
|
@ -180,7 +180,7 @@ namespace Microsoft.Blazor.Test
|
|||
// Act/Assert
|
||||
Assert.Throws<InvalidOperationException>(() =>
|
||||
{
|
||||
builder.AddAttribute("name", () => { });
|
||||
builder.AddAttribute("name", eventInfo => { });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ namespace Microsoft.Blazor.Test
|
|||
{
|
||||
builder.OpenElement("some element");
|
||||
builder.AddText("hello");
|
||||
builder.AddAttribute("name", () => { });
|
||||
builder.AddAttribute("name", eventInfo => { });
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace BasicTestApp
|
|||
builder.CloseElement();
|
||||
}
|
||||
|
||||
private void OnButtonClicked()
|
||||
private void OnButtonClicked(UIEventInfo eventInfo)
|
||||
{
|
||||
currentCount++;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Blazor.Components;
|
||||
using Microsoft.Blazor.UITree;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BasicTestApp
|
||||
{
|
||||
public class KeyPressEventComponent : IComponent
|
||||
{
|
||||
private List<string> keysPressed = new List<string>();
|
||||
|
||||
public void BuildUITree(UITreeBuilder builder)
|
||||
{
|
||||
builder.AddText("Type here:");
|
||||
builder.OpenElement("input");
|
||||
builder.AddAttribute("onkeypress", OnKeyPressed);
|
||||
builder.CloseElement();
|
||||
|
||||
builder.OpenElement("ul");
|
||||
foreach (var key in keysPressed)
|
||||
{
|
||||
builder.OpenElement("li");
|
||||
builder.AddText(key);
|
||||
builder.CloseElement();
|
||||
}
|
||||
builder.CloseElement();
|
||||
}
|
||||
|
||||
private void OnKeyPressed(UIEventInfo eventInfo)
|
||||
{
|
||||
keysPressed.Add(((UIKeyboardEventInfo)eventInfo).Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue