private static MvcHtmlString CascadingDropDownListInternal([NotNull] HtmlHelper thisValue, [NotNull] string name, [NotNull] string triggeredByProperty, CascadeDropDownListSettings settings = null, RouteValueDictionary htmlAttributes = null)
        {
            name = name.Trim();
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException(nameof(name));
            }
            settings ??= new CascadeDropDownListSettings();
            htmlAttributes ??= new RouteValueDictionary();

            string cascadeDdElementId = settings.Id?.Trim();

            if (string.IsNullOrEmpty(cascadeDdElementId))
            {
                cascadeDdElementId = GetDropDownElementId(htmlAttributes);
            }
            if (string.IsNullOrEmpty(cascadeDdElementId))
            {
                cascadeDdElementId = name;
            }

            htmlAttributes.Add("data-cascade-dd-url", settings.Url);

            string setDisableString     = string.Empty;
            string removeDisabledString = string.Empty;

            if (settings.OptionLabel != null)
            {
                htmlAttributes.Add("data-option-lbl", settings.OptionLabel);
            }

            if (settings.DisabledWhenParentNotSelected)
            {
                htmlAttributes.Add("disabled", "disabled");
                setDisableString     = "targetElement.setAttribute('disabled','disabled');";
                removeDisabledString = "targetElement.removeAttribute('disabled');";
            }

            MvcHtmlString defaultDropDownHtml = thisValue.DropDownList(name, Array.Empty <SelectListItem>(), settings.OptionLabel, htmlAttributes);
            StringBuilder builder             = new StringBuilder(Constants.BUFFER_KB);
            string        optionLblStr        = settings.OptionLabel == null ? "''" : $@"'<option value="""">{settings.OptionLabel}</option>'";

            builder.AppendFormat(Js1CreateInitFunction, cascadeDdElementId, triggeredByProperty, settings.SelectedValue, removeDisabledString, optionLblStr, setDisableString);
            builder.Append(string.IsNullOrEmpty(settings.ClientSideEvents.BeforeSend)
                                ? string.Format(Js2SimpleGenerateJsonToSendFormat, settings.AjaxActionParamName)
                                : string.Format(Js2GenerateJsonToSendFromFunctionFormat, settings.ClientSideEvents.BeforeSend, settings.AjaxActionParamName));
            builder.Append(settings.HttpMethod == null || settings.HttpMethod != HttpMethod.Post
                                ? Js3InitializeGetRequest
                                : Js3InitializePostRequest);

            string onComplete = null;
            string onSuccess  = null;
            string onFailure  = null;

            if (!string.IsNullOrEmpty(settings.ClientSideEvents.OnSuccess))
            {
                onSuccess = $"{settings.ClientSideEvents.OnSuccess}(data);";
            }

            if (!string.IsNullOrEmpty(settings.ClientSideEvents.OnFailure))
            {
                onFailure = $"{settings.ClientSideEvents.OnFailure}(request.responseText, request.status, request.statusText);";
            }

            if (!string.IsNullOrEmpty(settings.ClientSideEvents.OnComplete))
            {
                onComplete = $"{settings.ClientSideEvents.OnComplete}(data, null);";
            }

            builder.AppendFormat(Js4OnLoadFormat, onComplete ?? string.Empty, onSuccess ?? string.Empty, onFailure ?? string.Empty);

            onComplete = null;
            onFailure  = null;


            if (!string.IsNullOrEmpty(settings.ClientSideEvents.OnComplete) || !string.IsNullOrEmpty(settings.ClientSideEvents.OnFailure))
            {
                if (!string.IsNullOrEmpty(settings.ClientSideEvents.OnComplete))
                {
                    onComplete = $"{settings.ClientSideEvents.OnComplete}(null, request.responseText);";
                }

                if (!string.IsNullOrEmpty(settings.ClientSideEvents.OnSuccess))
                {
                    onFailure = $"{settings.ClientSideEvents.OnFailure}(request.responseText, request.status, request.statusText);";
                }

                builder.AppendFormat(Js5ErrorCallback, onComplete, onFailure);
            }

            builder.Append(settings.HttpMethod == null || settings.HttpMethod != HttpMethod.Post
                                ? Js6SendGetRequest
                                : Js6SendPostRequest);

            builder.AppendFormat(Js7EndFormat, cascadeDdElementId);
            return(new MvcHtmlString(string.Concat(defaultDropDownHtml, Environment.NewLine, "<script type='text/javascript'>", builder, "</script>", Environment.NewLine)));
        }
        public static MvcHtmlString CascadingDropDownListFor <TModel, TProperty>([NotNull] this HtmlHelper <TModel> thisValue, [NotNull] Expression <Func <TModel, TProperty> > expression, [NotNull] string triggeredByPropertyWithId, CascadeDropDownListSettings settings = null, object htmlAttributes = null)
        {
            string dropDownElementName = thisValue.GetElementNameFromExpression(expression)?.Trim();

            if (string.IsNullOrEmpty(dropDownElementName))
            {
                throw new ArgumentException("Drop down element name is missing.", nameof(expression));
            }

            settings ??= new CascadeDropDownListSettings();
            if (string.IsNullOrWhiteSpace(settings.Id))
            {
                settings.Id = thisValue.GetElementIdFromExpression(expression);
            }
            settings.SelectedValue = GetPropStringValue(thisValue.ViewData.Model, expression);

            return(CascadingDropDownListInternal(thisValue, dropDownElementName, triggeredByPropertyWithId, settings, Helpers.HtmlHelper.ToHtmlAttributes(htmlAttributes)));
        }
 public static MvcHtmlString CascadingDropDownList([NotNull] this HtmlHelper thisValue, [NotNull] string name, [NotNull] string triggeredByProperty, CascadeDropDownListSettings settings = null, RouteValueDictionary htmlAttributes = null)
 {
     settings ??= new CascadeDropDownListSettings();
     settings.SelectedValue = GetPropStringValue(thisValue.ViewData.Model, name);
     return(CascadingDropDownListInternal(thisValue, name, triggeredByProperty, settings, htmlAttributes));
 }
        public static MvcHtmlString CascadingDropDownList <TModel, TProperty>([NotNull] this HtmlHelper <TModel> thisValue, [NotNull] string name, [NotNull] Expression <Func <TModel, TProperty> > triggeredByProperty, CascadeDropDownListSettings settings = null, object htmlAttributes = null)
        {
            string triggeredByPropId = thisValue.GetElementIdFromExpression(triggeredByProperty)?.Trim();

            if (string.IsNullOrEmpty(triggeredByPropId))
            {
                throw new ArgumentException("Triggered by property id is missing.", nameof(triggeredByProperty));
            }
            return(CascadingDropDownList(thisValue, name, triggeredByPropId, settings, htmlAttributes));
        }