Skip to content

Commit e55d94c

Browse files
authored
Merge pull request #1950 from riganti/fix/button-null-binding
Fixed Button issue with null binding in Enabled property
2 parents b34283c + a109d4f commit e55d94c

5 files changed

Lines changed: 92 additions & 2 deletions

File tree

src/Framework/Framework/Controls/ButtonBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ protected override void AddAttributesToRender(IHtmlWriter writer, IDotvvmRequest
9898
{
9999
writer.AddKnockoutDataBind("dotvvm-enable", this, EnabledProperty, () =>
100100
{
101-
if (!Enabled)
101+
if (GetValue(EnabledProperty) is not true)
102102
{
103103
writer.AddAttribute("disabled", "disabled");
104104
}
@@ -114,7 +114,7 @@ public bool ValidateCommand(DotvvmProperty targetProperty)
114114
{
115115
if (targetProperty == ClickProperty)
116116
{
117-
return Enabled && Visible;
117+
return GetValue(EnabledProperty) is true && GetValue(VisibleProperty) is true;
118118
}
119119
return false;
120120
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using DotVVM.Framework.ViewModel;
7+
using DotVVM.Framework.Hosting;
8+
9+
namespace DotVVM.Samples.Common.ViewModels.FeatureSamples.NullHandling
10+
{
11+
public class Button_EnabledViewModel : DotvvmViewModelBase
12+
{
13+
14+
public NullObject Null { get; set; } = null;
15+
16+
public int Value { get; set; }
17+
18+
public class NullObject
19+
{
20+
public bool Enabled { get; set; }
21+
}
22+
}
23+
24+
}
25+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
@viewModel DotVVM.Samples.Common.ViewModels.FeatureSamples.NullHandling.Button_EnabledViewModel, DotVVM.Samples.Common
2+
3+
<!DOCTYPE html>
4+
5+
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
6+
<head>
7+
<meta charset="utf-8" />
8+
<title></title>
9+
</head>
10+
<body>
11+
12+
<h1>Repro for ButtonBase.Enabled bug</h1>
13+
14+
<dot:Button Enabled="{resource: Null.Enabled}" Text="resource binding" Click="{command: Value = Value + 1}" data-ui="resource-button" />
15+
16+
<dot:Button Enabled="{value: Null.Enabled}" Text="value binding" Click="{command: Value = Value + 1}" data-ui="value-button"/>
17+
18+
<a onclick="unlockButtons(); return false;" href="#">Unlock by JS</a>
19+
20+
<p class="result">{{value: Value}}</p>
21+
22+
<script type="text/javascript">
23+
function unlockButtons() {
24+
Array.from(document.querySelectorAll('input[type=button]')).forEach(b => b.disabled = null);
25+
}
26+
</script>
27+
</body>
28+
</html>
29+
30+

src/Samples/Tests/Abstractions/SamplesRouteUrls.designer.cs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using DotVVM.Samples.Tests.Base;
2+
using DotVVM.Testing.Abstractions;
3+
using Riganti.Selenium.Core;
4+
using Xunit;
5+
using Xunit.Abstractions;
6+
7+
namespace DotVVM.Samples.Tests.Feature;
8+
9+
public class NullHandlingTests(ITestOutputHelper output) : AppSeleniumTest(output)
10+
{
11+
[Theory]
12+
[InlineData("resource-button")]
13+
[InlineData("value-button")]
14+
[Trait("Category", "dev-only")] // error page
15+
public void Feature_NullHandling_Button_Enabled(string buttonId)
16+
{
17+
RunInAllBrowsers(browser => {
18+
browser.NavigateToUrl(SamplesRouteUrls.FeatureSamples_NullHandling_Button_Enabled);
19+
20+
var button = browser.Single(buttonId, SelectByDataUi);
21+
AssertUI.IsNotEnabled(button);
22+
23+
browser.Single("a").Click();
24+
25+
button.Click();
26+
27+
var errorPage = browser.Single("#debugWindow");
28+
AssertUI.IsDisplayed(errorPage);
29+
30+
var scope = browser.GetFrameScope("#debugWindow iframe");
31+
AssertUI.Text(scope.Single(".summary"), t => t.Contains("Execution of '{command: Value = Value + 1}' was disallowed by '<dot:Button "));
32+
});
33+
}
34+
}

0 commit comments

Comments
 (0)