Search code examples
c#.netasp.net-mvchtml-helper

Get comma-separated string from CheckboxList HTML Helper


I got the following code from the internet for CheckboxListFor html helper extension. At the moment, in the SelectedValues it is returning a List<string> of selected values from the checkboxlist. I want to get a comma-separated string in SelectedValues.

Can anyone tell me how I can achieve it?

Here is the code:

HTMLHelper extension:

        /// <summary>
    /// Returns a checkbox for each of the provided <paramref name="items"/>.
    /// </summary>
    public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper, string listName, IEnumerable<SelectListItem> items, object htmlAttributes = null)
    {
        var container = new TagBuilder("div");
        foreach (var item in items)
        {
            var label = new TagBuilder("label");
            label.MergeAttributes(new RouteValueDictionary(htmlAttributes), true);

            var cb = new TagBuilder("input");
            cb.MergeAttribute("type", "checkbox");
            cb.MergeAttribute("name", listName);
            cb.MergeAttribute("value", item.Value ?? item.Text);
            if (item.Selected)
                cb.MergeAttribute("checked", "checked");

            label.InnerHtml = cb.ToString(TagRenderMode.SelfClosing) + item.Text;

            container.InnerHtml += label.ToString();
        }

        return new MvcHtmlString(container.ToString());
    }

    private static IEnumerable<SelectListItem> GetCheckboxListWithDefaultValues(object defaultValues, IEnumerable<SelectListItem> selectList)
    {
        var defaultValuesList = defaultValues as IEnumerable;

        if (defaultValuesList == null)
            return selectList;

        IEnumerable<string> values = from object value in defaultValuesList
                                     select Convert.ToString(value, CultureInfo.CurrentCulture);

        var selectedValues = new HashSet<string>(values, StringComparer.OrdinalIgnoreCase);
        var newSelectList = new List<SelectListItem>();

        selectList.ForEach(item =>
        {
            item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text);
            newSelectList.Add(item);
        });

        return newSelectList;
    }

    /// <summary>
    /// Returns a checkbox for each of the provided <paramref name="items"/>.
    /// </summary>
    public static MvcHtmlString CheckBoxListFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper, 
        Expression<Func<TModel, TValue>> expression, 
        IEnumerable<SelectListItem> items, object htmlAttributes = null)
    {
        var listName = ExpressionHelper.GetExpressionText(expression);
        var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        items = GetCheckboxListWithDefaultValues(metaData.Model, items);
        return htmlHelper.CheckBoxList(listName, items, htmlAttributes);
    }

In the view:

@Html.CheckBoxListFor(model => model.SelectedValues, Model.MySelectList)

Model:

public class MyViewModel
{        
      public SelectList MySelectList{ get; set; }

      public List<string> SelectedValues{ get; set; }

      //public string SelectedValues{ get; set; }   Can I get comma separated string here
}

Note that I need comma separated string returned from the helper not after I got back list on the controller action.

Why I am trying to do this?:

//Here in my model, I am getting `SelectedValues` which is a List<String>.
public ActionResult Index(MyViewModel model)
{
      //My code....
}

In View

//But I cannot save this list into RouteValueDictionary like:
var searchCriteria = new RouteValueDictionary();
searchCriteria["model.SelectedValues"] = Model.SelectedValues; // List<string> cannot be save here. That's why I needed comma separated string.
var viewDataDictionary = new ViewDataDictionary();
viewDataDictionary["searchCriteria"] = searchCriteria;

@Html.Partial("_MyPagingView", Model.MyList, viewDataDictionary)

There is a whole mechanism inside the _MyPagingView which calls Index Action whenever next page is clicked. And to preserve the state of the search we need to keep our searched data inside RouteValueDictionary.


Solution

  • You could create a helper method to add theSelectedValues to aRouteValueDictionary

    public void AddRoutes(List<string> values, string propertyName, RouteValueDictionary dictionary)
    {
        for (int i = 0; i < values.Count; i++ )
        {
            string key = string.Format("{0}[{1}]", propertyName, i);
            dictionary[key] = values[i];
        }
    }
    

    and then use it as

    var searchCriteria = new RouteValueDictionary();
    AddRoutes(Model.SelectedValues, "SelectedValues", searchCriteria);
    

    and avoid the need to create a hidden input and use javascript