DmitryEfimenko / TwitterBootstrapMvc

Fluent implementation of ASP.NET-MVC HTML helpers for Twitter Bootstrap.
Apache License 2.0
224 stars 79 forks source link

DisplayTextFor not using DataFormatString on model #114

Closed mikestu closed 10 years ago

mikestu commented 10 years ago

When using the DisplayTextFor, I can't seem to get the date to use my DataFormatString to take off the time. If I use the @Html.DisplayFor, it does format the date. Is this something you can fix in the Bootstrap helpers, or am I doing something wrong? Thanks!

@Html.Bootstrap().FormGroup().DisplayTextFor(m => m.OrderDate) @Html.DisplayFor(m => m.OrderDate)

[Display(Name = "Order Date")] [DisplayFormat(DataFormatString = "{0:M/d/yyyy}")] public DateTime OrderDate { get; set; }

Update: I am using version 3.4.1

DmitryEfimenko commented 10 years ago

BMVC .DisplayTextFor() is equivalent to @Html.DisplayTextFor(), not @Html.DisplayFor(). These are two different helpers.

I'm not sure now whether it would be appropriate to change implementation of BMVC DisplayTextFor to use @Html.DisplayFor() or should I introduce a new, spearate BMVC helper... What do you think?

mikestu commented 10 years ago

I didn't know the technical difference in those two, but found this: http://forums.asp.net/t/1902048.aspx. Maybe to be consistent with the built-in MVC Html helpers, you could also have a .DisplayFor as well.

DmitryEfimenko commented 10 years ago

new helper: .DisplayFor() is available under .FormGroup()

mikestu commented 10 years ago

Thanks, Dmitry! I will try it out soon.

mikestu commented 10 years ago

I switched one view to use DisplayFor instead of DisplayTextFor, and got an exception. Let me know if I'm not using it correctly, or if you'd rather I open a new issue. Thanks!

Example: using (var form = Html.Bootstrap().Begin(new Form() .Type(FormType.Horizontal) .LabelWidthMd(3) )) { @form.FormGroup().DisplayFor(m => m.Phone) }

Exception was : f:\Development\FirthOfForth\Brightree\UI\Brightree.Web.UI.PatientPortal\Brightree.Web.PatientPortal\Views\Home\ContactUs.cshtml(19): error CS1061: 'TwitterBootstrapMVC.BootstrapMethods.BootstrapControlGroupBase' does not contain a definition for 'DisplayFor' and no extension method 'DisplayFor' accepting a first argument of type 'TwitterBootstrapMVC.BootstrapMethods.BootstrapControlGroupBase' could be found (are you missing a using directive or an assembly reference?)

Stack Trace: at System.Web.Compilation.AssemblyBuilder.Compile() at System.Web.Compilation.BuildProvidersCompiler.PerformBuild() at System.Web.Compilation.BuildManager.CompileWebFile(VirtualPath virtualPath) at System.Web.Compilation.BuildManager.GetVPathBuildResultInternal(VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate) at System.Web.Compilation.BuildManager.GetVPathBuildResultWithNoAssert(HttpContext context, VirtualPath virtualPath, Boolean noBuild, Boolean allowCrossApp, Boolean allowBuildInPrecompile, Boolean throwIfNotFound, Boolean ensureIsUpToDate) at System.Web.Compilation.BuildManager.GetVirtualPathObjectFactory(VirtualPath virtualPath, HttpContext context, Boolean allowCrossApp, Boolean throwIfNotFound) at System.Web.Mvc.BuildManagerWrapper.System.Web.Mvc.IBuildManager.FileExists(String virtualPath) at System.Web.Mvc.BuildManagerViewEngine.FileExists(ControllerContext controllerContext, String virtualPath) at Microsoft.Web.Mvc.FixedRazorViewEngine.Microsoft.Web.Mvc.IViewEngineProxy.FileExists(ControllerContext controllerContext, String virtualPath) at Microsoft.Web.Mvc.ViewEngineFixWorker1.<>c__DisplayClass4.<GetPathFromGeneralName>b__0(String path) at System.Web.WebPages.DefaultDisplayMode.GetDisplayInfo(HttpContextBase httpContext, String virtualPath, Func2 virtualPathExists) at System.Web.WebPages.DisplayModeProvider.<>cDisplayClassb.b8(IDisplayMode mode) at System.Linq.Enumerable.WhereSelectListIterator2.MoveNext() at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable1 source, Func2 predicate) at System.Web.WebPages.DisplayModeProvider.GetDisplayInfoForVirtualPath(String virtualPath, HttpContextBase httpContext, Func2 virtualPathExists, IDisplayMode currentDisplayMode, Boolean requireConsistentDisplayMode) at Microsoft.Web.Mvc.ViewEngineFixWorker1.GetPathFromGeneralName(ControllerContext controllerContext, List1 locations, String name, String controllerName, String areaName, String cacheKey, String[]& searchedLocations) at Microsoft.Web.Mvc.ViewEngineFixWorker1.GetPath(ControllerContext controllerContext, String[] locations, String[] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String[]& searchedLocations) at Microsoft.Web.Mvc.ViewEngineFixWorker1.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache) at Microsoft.Web.Mvc.FixedRazorViewEngine.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache) at Castle.Proxies.Invocations.IViewEngine_FindView.InvokeMethodOnTarget() at Castle.DynamicProxy.AbstractInvocation.Proceed() at Glimpse.Core.Extensibility.CastleInvocationToAlternateMethodContextAdapter.Proceed() at Glimpse.Core.Extensions.AlternateMethodContextExtensions.TryProceedWithTimer(IAlternateMethodContext context, TimerResult& timerResult) at Glimpse.Core.Extensibility.AlternateMethod.NewImplementation(IAlternateMethodContext context) at Glimpse.Core.Extensibility.AlternateTypeToCastleInterceptorAdapter.Intercept(IInvocation invocation) at Castle.DynamicProxy.AbstractInvocation.Proceed() at Castle.Proxies.IViewEngineProxy_1.FindView(ControllerContext controllerContext, String viewName, String masterName, Boolean useCache) at System.Web.Mvc.ViewEngineCollection.<>cDisplayClassc.bb(IViewEngine e) at System.Web.Mvc.ViewEngineCollection.Find(Func2 lookup, Boolean trackSearchedPaths) at System.Web.Mvc.ViewEngineCollection.FindView(ControllerContext controllerContext, String viewName, String masterName) at System.Web.Mvc.ViewResult.FindView(ControllerContext context) at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context) at System.Web.Mvc.ControllerActionInvoker.InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult) at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1a.<InvokeActionResultWithFilters>b__17() at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func1 continuation) at System.Web.Mvc.ControllerActionInvoker.<>cDisplayClass1a.<>cDisplayClass1c.b19() at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1 continuation) at System.Web.Mvc.ControllerActionInvoker.<>cDisplayClass1a.<>cDisplayClass1c.b19() at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func1 continuation) at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass1a.<>c__DisplayClass1c.<InvokeActionResultWithFilters>b__19() at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList1 filters, ActionResult actionResult) at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>cDisplayClass25.<>cDisplayClass2a.b20() at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>cDisplayClass25.b__22(IAsyncResult asyncResult)

DmitryEfimenko commented 10 years ago

It looks like you have an old dll... old nuget package. I noticed that I forgot to bump version of the project last time I published. Not sure if that would affect anything, but I updated package again. Try to get latest and see if it fixes the issue.

mikestu commented 10 years ago

The latest package does format from the annotation in my model now, as expected (thank you!). It doesn't line up though with the form label (it's higher). I may need to somehow get it wrapped in a 'p class="form-control-static"', but I don't know how I can do that with @form.FormGroup().DisplayFor(m => m.Phone). I'd use an MVC display template, but the "Phone" property type is just string. Maybe I could make my own class for phone, so I can target it with a display template, but I don't know if that's good or not. Do you have any recommendations?

mikestu commented 10 years ago

It looks like the MVC DisplayFor has overrides that let you specify a template name: http://msdn.microsoft.com/en-us/library/ee407420(v=vs.108).aspx

With that, I could tell it specifically which display template to render with. What do you think?

DmitryEfimenko commented 10 years ago

I'll update DisplayFor helper to automatically wrap contents into a div with class form-control-static this evening. It makes sense to do since it is always expected to render a static text.

Not sure if making a whole class for a phone would be feasible. Perhaps just using an int with a combination of a specific for a Phone template that would format that int into a phone-like format would do a better job.

I made sure that .FormGroup().DisplayFor() method has extension methods to set all properties of a regular @Html.DisplayFor() helper so you could write something like:

@f.FormGroup().DisplayFor(x => x.Phone).TemplateName("Phone")
DmitryEfimenko commented 10 years ago

All right, the output of DisplayFor now is being wrapped into <div class="form-control-static">

mikestu commented 10 years ago

The latest package works great for me. Thanks again!