Closed ipostanogov closed 11 years ago
I believe the functionality you are looking for is achieved through extension method .Label()
:
@(Html.Bootstrap().ControlGroup().DropDownListFor(m => m.barId, ViewBag.barId as IEnumerable<SelectListItem>)
.Label().LabelText(Model.Bar.name).ShowRequiredStar(true))
Let me know if this works out for you.
'Model.Bar.name' returns field's value of the sent object, not the 'LabelFor'.
Now I have
<div class="control-group">
@Html.LabelForRequired(m => m.Bar.name)
<div class="controls">
@Html.DropDownList("barId", String.Empty)
</div>
</div>
with LabelForRequired helper, but for me it seems костыль :)
Right... now I see what you are trying to do. Though I can't think of a prod case where such functionality would be needed. Just out of curiosity, what classes Foo and Bar actually are? I want to understand why you can't slap [Display(Name = "BarDispName")]
on public int id;
of the Foo
class.
Also keep in mind that in your case rendered label will not be linked to the dropdown because it will have incorrect for
attribute.
E.g. Foo is item, Bar is maker. Every item has maker, every maker has name.
While adding item, the maker should be selected from list of existing makers.
DropDownListFor(m => m.barId, ViewBag.barId as IEnumerable<SelectListItem>)
almost suites me, except that the label is bad. Yes, I know that I could do
[Display(Name = "Maker")]
public int barId { get; set; }
but it violates DRY principle, because
[Display(Name = "Maker")]
public string name { get; set; }
attribute is already presented in Bar class.
And what if I would need to display other field in other view, e.g. maker's address. What should be the barId's DisplayName?
Thanks for telling about label.for. For now it doesn't matter but I haven't noticed it.
Well, you can always use a CustomControls of ControlGroup:
@(Html.Bootstrap().ControlGroup()
.CustomControls(Html.Bootstrap().DropDownListFor(m => m.barId, ViewBag.barId as IEnumerable<SelectListItem>))
.LabelFor((m => m.Bar.name)))
.LabelFor
will try to determine whether to slap a required star on label or not, but you can always override what it should be with extension method .ShowRequiredStar()
Let me know if this works for you!
It seems almost OK, except that it doesn't select corresponding value of the Model.Bar.name in CustomControl. What is the easiest way to auto set it?
There is an extension method .SelectedValue()
on drop DropDownList
.
Selected value - first, but not model's in the
@(Html.Bootstrap().ControlGroup().CustomControls(Html.Bootstrap().DropDownListFor(m => m.makerId, ViewBag.makerId as IEnumerable<SelectListItem>).SelectedValue(Model.Maker.name)).LabelFor((m => m.Maker.name)))
which is the same as in
@(Html.Bootstrap().ControlGroup().CustomControls(Html.Bootstrap().DropDownListFor(m => m.makerId, ViewBag.makerId as IEnumerable<SelectListItem>).SelectedValue(Model.makerId)).LabelFor((m => m.Maker.name)))
Now I use this obvious workaround
public static class MySelectExtensions
{
public static MvcHtmlString DropDownListBootstrap<TModel, TValue>(this HtmlHelper<TModel> htmlHelper,Expression<Func<TModel, TValue>> expression, string name, string optionLabel = "")
{
var contGroup = new TagBuilder("div");
contGroup.AddCssClass("control-group");
var controls = new TagBuilder("div");
controls.AddCssClass("controls");
controls.InnerHtml = htmlHelper.DropDownList(name, optionLabel).ToString();
contGroup.InnerHtml = htmlHelper.LabelForRequired(expression) + controls.ToString();
return MvcHtmlString.Create(contGroup.ToString());
}
}
with this sample usage
@Html.DropDownListBootstrap(m => m.Maker.name, "makerId")
Not very elegant and absolutely ignores your framework, but it works. Still don't know your alternative.
Any ideas about making normal label.for attribute? Or it should be constructed directly?
I still do not quite understand the whole thing that you are trying to do. The whole thing feels to be a bit wrong if you need to write so much customization. Though I don't care that much :)
The verdict is that if you can construct this with the use of regular html helpers, you should be able to achieve the same with BMVC's custom control.
Based on the code you showed me I tried to reproduce the same logic with BMVC, but found that BMVC .DropDownList method does not have overload that you need. The one that does not require List<SelectListItem>
and takes optionLabel
. This is a bug and it will be fixed in upcoming release (which should happen today or tomorrow).
When it's fixed you would be able to achieve the same by writing this:
@(Html.Bootstrap().ControlGroup()
.CustomControls(Html.Bootstrap().DropDownList("makerId", ""))
.LabelFor(m => m.Maker.name))
As for the label's for
attribute, you can use htmlAttributes to set it:
// BMVC:
.LabelFor(m => m.Maker.name).HtmlAttributes(new { @For = "makerId" })
// Regular helper:
@Html.LabelFor(m => m.Maker.name, new { @For = "makerId" })
Important: Notice uppercase "F" in the "For". It is needed to override default "for" value.
I have some classes
The closes thing I need is
The problem is that generated label is 'bar Id*', but I want it to be the same as
plus '*' if needed.
So I suggest to add an overload to DropDownListFor with two expressions:
[ ] For 'Required' rules (adding *) and for attributes like
If there is a way to do it now, I would be glad to know about it.