Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Navbar shape for Liquid #15532

Merged
merged 7 commits into from
Mar 21, 2024
Merged

Add Navbar shape for Liquid #15532

merged 7 commits into from
Mar 21, 2024

Conversation

MikeAlhayek
Copy link
Member

@MikeAlhayek MikeAlhayek commented Mar 17, 2024

Fix #15148

@MikeAlhayek
Copy link
Member Author

@sebastienros with this change, I am expecting to be able to add the following in a Layout.liquid file

{% assign navbarShape = Navbar | shape_render %}

Then later in the same file, I want to print out the rendered shape like this

{{ navbarShape }}

However, this is not working as expected. Any idea why Navbar is not rendering using Liquid?

@MikeAlhayek
Copy link
Member Author

If I add use filter it works but I should not have to use filter.

Here is how it works using filters. First I register the temporary filter services.AddLiquidFilter<NavbarShapeFilter>("navbar_new");.
Then in the Layout.liquid I add {% assign navbarShape = "" | navbar_new | shape_render %} then render it later using
{{ navbarShape }}

@sebastienros @lahma

Beside the following, what else do I need to do so that Liquid recognize Navbar as a value that us constructed using the callback?

 services.Configure<TemplateOptions>(o =>
 {
     o.Scope.SetValue(nameof(Navbar), new ObjectValue(new NavbarAccessor()));
     o.MemberAccessStrategy.Register<NavbarAccessor, FluidValue>(async (obj, name, ctx) =>
     {
         if (ctx is LiquidTemplateContext context)
         {
             var displayManager = context.Services.GetRequiredService<IDisplayManager<Navbar>>();
             var updateModelAccessor = context.Services.GetRequiredService<IUpdateModelAccessor>();

             var shape = await displayManager.BuildDisplayAsync(updateModelAccessor.ModelUpdater);

             return FluidValue.Create(shape, ctx.Options);
         }

         return NilValue.Instance;
     });

     o.MemberAccessStrategy.Register<Navbar, FluidValue>((navbar, name, context) =>
     {
         return name switch
         {
             nameof(Navbar.Properties) => new ObjectValue(navbar.Properties),
             _ => NilValue.Instance
         };
     });
 });

@sebastienros
Copy link
Member

I think it's not possible right now, because there is no way to evaluate a FluidValue (Navbar) lazily and asynchronously. It's possible to evaluate it lazily by creating a custom FluidValue whose ToObjectValue() will return something on demand, but in your case you want it to be a shape that is built asynchronously.

Only property accessors are asynchronous (ValueTask<FluidValue> GetValueAsync(string name, TemplateContext context)) which are used by the Register method. So doing Navbar.Something | filter can be asynchonous, but not Navbar | filter.

An alternative could be to create a custom Function and register it like this:

o.Scope.SetValue(nameof(Navbar), new FunctionValue((args, context) => 
{
   if (ctx is LiquidTemplateContext context)
   {
       var displayManager = context.Services.GetRequiredService<IDisplayManager<Navbar>>();
       var updateModelAccessor = context.Services.GetRequiredService<IUpdateModelAccessor>();

       var shape = await displayManager.BuildDisplayAsync(updateModelAccessor.ModelUpdater);

       return FluidValue.Create(shape, ctx.Options);
   }

   return NilValue.Instance;
}));

And then use it this way:

{{ Navbar() }}

NB: It could even take arguments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Culture Picker is not rendering cultures after upgrading to v1.8.2
2 participants