IT story

.NET MVC 3 Razor 편집기를 사용하는 HTML5 자리 표시 자

hot-time 2020. 9. 2. 20:40
반응형

.NET MVC 3 Razor 편집기를 사용하는 HTML5 자리 표시 자


@ Html.EditorFor를 사용하여 Html5 자리 표시자를 작성하는 방법이 있습니까 , 아니면 TextBoxFor 확장을 사용해야합니까?

@Html.TextBoxFor(model => model.Title, new { @placeholder = "Enter title here"})

또는 DataAnnotations를 통해 'Description'표시 속성을 사용할 수있는 자체 사용자 지정 확장을 작성하는 것이 합리적 일까요 ( this 와 유사 )?

물론 동일한 질문이 '자동 초점'에도 적용됩니다.


사용자 정의 작성 에 대한 다음 기사살펴볼 수 있습니다 DataAnnotationsModelMetadataProvider.

그리고 새로 도입 된 IMetadataAware 인터페이스를 포함하여 진행하는 또 다른 ASP.NET MVC 3ish 방법이 있습니다.

이 인터페이스를 구현하는 사용자 정의 속성을 작성하여 시작하십시오.

public class PlaceHolderAttribute : Attribute, IMetadataAware
{
    private readonly string _placeholder;
    public PlaceHolderAttribute(string placeholder)
    {
        _placeholder = placeholder;
    }

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        metadata.AdditionalValues["placeholder"] = _placeholder;
    }
}

그런 다음 모델을 장식합니다.

public class MyViewModel
{
    [PlaceHolder("Enter title here")]
    public string Title { get; set; }
}

다음으로 컨트롤러를 정의합니다.

public class HomeController : Controller
{
    public ActionResult Index()
    {
        return View(new MyViewModel());
    }
}

해당보기 :

@model MyViewModel
@using (Html.BeginForm())
{
    @Html.EditorFor(x => x.Title)
    <input type="submit" value="OK" />
}

마지막으로 편집기 템플릿 ( ~/Views/Shared/EditorTemplates/string.cshtml) :

@{
    var placeholder = string.Empty;
    if (ViewData.ModelMetadata.AdditionalValues.ContainsKey("placeholder"))
    {
        placeholder = ViewData.ModelMetadata.AdditionalValues["placeholder"] as string;
    }
}
<span>
    @Html.Label(ViewData.ModelMetadata.PropertyName)
    @Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { placeholder = placeholder })
</span>

Darin Dimitrov의 답변에있는 smnbss 주석은 Prompt정확히이 목적을 위해 존재하므로 사용자 지정 속성을 만들 필요없습니다 . 문서에서 :

UI의 프롬프트에 대한 워터 마크를 설정하는 데 사용할 값을 가져 오거나 설정합니다.

그것을 사용하려면 다음과 같이 뷰 모델의 속성을 장식하십시오.

[Display(Prompt = "numbers only")]
public int Age { get; set; }

This text is then conveniently placed in ModelMetadata.Watermark. Out of the box, the default template in MVC 3 ignores the Watermark property, but making it work is really simple. All you need to do is tweaking the default string template, to tell MVC how to render it. Just edit String.cshtml, like Darin does, except that rather than getting the watermark from ModelMetadata.AdditionalValues, you get it straight from ModelMetadata.Watermark:

~/Views/Shared/EditorTemplates/String.cshtml:

@Html.TextBox("", ViewData.TemplateInfo.FormattedModelValue, new { @class = "text-box single-line", placeholder = ViewData.ModelMetadata.Watermark })

And that is it.

As you can see, the key to make everything work is the placeholder = ViewData.ModelMetadata.Watermark bit.

If you also want to enable watermarking for multi-line textboxes (textareas), you do the same for MultilineText.cshtml:

~/Views/Shared/EditorTemplates/MultilineText.cshtml:

@Html.TextArea("", ViewData.TemplateInfo.FormattedModelValue.ToString(), 0, 0, new { @class = "text-box multi-line", placeholder = ViewData.ModelMetadata.Watermark })

I actually prefer to use the display name for the placeholder text majority of the time. Here is an example of using the DisplayName:

  @Html.TextBoxFor(x => x.FirstName, true, null, new { @class = "form-control", placeholder = Html.DisplayNameFor(x => x.FirstName) })

I use this way with Resource file (don't need Prompt anymore !)

@Html.TextBoxFor(m => m.Name, new 
{
     @class = "form-control",
     placeholder = @Html.DisplayName(@Resource.PleaseTypeName),
     autofocus = "autofocus",
     required = "required"
})

I've wrote such a simple class:

public static class WatermarkExtension
{
    public static MvcHtmlString WatermarkFor<TModel, TValue>(this HtmlHelper<TModel> html, Expression<Func<TModel, TValue>> expression)
    {
        var watermark = ModelMetadata.FromLambdaExpression(expression, html.ViewData).Watermark;
        var htmlEncoded = HttpUtility.HtmlEncode(watermark);
        return new MvcHtmlString(htmlEncoded);
    }
}

The usage as such:

@Html.TextBoxFor(model => model.AddressSuffix, new {placeholder = Html.WatermarkFor(model => model.AddressSuffix)})

And property in a viewmodel:

[Display(ResourceType = typeof (Resources), Name = "AddressSuffixLabel", Prompt = "AddressSuffixPlaceholder")]
public string AddressSuffix
{
    get { return _album.AddressSuffix; }
    set { _album.AddressSuffix = value; }
}

Notice Prompt parameter. In this case I use strings from resources for localization but you can use just strings, just avoid ResourceType parameter.


Here is a solution I made using the above ideas that can be used for TextBoxFor and PasswordFor:

public static class HtmlHelperEx
{
    public static MvcHtmlString TextBoxWithPlaceholderFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        return htmlHelper.TextBoxFor(expression, htmlAttributes.AddAttribute("placeholder", metadata.Watermark));

    }

    public static MvcHtmlString PasswordWithPlaceholderFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
        return htmlHelper.PasswordFor(expression, htmlAttributes.AddAttribute("placeholder", metadata.Watermark));

    }
}

public static class HtmlAttributesHelper
{
    public static IDictionary<string, object> AddAttribute(this object htmlAttributes, string name, object value)
    {
        var dictionary = htmlAttributes == null ? new Dictionary<string, object>() : htmlAttributes.ToDictionary();
        if (!String.IsNullOrWhiteSpace(name) && value != null && !String.IsNullOrWhiteSpace(value.ToString()))
            dictionary.Add(name, value);
        return dictionary;
    }

    public static IDictionary<string, object> ToDictionary(this object obj)
    {
        return TypeDescriptor.GetProperties(obj)
            .Cast<PropertyDescriptor>()
            .ToDictionary(property => property.Name, property => property.GetValue(obj));
    }
}

I think create a custom EditorTemplate is not good solution, beause you need to care about many possible tepmlates for different cases: strings, numsers, comboboxes and so on. Other solution is custom extention to HtmlHelper.

Model:

public class MyViewModel
{
    [PlaceHolder("Enter title here")]
    public string Title { get; set; }
}

Html helper extension:

   public static MvcHtmlString BsEditorFor<TModel, TValue>(this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TValue>> expression, string htmlClass = "")
{
    var modelMetadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
    var metadata = modelMetadata;

    var viewData = new
    {
        HtmlAttributes = new
            {
                @class = htmlClass,
                placeholder = metadata.Watermark,
            }
    };
    return htmlHelper.EditorFor(expression, viewData);

}

A corresponding view:

@Html.BsEditorFor(x => x.Title)

참고URL : https://stackoverflow.com/questions/5824124/html5-placeholders-with-net-mvc-3-razor-editorfor-extension

반응형