1

I would like to output data-attributes on the link created by a VariantField that outputs a value from a General Link field using a token.

Simple data-attributes work fine(string as a value). But my problem is that the value of my data-attribute should come from a token.

I have implemented a custom VariantField (https://ggullentops.blogspot.com/2018/10/using-tokens-in-sitecore-sxa-variant.html) and it works fine when it is not using a General Link to populate the data.

When General Link is used, the code never gets to my custom string GetAttributeTokenValue(string fieldName, Item item) method.

Any ideas?

Regards, Nicolas

0

Lol, I have the same problem yesterday and fixed it. Decompile the "RenderVariantField" pipeline in "Sitecore.XA.Foundation.RenderingVariants.Pipelines.RenderVariantField", patch the config that the pipeline points to your implementation ("patch:instead").

There are two problems:

First Problem:

Your Link field, like the default in the Link-Component, is rendered like this (I removed the customdata-attribute...):

<div class="field-link" #DATA-ATTRIBUTE SHOULD APPEAR HERE#>
<a target="_blank" data-variantitemid="{40BCAED1-7B1F-4B00-9B68-BC26BE3094EA}" href="http://www.google.de" rel="noopener noreferrer" data-variantfieldname="Link" sc-part-of="field" class="scEnabledChrome">Link Text</a>

The data attribute is not set, because of the "RenderVariantField" pipeline. I don't know why but SXA prevents to add attributes to "images" and "general links":

protected virtual void AddWrapperDataAttributes(
  Sitecore.XA.Foundation.RenderingVariants.Fields.VariantField variantField,
  RenderVariantFieldArgs args,
  HtmlGenericControl tag)
{
  if (variantField.DataAttributes.Count <= 0)
    return;
  Field field = args.Item.Fields[variantField.FieldName];
  string first = field != null ? field.Type : string.Empty;
  if (first.Is("Image") || first.Is("General Link"))
    return;
  this.AddWrapperDataAttributes((RenderingVariantFieldBase) variantField, args, tag);
}

This could easily be fixed, but this leads directly to the second problem...

Second Problem:

Even if you change that behaviour, for example you want to add a style attribute like "style: color: #fff;", the styles will not be applied on the link, because the color will be overwritten by the "optimized.min.css" file and your link will still be black.

After deeper investigation I saw that the general link control is rendered in a different way and they missed to replace the tokens there. But overwriting this method was the solution for me! Original code:

protected virtual IDictionary<string, string> GetVariantAttributes(
  RenderingVariantFieldBase variantField,
  Item item)
{
  Dictionary<string, string> dictionary = new Dictionary<string, string>();
  if (variantField.DataAttributes.Count > 0)
  {
    foreach (string dataAttribute1 in (NameObjectCollectionBase) variantField.DataAttributes)
    {
      string dataAttribute2 = variantField.DataAttributes[dataAttribute1];
      if (!string.IsNullOrWhiteSpace(dataAttribute2))
      {
        string str = this.ResolveAttributeValues(dataAttribute2, item, (object) null);
        if (!string.IsNullOrWhiteSpace(str))
          dictionary.Add(dataAttribute1, str);
      }
    }
  }
  return (IDictionary<string, string>) dictionary;
}

For me the code looks similar to the "AddWrapperDataAttributes"-Method, but without the part were they replace the token values. I added a new method for the "GetAttributeTokenValues"-Method which works for a "Dictionary" instead of a "AttributeCollection":

    // Custom Implementation for a Dictionary
    protected virtual void GetAttributeTokenValues(
        Item item,
        Dictionary<string, string> attributes,
        MatchCollection matches,
        string value,
        string key)
    {
        foreach (Match match in matches)
        {
            var attributeTokenValue = GetAttributeTokenValue(match.Groups[1].Value, item);
            value = value.Replace(match.Value, attributeTokenValue);
            attributes.Add(key, value);
        }
    }

Then overwrite the "GetVariantsAttribute"-Method like this:

    // Note: Override due to token customization
    protected override IDictionary<string, string> GetVariantAttributes(
        RenderingVariantFieldBase variantField,
        Item item)
    {
        var dictionary = new Dictionary<string, string>();

        if (variantField.DataAttributes.Count <= 0)
        {
            return dictionary;
        }

        foreach (string dataAttribute1 in variantField.DataAttributes)
        {
            var dataAttribute2 = variantField.DataAttributes[dataAttribute1];
            if (string.IsNullOrWhiteSpace(dataAttribute2))
            {
                continue;
            }

            // Customization: We do here check for Tokens as well
            var matches = AttributeFieldToken.Matches(dataAttribute2);
            if (matches.Count > 0)
            {
                GetAttributeTokenValues(item, dictionary, matches, dataAttribute2, dataAttribute1);
            }
            else
            {
                var str = ResolveAttributeValues(dataAttribute2, item, null);
                if (!string.IsNullOrWhiteSpace(str))
                {
                    dictionary.Add(dataAttribute1, str);
                }
            }
        }

        return dictionary;
    }

That works like a charm! The attributes are now added to the inner link (I removed the customdata-attribute...):

<div class="field-link">
<a target="_blank" !!! style="color: #fff;" !!! data-variantitemid="{40BCAED1-7B1F-4B00-9B68-BC26BE3094EA}" href="http://www.google.de" rel="noopener noreferrer" data-variantfieldname="Link" sc-part-of="field" class="scEnabledChrome">Link Text</a>

Give it a try! Have fun!

Best regards Dirk

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.