Handlebars-Net / Handlebars.Net

A real .NET Handlebars engine

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

each with condition

gstrit opened this issue · comments

Hello,

I would like to write a each block helper with one condition. Exactly like that : https://stackoverflow.com/questions/41790849/how-do-i-filter-this-array-using-value-with-handlebars-js

The goal is to have the @last correct.

Thanks for your help.

Hello @gstrit
What is the problem you're facing?
Share the code you currently have and I'd be able to assist with modifying it.

Hello @zjklee

_handlebars.RegisterHelper("each_when", (writer, options, context, arguments) => 
{
  var enumerable = (IEnumerable)arguments[0];
  var property = (string)arguments[1];
  var value = (string)arguments[2];
  var enumerator = enumerable.GetEnumerator();

  while(enumerator.MoveNext()) {
      if(enumerator.Current.property == value) //here I should be able to check if the property has the good value
           options.Template(writer, enumerator.Current);
      }
});

I don't know how to dynamically check the value and I don't know how to set @FIRST and @last fields with the good values.
@FIRST and @last should be set according the filter. If the first value of the list doesn't match the property and its value, it should not be assigned to the @FIRST field.


Edit note: fixed code block (@zjklee)

@gstrit , should be something like this (I haven't tested it though):

handlebars.RegisterHelper("each_when", (writer, options, context, arguments) => 
{
    var target = (IEnumerable)arguments[0];
    var property = (string)arguments[1];
    var value = (string)arguments[2];
    using var frame = options.CreateFrame();

    var iterator = new IteratorValues(frame);
    var blockParamsValues = new BlockParamsValues(frame, options.BlockVariables);

    blockParamsValues.CreateProperty(0, out var _0);
    blockParamsValues.CreateProperty(1, out var _1);

    var enumerator = ExtendedEnumerator<object>.Create(target.GetEnumerator());

    iterator.First = BoxedValues.True;
    iterator.Last = BoxedValues.False;
    
    var index = 0;
    var executed = false;
    while(enumerator.MoveNext()) 
    {
        var current = enumerator.Current;
        var instance = current.Value;
        
        if (
            !options.TryAccessMember(instance, property, out var v) 
            || v.ToString() != value
        ){ continue; }

        executed = true;
        var indexObject = BoxedValues.Int(index);
    
        if (index == 1) iterator.First = BoxedValues.False;
        if (current.IsLast) iterator.Last = BoxedValues.True;

        iterator.Key = iterator.Index = indexObject;
    
        blockParamsValues[_0] = value;
        blockParamsValues[_1] = indexObject;
    
        iterator.Value = value;
        frame.Value = value;

        options.Template(writer, frame);

        ++index;
    }

    if (!executed)
    {
        options.Template(writer, context);
    }
});

@gstrit , alternative approach:

handlebars.RegisterHelper("each_when", (writer, options, context, arguments) => 
{
    var property = (string)arguments[1];
    var value = arguments[2];
    
    var target = ((IEnumerable)arguments[0])
        .OfType<object>()
        .Where(o => options.TryAccessMember(o, property, out var v) && v.Equals(value));
    
    if (!ObjectDescriptor.TryCreate(target, out var descriptor))
    {
        options.Inverse(writer, context);
        return;
    }
    
    descriptor.Iterator.Iterate(writer, options.Frame, options.BlockVariables, target, options.Template, options.Inverse);
});