Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC: Custom, fluent Html Helpers

I'm writing a custom HTML helper to display a Grid and I'm focussing myself on Telerik and other parties for the syntax I would like to use.

I have a model with 3 properties (Name, DateUpdated and DateCreted) and an IEnumerable of that one is passed to my view:

@model IEnumerable<GridPageFolderViewModel>

Then I have my static HtmlHelperExtensions class:

public static class HtmlHelperExtensions
{
    #region Grid

    public static GridBuilder<TModelEntry> GridFor<TModel, TModelEntry>(this HtmlHelper<TModel> htmlHelper, TModelEntry model)
    {
        return new GridBuilder<TModelEntry>();
    }

    #endregion
}

This class does return a GridBuilder which looks as the following:

public class GridBuilder<TModel> : IGridBuilder
{
    #region Properties

    private string name { get; set; }

    #endregion

    #region Methods

    public GridBuilder<TModel> WithColumns(Action<ColumnBuilder<TModel>> function)
    {
        return this;
    } 

    internal MvcHtmlString Render()
    {
        return new MvcHtmlString("This is a value.");
    }

    #endregion

    #region IGridBuilder Members

    public GridBuilder<TModel> Name(string name)
    {
        this.name = name;

        return this;
    }

    #endregion

    #region IHtmlString Members

    public string ToHtmlString()
    { return Render().ToHtmlString(); }

    #endregion
}

And then I have my ColumnBuilder class.

public class ColumnBuilder<TModel>
{
    public void Bind<TItem>(Func<TModel, TItem> func)
    {

    }
}

With all this code into place (nothing is rendered at this point), I can use the following syntax:

@(Html.GridFor(new GridPageFolderViewModel())
      .Name("PageOverviewGrid")
      .WithColumns(column =>
      {
          column.Bind(c => c.Name);
          column.Bind(c => c.DateCreated);
          column.Bind(c => c.DateUpdated);
      }
)

The 'problem' here is that I need to specify the type of object that a single item in the Grid is holding (the GridPageFolderViewModel), otherwise, I cannot access the properties in the column binder code.

Anyone has some advice on how I can get rid of it?

like image 472
Complexity Avatar asked Nov 11 '22 07:11

Complexity


1 Answers

As the view model is IEnumerable<GridPageFolderViewModel>, you just need to declare your helper like this:

public static GridBuilder<TModelEntry> GridFor<TModelEntry>(this HtmlHelper<IEnumerable<TModelEntry>> htmlHelper)
{
    return new GridBuilder<TModelEntry>();
}

It would mean your helper can only be used on views where the model is an IEnumerable<T>, but I think that makes sense.

Now in your view you can do:

@(Html.GridFor()
      .Name("PageOverviewGrid")
      .WithColumns(column =>
      {
          column.Bind(c => c.Name);
          column.Bind(c => c.DateCreated);
          column.Bind(c => c.DateUpdated);
      }
)

PS. Don't worry if you need to access the model inside your helper. You can still retrieve it from htmlHelper.ViewData.Model, which will be nicely typed as IEnumerable<TModelEntry>

Hope it helps!

like image 120
Daniel J.G. Avatar answered Nov 15 '22 12:11

Daniel J.G.