protected override void ProcessCore(TagHelperContext context, TagHelperOutput output)
        {
            if (For != null)
            {
                TargetInputSelector = "#" + HtmlHelper.GenerateIdFromName(For.Name);
            }

            var options = new
            {
                entityType           = EntityType,
                url                  = UrlHelper.Action("Picker", "Entity", new { area = string.Empty }),
                caption              = (DialogTitle.NullEmpty() ?? Caption).HtmlEncode(),
                disableIf            = DisableGroupedProducts ? "groupedproduct" : (DisableBundleProducts ? "notsimpleproduct" : null),
                disableIds           = DisabledEntityIds == null ? null : string.Join(',', DisabledEntityIds),
                thumbZoomer          = EnableThumbZoomer,
                highligtSearchTerm   = HighlightSearchTerm,
                returnField          = FieldName,
                delim                = Delimiter,
                targetInput          = TargetInputSelector,
                selected             = Selected,
                appendMode           = AppendMode,
                maxItems             = MaxItems,
                onDialogLoading      = OnDialogLoadingHandler,
                onDialogLoaded       = OnDialogLoadedHandler,
                onSelectionCompleted = OnSelectionCompletedHandler
            };

            var buttonId = "entpicker-toggle-" + CommonHelper.GenerateRandomInteger();

            output.TagName = "button";
            output.TagMode = TagMode.StartTagAndEndTag;
            output.MergeAttribute("id", buttonId);
            output.MergeAttribute("type", "button");
            output.AppendCssClass("btn btn-secondary");

            if (IconCssClass.HasValue())
            {
                output.Content.AppendHtml($"<i class='{ IconCssClass }'></i>");
            }

            if (Caption.HasValue())
            {
                output.Content.AppendHtml($"<span>{ Caption }</span>");
            }

            var json = JsonConvert.SerializeObject(options, new JsonSerializerSettings
            {
                ContractResolver  = SmartContractResolver.Instance,
                Formatting        = Formatting.None,
                NullValueHandling = NullValueHandling.Ignore
            });

            output.PostElement.AppendHtmlLine(@$ "<script data-origin='EntityPicker'>$(function() {{ $('#{buttonId}').entityPicker({json}); }})</script>");
        }
        private void UpdateModel(IEnumerable <TItem> items)
        {
            var modifiedNodes = new List <TreeNode <TItem> >();
            var dict          = new Dictionary <string, TreeNode <TItem> >();

            foreach (var item in items)
            {
                // get key value and check is given and unique
                var key = KeyField !(item)?.ToString();
                if (key is null || string.IsNullOrEmpty(key))
                {
                    throw new PDTreeException("Items must supply a key value.");
                }

                // get parent key and find parent node
                var parentKey = ParentKeyField?.Invoke(item)?.ToString();
                TreeNode <TItem>?parentNode = null;
                if (parentKey == null || string.IsNullOrWhiteSpace(parentKey))
                {
                    parentNode = RootNode;
                }
                else
                {
                    parentNode = (dict.ContainsKey(parentKey)) ? parentNode = dict[parentKey] : RootNode.Find(parentKey);
                }
                if (parentNode == null)
                {
                    throw new PDTreeException($"A parent item with key '{parentKey}' could not be found");
                }

                // does the node already exist?
                var node = parentNode.Find(key);
                if (node is null)
                {
                    node = new TreeNode <TItem>();
                    // add to parent node and mark parent node for re-sort
                    (parentNode.Nodes ??= new List <TreeNode <TItem> >()).Add(node);
                    if (!modifiedNodes.Contains(parentNode))
                    {
                        modifiedNodes.Add(parentNode);
                    }
                }
                node.Key          = key;
                node.Text         = TextField?.Invoke(item)?.ToString() ?? item.ToString();
                node.IsExpanded   = false;
                node.Data         = item;
                node.ParentNode   = parentNode;
                node.Level        = parentNode.Level + 1;
                node.IconCssClass = IconCssClass?.Invoke(item, parentNode.Level + 1) ?? string.Empty;
                node.Nodes        = LoadOnDemand ? null : new List <TreeNode <TItem> >();
                if (LoadOnDemand && IsLeaf != null && IsLeaf(item))
                {
                    node.Nodes = new List <TreeNode <TItem> >();
                }

                // cache node for performance
                dict.Add(key, node);
            }

            // re-apply sorts where necessary
            foreach (var node in modifiedNodes)
            {
                node?.Nodes?.Sort(NodeSort);
            }
        }