0

I have built a custom Sitecore Form field which generates a download URL for media. It works fine using a TextBox in the Form Elements Pane to enter the GUID for a media item. However to make this more friendly for content editors I would like to use a Tree List instead so the editors can select the media item from the Media Library.

I've added a FormItemTreeView Parameters item to my Form Parameters for the custom field, and this displays correctly in the Form Elements Pane. However I cannot seem to get the ID of the selected item in the tree. At the moment I have the binding configured as per the screenshot, but I've also tried CheckedItemIds, SelectedItemValue and SelectedItem. In all cases nothing is passed back from the Tree List.

Any help would be greatly appreciated.

enter image description here

 [Serializable]
public class DownloadLinkViewModel : FieldViewModel
{
    public string SelectedItem { get; set; }
    public string ButtonValue { get; set; }
    public string MediaUrl { get; set; }

    protected override void InitItemProperties(Item item)
    {
        base.InitItemProperties(item);
        SelectedItem = StringUtil.GetString(item.Fields["SelectedItem"]);
        ButtonValue = StringUtil.GetString(item.Fields["ButtonValue"]);
        GetItemUrl(SelectedItem);
    }

    protected override void UpdateItemFields(Item item)
    {
        base.UpdateItemFields(item);
        item.Fields["SelectedItem"]?.SetValue(SelectedItem, true);
        item.Fields["ButtonValue"]?.SetValue(ButtonValue, true);
    }
    private void GetItemUrl(string id)
    {
        if(!string.IsNullOrEmpty(id))
        {
            Item item = Sitecore.Context.Database.GetItem(id);

            if(item != null)
            {
                MediaUrl = Sitecore.Resources.Media.MediaManager.GetMediaUrl(item);
            }
        }
    }
}
2
  • Can you add the code of your custom field? Dec 22, 2022 at 16:41
  • Just updated the post with the view model code. Thanks
    – Madgibbon
    Dec 22, 2022 at 17:06

1 Answer 1

0

By taking the example of how the OOTB control called DropDown List works, you can take the example of the functionality that this controls provides the user to select the datasource for the dynamic list item. Users can select the item from the content tree and it holds the value of the item.

So the OOTB control provides the following configuration for the datasource field.

enter image description here

And if you see the Model code that how it is processing the value of the datasource looks like this.

  [Serializable]
  public class ListViewModel : InputViewModel<List<string>>
  {
    [NonSerialized]
    private IFieldSettingsManager<ListFieldItemCollection> _dataSourceSettingsManager;
    private List<string> _value;

    [FieldPropertyBinder(typeof (ListValuePropertyBinder))]
    public override List<string> Value
    {
      get => this._value;
      set
      {
        this._value = value;
        this.OnValueChanged((IEnumerable<string>) value);
      }
    }

    protected virtual IFieldSettingsManager<ListFieldItemCollection> DataSourceSettingsManager => this._dataSourceSettingsManager ?? (this._dataSourceSettingsManager = ServiceLocator.ServiceProvider.GetService<IFieldSettingsManager<ListFieldItemCollection>>());

    // This is how the DataSource Field is declared. 
    public string DataSource { get; set; } = string.Empty;

    public bool IsDynamic { get; set; }

    public string DisplayFieldName { get; set; } = string.Empty;

    public string ValueFieldName { get; set; } = string.Empty;

    public List<ListFieldItem> Items { get; } = new List<ListFieldItem>();

    protected override void InitItemProperties(Item item)
    {
      Assert.ArgumentNotNull((object) item, nameof (item));
      base.InitItemProperties(item);
      // This is how the DataSource Field is binded. 
      this.DataSource = item.Fields["Datasource"]?.Value;
      this.IsDynamic = MainUtil.GetBool(item.Fields["Is Dynamic"]?.Value, false);
      this.DisplayFieldName = item.Fields["Display Field Name"]?.Value;
      this.ValueFieldName = item.Fields["Value Field Name"]?.Value;
      this.InitializeDataSourceSettings(item);
    }

    protected override void UpdateItemFields(Item item)
    {
      Assert.ArgumentNotNull((object) item, nameof (item));
      base.UpdateItemFields(item);
      string str = this.IsDynamic ? this.DataSource : string.Empty;
      item.Fields["Datasource"]?.SetValue(str, false);
      item.Fields["Is Dynamic"]?.SetValue(this.IsDynamic ? "1" : string.Empty, false);
      item.Fields["Display Field Name"]?.SetValue(this.DisplayFieldName, false);
      if (string.IsNullOrEmpty(this.ValueFieldName))
        this.ValueFieldName = !this.IsDynamic ? "Value" : "__ItemName";
      item.Fields["Value Field Name"]?.SetValue(this.ValueFieldName, false);
      string[] array = this.UpdateDataSourceSettings(item).Where<ListFieldItem>((Func<ListFieldItem, bool>) (li => li.Selected && ID.IsID(li.ItemId))).Select<ListFieldItem, string>((Func<ListFieldItem, string>) (li => li.ItemId)).ToArray<string>();
      item.Fields["Default Selection"]?.SetValue(string.Join("|", array), false);
    }

    protected override void InitializeValue(object value) => this.Value = value as List<string>;

    protected virtual void InitializeDataSourceSettings(Item item)
    {
      Assert.ArgumentNotNull((object) item, nameof (item));
      ListFieldItemCollection settings = this.DataSourceSettingsManager.GetSettings(item);
      if (settings == null)
        return;
      this.Items.Clear();
      this.Items.AddRange((IEnumerable<ListFieldItem>) settings);
    }

    protected virtual ListFieldItemCollection UpdateDataSourceSettings(
      Item item)
    {
      Assert.ArgumentNotNull((object) item, nameof (item));
      ListFieldItemCollection settings = new ListFieldItemCollection();
      settings.AddRange((IEnumerable<ListFieldItem>) this.Items);
      this.DataSourceSettingsManager.SaveSettings(item, settings);
      return settings;
    }

    protected virtual void OnValueChanged(IEnumerable<string> value) => this.Items.ForEach((Action<ListFieldItem>) (i => i.Selected = value.Contains<string>(i.Value)));

    public override string GetStringValue() => this.Value != null && this.Value.Any<string>() ? this.Value.Aggregate<string>((Func<string, string, string>) ((x, y) => x + "," + y)) : string.Empty;
  }

So I would suggest here to go through the approach and do the code updates to bind your field by using a statement like this.

this.DataSource = item.Fields["Datasource"]?.Value;

Hope this helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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