Search code examples
c#dictionaryliquiddotliquid

DotLiquid: Loop through a (Wrapped) Dictionary<string, string> in for-loop in template


As far as I know, DotLiquid (using Version 1.8.0.0) does not support C# Dictionary constructs out of the box. They must be wrapped in a Drop-Object.

So I tried to adapt the Answer of Tim Jones for my use-case. Sadly, this is not working as expected, So I hope someone could show me where I'm going wrong here, for I am out of Ideas.

This is (one of) my wrapped model class containing a Dictionary:

public class LegendAdditive : Drop
{
    public LegendAdditive() 
    {
        AdditiveDict = new Dictionary<string, string>();
    }

    public Dictionary<string, string> AdditiveDict { get; set; }
}

The class itself is embedded in a LegendModel containing some other values:

public class LegendModel: Drop
{
    ...
    public LegendAdditive Additives { get; set; }
    ...
}

As you can see, all the Classes are wrapped to be a Drop, which as I know is a prerequisite for using Dictionaries (Implementing ILiquidizable and so on).

In a converter, this Model is filled like this:

public DotLiquid.Drop GetModel(MyObject plan) 
{
    ...
    var LegendAdditives = new LegendAdditive();

    //dbLegend.Additives is a Dictionary<string, string> itself.
    if (dbLegend.Additives.Any())
        foreach (var additive in dbLegend.Additives.OrderBy(a => a.Key))
            LegendAdditives.AdditiveDict.Add(additive.Key, additive.Value);

   ...

    LegendModel model = new LegendModel
    {
        ...
        Additives = LegendAdditives,
        ...
    };

    return model; 
}

And in a class ConvertToPdf, I have a ConvertTemplate Method like this, parsing the template:

public static string ConvertTemplate(ITemplateFileFactory templateFilePathFactory IDropModelConverter modelConverter, MyObject mplan)
{
    //reading my filepath out of the factory here...

    DotLiquid.Template.NamingConvention = new DotLiquid.NamingConventions.CSharpNamingConvention();

    Template templateObj = Template.Parse(template);  // Parses and compiles the template
    Drop plan = modelConverter.GetModel(mplan);
    Hash hashedValues = Hash.FromAnonymousObject(new { plan });
    string ret = templateObj.Render(hashedValues);
    return ret;
}

And finally in my Templatefile, I try to get the Values of this Dictionary like this:

<div>
    <dl>
        {% for add in plan.Additives.AdditiveDict %}
        <dt>{{add.Key}}</dt>
        <dd>{{add.Value}}</dd>
        {% endfor %}
    </dl>
</div>

Now the file is parsing correctly, but all I get for now is this output when I try to access the Dictionaryvalues in my loop:

Liquid syntax error: Object '[18, Stärke]' is
invalid because it is neither a built-in type
nor implements ILiquidizable

Now it seems that I actually get the correct Values in my Template.Parse Method. I'm just not getting them out of my structure, because...? Any help is appreciated. To be honest, I think I am missing something fundamentally here.


Solution

  • The problem is that KeyValuePair<T>, which you're trying to access the Key and Value properties of, is neither a Drop nor implements ILiquidizable.

    If you want to loop through the items in your dictionary like that, you'll have to create a KeyValueDrop wrapper, and expose a List of that, instead of a dictionary.