mvc, razor, html helper

I am using MVC 3 with razor with the following codes.

 @Html.LabelFor(m => m.email, new { @class="control-label" })


 I just want to the razor codes above convert into below, and I got the following error:

 <label class="control-label" for="inputRegisterFirstName">Email</label>

 
alert

 Compiler Error Message: CS1928: 'System.Web.Mvc.HtmlHelper<SuretyNetwork.Controllers.SignUpModel>' does not contain a definition for 'LabelFor' and the best extension method overload 'System.Web.Mvc.Html.LabelExtensions.LabelFor<TModel,TValue>(System.Web.Mvc.HtmlHelper<TModel>, System.Linq.Expressions.Expression<System.Func<TModel,TValue>>, string)' has some invalid arguments

How to fix it?
solution1368Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

StephanLead Software EngineerCommented:
That is strange, it should work, I tried the following and get no errors:

@model string
@Html.LabelFor(x => x, new { @class = "option" })

Open in new window


Do you have the following lines in your web.config inside the "views" folder?

<add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />

Open in new window

0
solution1368Author Commented:
What mvc ver you use?
0
StephanLead Software EngineerCommented:
I am using mvc4, but it should be for version 3 and 4 thesame
0
Exploring SQL Server 2016: Fundamentals

Learn the fundamentals of Microsoft SQL Server, a relational database management system that stores and retrieves data when requested by other software applications.

solution1368Author Commented:
i use mvc 3 but it is not working yes. it is there under view folder
0
StephanLead Software EngineerCommented:
Sorry for my late response..

I did some research and the overload you want to use does not exist in MVC 3.
You can create your own extension to support this behaviour.

Here is the code you need:

public static class LabelExtensions
{
    public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
    {
        return LabelFor(html, expression, new RouteValueDictionary(htmlAttributes));
    }
    public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
    {
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
        string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
        string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
        if (String.IsNullOrEmpty(labelText))
        {
            return MvcHtmlString.Empty;
        }

        TagBuilder tag = new TagBuilder("label");
        tag.MergeAttributes(htmlAttributes);
        tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));

        TagBuilder span = new TagBuilder("span");
        span.SetInnerText(labelText);

        // assign <span> to <label> inner html
        tag.InnerHtml = span.ToString(TagRenderMode.Normal);

        return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
    }
}

Open in new window

0
solution1368Author Commented:
thank. where the codes should be located? if i want all the cshtml be able use it.
0
StephanLead Software EngineerCommented:
It does not matter. Just make sure you have set the namespace in the web.config inside the views folder
0
solution1368Author Commented:
show me in codes. I tried it and no working.
0
StephanLead Software EngineerCommented:
Add this class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Routing;

namespace MvcApplication1.Helpers
{
    public static class LabelExtensions
    {
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
        {
            return LabelFor(html, expression, new RouteValueDictionary(htmlAttributes));
        }
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText))
            {
                return MvcHtmlString.Empty;
            }

            TagBuilder tag = new TagBuilder("label");
            tag.MergeAttributes(htmlAttributes);
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));

            TagBuilder span = new TagBuilder("span");
            span.SetInnerText(labelText);

            // assign <span> to <label> inner html
            tag.InnerHtml = span.ToString(TagRenderMode.Normal);

            return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
        }
    }
}

Open in new window


And place the following line in your web.config file within the views folder.

<add namespace="MvcApplication1.Helpers"/>

Open in new window


Then if you have the view already opened it, close it. and then open it agian to reload the intellisense.

Now you should be able to do the following (example on a empty view):
@model string
@Html.LabelFor(x => x, new { @class = "control-label" } )

Open in new window

0
solution1368Author Commented:
great working.
one more question.

If I want <span class="form-required" title="This field is required.">*</span> INSIDE
of the label like below. What should I do?

 <label class="control-label" for="inputIndemnitorSSN">
                            SSN
                            <span class="form-required" title="This field is required.">*</span>
                        </label>
0
StephanLead Software EngineerCommented:
You can do this in 2 ways, using the metadata from the property or create a custom method.

This is a way to do the metadata:

public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText))
            {
                return MvcHtmlString.Empty;
            }

            TagBuilder tag = new TagBuilder("label");
            tag.MergeAttributes(htmlAttributes);
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            tag.SetInnerText(labelText);

            if (metadata.IsRequired)
            {
                TagBuilder required = new TagBuilder("span");
                required.Attributes.Add("class", "form-required");
                required.Attributes.Add("title", "This field is required.");
                required.InnerHtml = "*";
                tag.InnerHtml += required.ToString(TagRenderMode.Normal);
            }

            return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
        }

Open in new window


And I think you can manage yourself how to overload this with a custom method.
0
solution1368Author Commented:
I still don't get it. Should I just copy and paste your new codes to achieve both requests I have? Actually, I did copy and paste and replace the codes and it is not working.
0
StephanLead Software EngineerCommented:
The class I gave you at first  (comment #a39551448) can be updated to:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Routing;

namespace MvcApplication1.Helpers
{
    public static class LabelExtensions
    {
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, object htmlAttributes)
        {
            return LabelFor(html, expression, new RouteValueDictionary(htmlAttributes));
        }
        public static MvcHtmlString LabelFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression, IDictionary<string, object> htmlAttributes)
        {
            ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, html.ViewData);
            string htmlFieldName = ExpressionHelper.GetExpressionText(expression);
            string labelText = metadata.DisplayName ?? metadata.PropertyName ?? htmlFieldName.Split('.').Last();
            if (String.IsNullOrEmpty(labelText))
            {
                return MvcHtmlString.Empty;
            }

            TagBuilder tag = new TagBuilder("label");
            tag.MergeAttributes(htmlAttributes);
            tag.Attributes.Add("for", html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(htmlFieldName));
            tag.SetInnerText(labelText);

            if (metadata.IsRequired)
            {
                TagBuilder required = new TagBuilder("span");
                required.Attributes.Add("class", "form-required");
                required.Attributes.Add("title", "This field is required.");
                required.InnerHtml = "*";
                tag.InnerHtml += required.ToString(TagRenderMode.Normal);
            }

            return MvcHtmlString.Create(tag.ToString(TagRenderMode.Normal));
        }
    }
}

Open in new window


Then, if you set RequiredAttribute to the property (e.g. email)

[Required]
public string Email { get; set; }

Open in new window


It should show because I tested it myself.
0
solution1368Author Commented:
First of all, thank you for your time to help me. But I think I should get you more information what I really need to do.

<label class="control-label" for="inputIndemnitorSSN">
                            SSN
                            <span class="form-required" title="This field is required.">*</span>
                        </label>

The goal is to add <span></span> inside of the label. And since not all of the <label> will contain <span></span>. So I assume something like the following will work to me.

@Html.LabelFor(x => x, new { @class = "control-label" } , AddSpan) for example if I want add.
@Html.LabelFor(x => x, new { @class = "control-label" } ) for example If I don't want to add.

The codes may be wrong, but I just try to explain what I need to do. Is it a way to modify in the labelExtensions Class?

Again, thank you for your helps. I am very new to MVC especially to the custom extensions side.
0
solution1368Author Commented:
No worry about what I posted. I finally get it okay but now have another issue.
I actually have separate class library. and I add labelExtensions there and
then go back to MVC website to add reference. Then, I added namespace into the web.config

Now it alerts the class is not namespace type. :-(
0
StephanLead Software EngineerCommented:
Not sure what is going on here.

So in steps you did the following:
- Moved the labelextensions class to a different class library (e.g. MyCompany.Extensions)
  - So the namespace is MyCompany.Extensions
- Referenced the class library to the web project (MyCompany.Web
- Added the namespace of the labelextensions class in the /Views/web.config file.

Did I miss something?
0
solution1368Author Commented:
your procedure list looks right to what I tried to do.
But it is still not working after I done all the steps
0
solution1368Author Commented:
And now it creates one more issue.

when it is validated, and show 'required' it end up create a new line. even i tried to add float:left in css. It does not resolve the issue.
0
StephanLead Software EngineerCommented:
Ok, what is the status now?

Now it alerts the class is not namespace type. :-(
Is this fixed?

when it is validated, and show 'required' it end up create a new line. even i tried to add float:left in css. It does not resolve the issue.
What else did you place (in this question) besides the label?
0
solution1368Author Commented:
Both items are still not fixed for your status.
Now I just put the label extensions cs back to the mvc project and it works and I take out the required in the model

But both must be fixed thank
0
StephanLead Software EngineerCommented:
Ok, lets just focus on the extension part because that is part of the overall question.

You have a different class library where you would like to add the extension class.
You move the extension class to the class library.
Change the namespace so it will match the class library
Change the namespace in the /views/web.config to get intellisense
Validate if the class library is referenced to the MVC project, if it's not, do this.
Open your view (if already opened, close and reopen to refresh intellisense).
Done.

If you have issues on building the project of the class library. You need the System.Web.Mvc and System.Web referenced to your class library.

If it is still not working, please attach a screenshot where it is going wrong.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
ASP.NET

From novice to tech pro — start learning today.