Skip to content

Commit

Permalink
Merge pull request #95 from hydrostack/add-key-attribute-behavior
Browse files Browse the repository at this point in the history
Add key bahavior
  • Loading branch information
kjeske authored Oct 2, 2024
2 parents b2e724c + c5ba35b commit b595da0
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 9 deletions.
19 changes: 19 additions & 0 deletions docs/content/features/parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,25 @@ or
<hydro name="Product" key="2"/>
```

You can also use `key` to force re-render of your component:

```razor
<hydro name="Items" params="@(new { Model.Items })" key="@Model.Items.GetHashCode()" />
```

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
<hydro name="Currency" key="PL" key-behavior="Morph" />
```

## 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,
Expand Down
22 changes: 17 additions & 5 deletions src/HydroComponent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,12 @@ public abstract class HydroComponent : ViewComponent
/// </summary>
[JsonProperty]
protected string Key { get; private set; }

/// <summary>
/// Component's HTML behavior when the key changes
/// </summary>
[JsonProperty]
protected KeyBehavior KeyBehavior { get; private set; }

/// <summary>
/// Default identifier used to specify place of the page to replace when during location change
Expand Down Expand Up @@ -138,12 +144,14 @@ private void ConfigurePolls()
/// </summary>
/// <param name="parameters">An object with component parameters</param>
/// <param name="key">Local identifier to distinguish components of same type</param>
public async Task<IHtmlContent> InvokeAsync(object parameters = null, string key = null)
/// <param name="keyBehavior">Component's HTML behavior when the key changes</param>
public async Task<IHtmlContent> 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<IPersistentState>();
_options = HttpContext.RequestServices.GetService<HydroOptions>();
Expand Down Expand Up @@ -430,7 +438,7 @@ private async Task<string> RenderOnlineNestedComponent(IPersistentState persiste

if (IsComponentIdRendered(componentId))
{
return GetComponentPlaceholderTemplate(componentId, Key);
return GetComponentPlaceholderTemplate(componentId, Key, KeyBehavior);
}

if (!await AuthorizeAsync())
Expand All @@ -444,8 +452,12 @@ private async Task<string> RenderOnlineNestedComponent(IPersistentState persiste
return await GenerateComponentHtml(componentId, persistentState, includeScripts: true);
}

private static string GetComponentPlaceholderTemplate(string componentId, string key) =>
$"<div id=\"{componentId}\" {(!string.IsNullOrWhiteSpace(key) ? $"key=\"{key}\"" : "")} hydro hydro-placeholder></div>";
private static string GetComponentPlaceholderTemplate(string componentId, string key, KeyBehavior keyBehavior)
{
var useKey = !string.IsNullOrWhiteSpace(key) && keyBehavior == KeyBehavior.Replace;

return $"<div id=\"{componentId}\" {(useKey ? $"key=\"{key}\"" : "")} hydro hydro-placeholder></div>";
}

private async Task<string> RenderStaticComponent(IPersistentState persistentState)
{
Expand Down Expand Up @@ -496,7 +508,7 @@ private async Task<string> 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);
}
Expand Down
17 changes: 17 additions & 0 deletions src/KeyBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Hydro;

/// <summary>
/// Defines the component behavior when key changes
/// </summary>
public enum KeyBehavior
{
/// <summary>
/// Replace the component's HTML
/// </summary>
Replace,

/// <summary>
/// Morph the component's HTML
/// </summary>
Morph
}
9 changes: 5 additions & 4 deletions src/TagHelpers/HydroComponentTagHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,10 @@ public IDictionary<string, object> ParametersDictionary
public int? Delay { get; set; } = 0;

/// <summary>
///
/// Component's HTML behavior when the key changes
/// </summary>
[HtmlAttributeName("run")]
public bool Run { get; set; }
[HtmlAttributeName("key-behavior")]
public KeyBehavior KeyBehavior { get; set; } = KeyBehavior.Replace;

/// <summary>
/// Processes the tag helper
Expand All @@ -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);
Expand Down

0 comments on commit b595da0

Please sign in to comment.