From c5ba35b060aa7f4404e05e4f6c7b9c840ecb5ba4 Mon Sep 17 00:00:00 2001 From: Krzysztof Jeske Date: Wed, 2 Oct 2024 16:55:53 +0200 Subject: [PATCH] Add key bahavior --- docs/content/features/parameters.md | 19 +++++++++++++++++++ src/HydroComponent.cs | 22 +++++++++++++++++----- src/KeyBehavior.cs | 17 +++++++++++++++++ src/TagHelpers/HydroComponentTagHelper.cs | 9 +++++---- 4 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 src/KeyBehavior.cs diff --git a/docs/content/features/parameters.md b/docs/content/features/parameters.md index b9d4ad1..7b13d18 100644 --- a/docs/content/features/parameters.md +++ b/docs/content/features/parameters.md @@ -106,6 +106,25 @@ or ``` +You can also use `key` to force re-render of your component: + +```razor + +``` + +Now, whenever `Model.Items` changes, Hydro will re-render the component `Items` and pass new parameter. + +### Key attribute behavior in the UI + +By default, when a component with the same key attribute is +re-rendered, its HTML is replaced (not morphed). Since `key` is also used to force re-render of the component, +there might be a case where you want to morph the component HTML instead, for example when the rendered component +is the one where might be the focus. To do that, use `key-behavior` attribute: + +```razor + +``` + ## Caching Let's imagine you need to show list of customers in a table. It's good to use caching per request for such rows data, diff --git a/src/HydroComponent.cs b/src/HydroComponent.cs index eb26b5b..5f88662 100644 --- a/src/HydroComponent.cs +++ b/src/HydroComponent.cs @@ -59,6 +59,12 @@ public abstract class HydroComponent : ViewComponent /// [JsonProperty] protected string Key { get; private set; } + + /// + /// Component's HTML behavior when the key changes + /// + [JsonProperty] + protected KeyBehavior KeyBehavior { get; private set; } /// /// Default identifier used to specify place of the page to replace when during location change @@ -138,12 +144,14 @@ private void ConfigurePolls() /// /// An object with component parameters /// Local identifier to distinguish components of same type - public async Task InvokeAsync(object parameters = null, string key = null) + /// Component's HTML behavior when the key changes + public async Task InvokeAsync(object parameters = null, string key = null, KeyBehavior keyBehavior = KeyBehavior.Replace) { ApplyParameters(parameters); ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = null; Key = key; + KeyBehavior = keyBehavior; var persistentState = HttpContext.RequestServices.GetService(); _options = HttpContext.RequestServices.GetService(); @@ -430,7 +438,7 @@ private async Task RenderOnlineNestedComponent(IPersistentState persiste if (IsComponentIdRendered(componentId)) { - return GetComponentPlaceholderTemplate(componentId, Key); + return GetComponentPlaceholderTemplate(componentId, Key, KeyBehavior); } if (!await AuthorizeAsync()) @@ -444,8 +452,12 @@ private async Task RenderOnlineNestedComponent(IPersistentState persiste return await GenerateComponentHtml(componentId, persistentState, includeScripts: true); } - private static string GetComponentPlaceholderTemplate(string componentId, string key) => - $"
"; + private static string GetComponentPlaceholderTemplate(string componentId, string key, KeyBehavior keyBehavior) + { + var useKey = !string.IsNullOrWhiteSpace(key) && keyBehavior == KeyBehavior.Replace; + + return $"
"; + } private async Task RenderStaticComponent(IPersistentState persistentState) { @@ -496,7 +508,7 @@ private async Task GenerateComponentHtml(string componentId, IPersistent rootElement.SetAttributeValue("hydro-name", GetType().Name); rootElement.SetAttributeValue("x-data", "hydro"); - if (!string.IsNullOrWhiteSpace(Key)) + if (!string.IsNullOrWhiteSpace(Key) && KeyBehavior == KeyBehavior.Replace) { rootElement.SetAttributeValue("key", Key); } diff --git a/src/KeyBehavior.cs b/src/KeyBehavior.cs new file mode 100644 index 0000000..bfde531 --- /dev/null +++ b/src/KeyBehavior.cs @@ -0,0 +1,17 @@ +namespace Hydro; + +/// +/// Defines the component behavior when key changes +/// +public enum KeyBehavior +{ + /// + /// Replace the component's HTML + /// + Replace, + + /// + /// Morph the component's HTML + /// + Morph +} \ No newline at end of file diff --git a/src/TagHelpers/HydroComponentTagHelper.cs b/src/TagHelpers/HydroComponentTagHelper.cs index 3a7b7d8..10230cc 100644 --- a/src/TagHelpers/HydroComponentTagHelper.cs +++ b/src/TagHelpers/HydroComponentTagHelper.cs @@ -68,10 +68,10 @@ public IDictionary ParametersDictionary public int? Delay { get; set; } = 0; /// - /// + /// Component's HTML behavior when the key changes /// - [HtmlAttributeName("run")] - public bool Run { get; set; } + [HtmlAttributeName("key-behavior")] + public KeyBehavior KeyBehavior { get; set; } = KeyBehavior.Replace; /// /// Processes the tag helper @@ -89,7 +89,8 @@ public override async Task ProcessAsync(TagHelperContext context, TagHelperOutpu var componentHtml = await viewComponentHelper.InvokeAsync(Name, new { parameters = Parameters ?? _parameters, - key = Key + key = Key, + keyBehavior = KeyBehavior }); output.Content.SetHtmlContent(componentHtml);