From bd1d2760130a5dd758350a303c34a808c291234d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=A0t=C4=9Bp=C3=A1nek?= Date: Fri, 23 Aug 2019 13:59:16 +0200 Subject: [PATCH 1/3] Add a sample that is not working --- .../DotVVM.Samples.Common.csproj | 1 + .../GridView/NotWorkingViewModel.cs | 88 +++++++++++++++++++ .../GridView/NotWorking.dothtml | 35 ++++++++ 3 files changed, 124 insertions(+) create mode 100644 src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/NotWorkingViewModel.cs create mode 100644 src/DotVVM.Samples.Common/Views/ControlSamples/GridView/NotWorking.dothtml diff --git a/src/DotVVM.Samples.Common/DotVVM.Samples.Common.csproj b/src/DotVVM.Samples.Common/DotVVM.Samples.Common.csproj index 50b7c4775b..f04012b618 100644 --- a/src/DotVVM.Samples.Common/DotVVM.Samples.Common.csproj +++ b/src/DotVVM.Samples.Common/DotVVM.Samples.Common.csproj @@ -18,6 +18,7 @@ + diff --git a/src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/NotWorkingViewModel.cs b/src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/NotWorkingViewModel.cs new file mode 100644 index 0000000000..ba23d4136a --- /dev/null +++ b/src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/NotWorkingViewModel.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DotVVM.Framework.Controls; + +namespace DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.GridView +{ + public class NotWorkingViewModel + { + public GridViewDataSet EventRegistrations { get; set; } = new GridViewDataSet { + RowEditOptions = new RowEditOptions { + PrimaryKeyPropertyName = nameof(RegistrationDto.Id) + }, + Items = new List { + new RegistrationDto { + Id = "r1", + Sku = "Sku1", + SkuDescription = "Sku1 Description", + FirstName = "John", + LastName = "Smith", + Email = "john@example.com", + OrderId = "o1", + Notes = "Help" + }, + new RegistrationDto { + Id = "r2", + Sku = "Sku2", + SkuDescription = "Sku2 Description", + FirstName = "Joe", + LastName = "Doe", + Email = "joe@example.com", + OrderId = "o2", + Notes = "Help" + }, + new RegistrationDto { + Id = "r3", + Sku = "Sku3", + SkuDescription = "Sku3 Description", + FirstName = "Jane", + LastName = "Doe", + Email = "jane@example.com", + OrderId = "o3", + Notes = "Help" + } + } + }; + + public void EditEventRegistration(string id) + { + EventRegistrations.RowEditOptions.EditRowId = id; + } + + public Task CancelEventRegistration() + { + EventRegistrations.RowEditOptions.EditRowId = null; + EventRegistrations.RequestRefresh(); + return Task.CompletedTask; + } + + public Task SaveEventRegistration(RegistrationDto item) + { + EventRegistrations.RowEditOptions.EditRowId = null; + EventRegistrations.RequestRefresh(); + return Task.CompletedTask; + } + + public class RegistrationDto + { + public string Id { get; set; } + + public string Sku { get; set; } + + public string SkuDescription { get; set; } + + public string FirstName { get; set; } + + public string LastName { get; set; } + + public string Email { get; set; } + + public string OrderId { get; set; } + + public string Notes { get; set; } + } + } +} diff --git a/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/NotWorking.dothtml b/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/NotWorking.dothtml new file mode 100644 index 0000000000..985326c759 --- /dev/null +++ b/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/NotWorking.dothtml @@ -0,0 +1,35 @@ +@viewModel DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.GridView.NotWorkingViewModel + + + + + + + + + + + + + + + + + Pencil + + + + + Ok + + + Repeat + + + + + + From c99cb5778aa4d60c40e1c5eb952e542f270c80e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=A0t=C4=9Bp=C3=A1nek?= Date: Fri, 6 Sep 2019 12:15:12 +0200 Subject: [PATCH 2/3] Fix a bug in GridView and rename the sample --- src/DotVVM.Framework/Controls/GridView.cs | 47 +++++++--- .../DotVVM.Samples.Common.csproj | 2 +- .../GridView/NotWorkingViewModel.cs | 88 ------------------- .../GridView/RenamedPrimaryKeyViewModel.cs | 54 ++++++++++++ .../GridView/NotWorking.dothtml | 35 -------- .../GridView/RenamedPrimaryKey.dothtml | 26 ++++++ 6 files changed, 116 insertions(+), 136 deletions(-) delete mode 100644 src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/NotWorkingViewModel.cs create mode 100644 src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/RenamedPrimaryKeyViewModel.cs delete mode 100644 src/DotVVM.Samples.Common/Views/ControlSamples/GridView/NotWorking.dothtml create mode 100644 src/DotVVM.Samples.Common/Views/ControlSamples/GridView/RenamedPrimaryKey.dothtml diff --git a/src/DotVVM.Framework/Controls/GridView.cs b/src/DotVVM.Framework/Controls/GridView.cs index 121f0a275d..247460faeb 100644 --- a/src/DotVVM.Framework/Controls/GridView.cs +++ b/src/DotVVM.Framework/Controls/GridView.cs @@ -11,6 +11,8 @@ using DotVVM.Framework.Binding.Properties; using DotVVM.Framework.Compilation.Javascript; using DotVVM.Framework.Utils; +using Microsoft.Extensions.DependencyInjection; +using DotVVM.Framework.ViewModel; namespace DotVVM.Framework.Controls { @@ -142,13 +144,13 @@ public bool InlineEditing public static readonly DotvvmProperty InlineEditingProperty = DotvvmProperty.Register(t => t.InlineEditing, false); - protected internal override void OnLoad(Hosting.IDotvvmRequestContext context) + protected internal override void OnLoad(IDotvvmRequestContext context) { DataBind(context); base.OnLoad(context); } - protected internal override void OnPreRender(Hosting.IDotvvmRequestContext context) + protected internal override void OnPreRender(IDotvvmRequestContext context) { DataBind(context); // TODO: support for observable collection base.OnPreRender(context); @@ -290,7 +292,7 @@ private static void SetCellAttributes(GridViewColumn column, HtmlGenericControl } } - private void CreateRowWithCells(Hosting.IDotvvmRequestContext context, DataItemContainer placeholder) + private void CreateRowWithCells(IDotvvmRequestContext context, DataItemContainer placeholder) { var isInEditMode = false; if (InlineEditing) @@ -345,21 +347,35 @@ private HtmlGenericControl CreateRow(DataItemContainer placeholder, bool isInEdi return row; } - private bool IsEditedRow(DataItemContainer placeholder) + private PropertyInfo ResolvePrimaryKeyProperty() { - var primaryKeyPropertyName = ((IGridViewDataSet)DataSource).RowEditOptions.PrimaryKeyPropertyName; + var dataSet = (IGridViewDataSet)DataSource; + var primaryKeyPropertyName = dataSet.RowEditOptions.PrimaryKeyPropertyName; if (string.IsNullOrEmpty(primaryKeyPropertyName)) { - throw new DotvvmControlException(this, $"The {nameof(IGridViewDataSet)} must specify the {nameof(IRowEditOptions.PrimaryKeyPropertyName)} property when inline editing is enabled on the {nameof(GridView)} control!"); + throw new DotvvmControlException(this, $"The {nameof(IGridViewDataSet)} must " + + $"specify the {nameof(IRowEditOptions.PrimaryKeyPropertyName)} property " + + $"when inline editing is enabled on the {nameof(GridView)} control!"); } - PropertyInfo prop; - var value = ReflectionUtils.GetObjectPropertyValue(placeholder.DataContext, primaryKeyPropertyName, out prop); + var enumerableType = ReflectionUtils.GetEnumerableType(dataSet.Items.GetType()); + var property = enumerableType.GetProperty(primaryKeyPropertyName); + if (property == null) + { + throw new InvalidOperationException($"Type '{enumerableType}' does not contain a " + + $"'{primaryKeyPropertyName}' property."); + } + return property; + } + private bool IsEditedRow(DataItemContainer placeholder) + { + var property = ResolvePrimaryKeyProperty(); + var value = property.GetValue(placeholder.DataContext); if (value != null) { var editRowId = ((IGridViewDataSet)DataSource).RowEditOptions.EditRowId; - if (editRowId != null && value.Equals(ReflectionUtils.ConvertValue(editRowId, prop.PropertyType))) + if (editRowId != null && value.Equals(ReflectionUtils.ConvertValue(editRowId, property.PropertyType))) { return true; } @@ -368,7 +384,7 @@ private bool IsEditedRow(DataItemContainer placeholder) return false; } - private void CreateTemplates(Hosting.IDotvvmRequestContext context, DataItemContainer placeholder, bool isInEditMode = false) + private void CreateTemplates(IDotvvmRequestContext context, DataItemContainer placeholder, bool isInEditMode = false) { var row = CreateRow(placeholder, isInEditMode); @@ -418,11 +434,17 @@ protected override void RenderContents(IHtmlWriter writer, IDotvvmRequestContext // render on client if (InlineEditing) { + var propertySerialization = context.Services + .GetRequiredService(); + var primaryKeyProperty = ResolvePrimaryKeyProperty(); + var primaryKeyPropertyName = propertySerialization.ResolveName(primaryKeyProperty); + var placeholder = new DataItemContainer { DataContext = null }; placeholder.SetDataContextTypeFromDataSource(GetBinding(DataSourceProperty)); placeholder.SetValue(Internal.PathFragmentProperty, GetPathFragmentExpression() + "/[$index]"); placeholder.SetValue(Internal.ClientIDFragmentProperty, GetValueRaw(Internal.CurrentIndexBindingProperty)); - writer.WriteKnockoutDataBindComment("if", "ko.unwrap(ko.unwrap($gridViewDataSet).RowEditOptions().EditRowId) !== ko.unwrap($data[ko.unwrap(ko.unwrap($gridViewDataSet).RowEditOptions().PrimaryKeyPropertyName)])"); + writer.WriteKnockoutDataBindComment("if", "ko.unwrap(ko.unwrap($gridViewDataSet).RowEditOptions().EditRowId) " + + $"!== ko.unwrap($data['{primaryKeyPropertyName}'])"); CreateTemplates(context, placeholder); Children.Add(placeholder); placeholder.Render(writer, context); @@ -432,7 +454,8 @@ protected override void RenderContents(IHtmlWriter writer, IDotvvmRequestContext placeholderEdit.SetDataContextTypeFromDataSource(GetBinding(DataSourceProperty)); placeholderEdit.SetValue(Internal.PathFragmentProperty, GetPathFragmentExpression() + "/[$index]"); placeholderEdit.SetValue(Internal.ClientIDFragmentProperty, GetValueRaw(Internal.CurrentIndexBindingProperty)); - writer.WriteKnockoutDataBindComment("if", "ko.unwrap(ko.unwrap($gridViewDataSet).RowEditOptions().EditRowId) === ko.unwrap($data[ko.unwrap(ko.unwrap($gridViewDataSet).RowEditOptions().PrimaryKeyPropertyName)])"); + writer.WriteKnockoutDataBindComment("if", "ko.unwrap(ko.unwrap($gridViewDataSet).RowEditOptions().EditRowId) " + + $"=== ko.unwrap($data['{primaryKeyPropertyName}'])"); CreateTemplates(context, placeholderEdit, true); Children.Add(placeholderEdit); placeholderEdit.Render(writer, context); diff --git a/src/DotVVM.Samples.Common/DotVVM.Samples.Common.csproj b/src/DotVVM.Samples.Common/DotVVM.Samples.Common.csproj index f04012b618..1f859c4a2a 100644 --- a/src/DotVVM.Samples.Common/DotVVM.Samples.Common.csproj +++ b/src/DotVVM.Samples.Common/DotVVM.Samples.Common.csproj @@ -18,7 +18,7 @@ - + diff --git a/src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/NotWorkingViewModel.cs b/src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/NotWorkingViewModel.cs deleted file mode 100644 index ba23d4136a..0000000000 --- a/src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/NotWorkingViewModel.cs +++ /dev/null @@ -1,88 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using DotVVM.Framework.Controls; - -namespace DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.GridView -{ - public class NotWorkingViewModel - { - public GridViewDataSet EventRegistrations { get; set; } = new GridViewDataSet { - RowEditOptions = new RowEditOptions { - PrimaryKeyPropertyName = nameof(RegistrationDto.Id) - }, - Items = new List { - new RegistrationDto { - Id = "r1", - Sku = "Sku1", - SkuDescription = "Sku1 Description", - FirstName = "John", - LastName = "Smith", - Email = "john@example.com", - OrderId = "o1", - Notes = "Help" - }, - new RegistrationDto { - Id = "r2", - Sku = "Sku2", - SkuDescription = "Sku2 Description", - FirstName = "Joe", - LastName = "Doe", - Email = "joe@example.com", - OrderId = "o2", - Notes = "Help" - }, - new RegistrationDto { - Id = "r3", - Sku = "Sku3", - SkuDescription = "Sku3 Description", - FirstName = "Jane", - LastName = "Doe", - Email = "jane@example.com", - OrderId = "o3", - Notes = "Help" - } - } - }; - - public void EditEventRegistration(string id) - { - EventRegistrations.RowEditOptions.EditRowId = id; - } - - public Task CancelEventRegistration() - { - EventRegistrations.RowEditOptions.EditRowId = null; - EventRegistrations.RequestRefresh(); - return Task.CompletedTask; - } - - public Task SaveEventRegistration(RegistrationDto item) - { - EventRegistrations.RowEditOptions.EditRowId = null; - EventRegistrations.RequestRefresh(); - return Task.CompletedTask; - } - - public class RegistrationDto - { - public string Id { get; set; } - - public string Sku { get; set; } - - public string SkuDescription { get; set; } - - public string FirstName { get; set; } - - public string LastName { get; set; } - - public string Email { get; set; } - - public string OrderId { get; set; } - - public string Notes { get; set; } - } - } -} diff --git a/src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/RenamedPrimaryKeyViewModel.cs b/src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/RenamedPrimaryKeyViewModel.cs new file mode 100644 index 0000000000..9804139407 --- /dev/null +++ b/src/DotVVM.Samples.Common/ViewModels/ControlSamples/GridView/RenamedPrimaryKeyViewModel.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DotVVM.Framework.Controls; +using Newtonsoft.Json; + +namespace DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.GridView +{ + public class RenamedPrimaryKeyViewModel + { + public GridViewDataSet Samples { get; set; } = new GridViewDataSet { + RowEditOptions = new RowEditOptions { + PrimaryKeyPropertyName = nameof(SampleDto.Id) + }, + Items = { + new SampleDto + { + Id = "1", + Name = "One" + }, + new SampleDto + { + Id = "2", + Name = "Two" + }, + new SampleDto + { + Id = "3", + Name = "Three" + } + } + }; + + public void Edit(string id) + { + Samples.RowEditOptions.EditRowId = id; + } + + public void Save() + { + Samples.RowEditOptions.EditRowId = null; + } + + public class SampleDto + { + [JsonProperty("id", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)] + public string Id { get; set; } + + public string Name { get; set; } + } + } +} diff --git a/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/NotWorking.dothtml b/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/NotWorking.dothtml deleted file mode 100644 index 985326c759..0000000000 --- a/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/NotWorking.dothtml +++ /dev/null @@ -1,35 +0,0 @@ -@viewModel DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.GridView.NotWorkingViewModel - - - - - - - - - - - - - - - - - Pencil - - - - - Ok - - - Repeat - - - - - - diff --git a/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/RenamedPrimaryKey.dothtml b/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/RenamedPrimaryKey.dothtml new file mode 100644 index 0000000000..e9e7492617 --- /dev/null +++ b/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/RenamedPrimaryKey.dothtml @@ -0,0 +1,26 @@ +@viewModel DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.GridView.RenamedPrimaryKeyViewModel + + + + + + + + + + + + + Edit + + + + + Save + + + + + + From f3e80da58a14342c4d369992d4b478e2eded7676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=A0t=C4=9Bp=C3=A1nek?= Date: Fri, 6 Sep 2019 12:24:58 +0200 Subject: [PATCH 3/3] Add a test for the RenamedPrimaryKey sample --- .../GridView/RenamedPrimaryKey.dothtml | 9 ++++++--- .../Control/GridViewTests.cs | 19 +++++++++++++++++++ .../SamplesRouteUrls.designer.cs | 3 ++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/RenamedPrimaryKey.dothtml b/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/RenamedPrimaryKey.dothtml index e9e7492617..b4d5aca939 100644 --- a/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/RenamedPrimaryKey.dothtml +++ b/src/DotVVM.Samples.Common/Views/ControlSamples/GridView/RenamedPrimaryKey.dothtml @@ -7,16 +7,19 @@ + InlineEditing="true" + data-ui="gridview"> - + Edit - + Save diff --git a/src/DotVVM.Samples.Tests/Control/GridViewTests.cs b/src/DotVVM.Samples.Tests/Control/GridViewTests.cs index c79f9bc110..635738347f 100644 --- a/src/DotVVM.Samples.Tests/Control/GridViewTests.cs +++ b/src/DotVVM.Samples.Tests/Control/GridViewTests.cs @@ -3,6 +3,7 @@ using DotVVM.Testing.Abstractions; using Riganti.Selenium.Core; using Riganti.Selenium.Core.Abstractions; +using Riganti.Selenium.DotVVM; using Xunit; using Xunit.Abstractions; @@ -533,5 +534,23 @@ public void Control_GridView_LargeGrid() AssertUI.TextEquals(tbody.Last("tr").Last("td").Single("span"), LastCell); }); } + + [Fact] + public void Control_GridView_RenamedPrimaryKey() + { + RunInAllBrowsers(browser => { + browser.NavigateToUrl(SamplesRouteUrls.ControlSamples_GridView_RenamedPrimaryKey); + browser.WaitUntilDotvvmInited(); + + var gridview = browser.Single("gridview", SelectByDataUi); + AssertUI.NotContainsElement(gridview, "input"); + + browser.First("edit-button", SelectByDataUi).Click(); + browser.WaitFor(() => AssertUI.ContainsElement(gridview, "input"), 1000); + + browser.First("save-button", SelectByDataUi).Click(); + browser.WaitFor(() => AssertUI.NotContainsElement(gridview, "input"), 1000); + }); + } } } diff --git a/src/DotVVM.Testing.Abstractions/SamplesRouteUrls.designer.cs b/src/DotVVM.Testing.Abstractions/SamplesRouteUrls.designer.cs index 7e2839e913..cf928e20e1 100644 --- a/src/DotVVM.Testing.Abstractions/SamplesRouteUrls.designer.cs +++ b/src/DotVVM.Testing.Abstractions/SamplesRouteUrls.designer.cs @@ -70,6 +70,7 @@ public partial class SamplesRouteUrls public const string ControlSamples_GridView_GridViewServerRender = "ControlSamples/GridView/GridViewServerRender"; public const string ControlSamples_GridView_GridViewStaticCommand = "ControlSamples/GridView/GridViewStaticCommand"; public const string ControlSamples_GridView_LargeGrid = "ControlSamples/GridView/LargeGrid"; + public const string ControlSamples_GridView_RenamedPrimaryKey = "ControlSamples/GridView/RenamedPrimaryKey"; public const string ControlSamples_HtmlLiteral_HtmlLiteral = "ControlSamples/HtmlLiteral/HtmlLiteral"; public const string ControlSamples_IncludeInPageProperty_IncludeInPage = "ControlSamples/IncludeInPageProperty/IncludeInPage"; public const string ControlSamples_LinkButton_LinkButton = "ControlSamples/LinkButton/LinkButton"; @@ -134,8 +135,8 @@ public partial class SamplesRouteUrls public const string Errors_EmptyBinding = "Errors/EmptyBinding"; public const string Errors_EncryptedPropertyInValueBinding = "Errors/EncryptedPropertyInValueBinding"; public const string Errors_FieldInValueBinding = "Errors/FieldInValueBinding"; - public const string Errors_InvalidServiceDirective = "Errors/InvalidServiceDirective"; public const string Errors_InvalidLocationFallback = "Errors/InvalidLocationFallback"; + public const string Errors_InvalidServiceDirective = "Errors/InvalidServiceDirective"; public const string Errors_InvalidViewModel = "Errors/InvalidViewModel"; public const string Errors_MalformedBinding = "Errors/MalformedBinding"; public const string Errors_MarkupControlInvalidViewModel = "Errors/MarkupControlInvalidViewModel";