.NET MVC 3 Razor Editorを使用したHTML5プレースホルダー


92

@ Html.EditorForを使用してHtml5プレースホルダーを書き込む方法はありますか、それともTextBoxFor拡張機能を使用するだけですか?

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

それとも、多分(に似DataAnnotationsを経由して「説明」の表示属性を使用することができます私たち自身のカスタム拡張書くために理にかなって、これを)?

もちろん、同じ質問が「オートフォーカス」にも当てはまります。

回答:


68

カスタムの作成については、次の記事をご覧くださいDataAnnotationsModelMetadataProvider

また、新しく導入されたIMetadataAwareインターフェイスを使用して、ASP.NET MVC 3に似た別の方法を次に示します。

このインターフェイスを実装するカスタム属性を作成することから始めます。

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>

IMetadataAwareインターフェイスの情報(および優れた例)に感謝します!
11

4
これはMVC3でも有効ですか?MVC3に新しい[Display(Prompt = "type Watermark here")]があることに気づきましたが、機能させることができませんでした。何か案が?
smnbss 2011年

2
@smnbss正解です。Prompt仕事をする方法を見るために私の答えを見てください。
Daniel Liuzzi

6
プレースホルダーを作成するのに、これだけの労力が必要ですか?S:単純なものである必要があります
krilovich

あります、以下の答えのいくつかを見てください。パックスは良いものを持っています。
Termato 2015

121

Darin Dimitrovの回答のsmnbssコメントはPrompt、まさにこの目的のために存在するため、カスタム属性を作成する必要はありません。ドキュメントから:

UIのプロンプトの透かしを設定するために使用される値を取得または設定します。

これを使用するには、ビューモデルのプロパティを次のように装飾するだけです。

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

その後、このテキストは便利にに配置されModelMetadata.Watermarkます。デフォルトでは、MVC 3のデフォルトテンプレートはWatermarkプロパティを無視しますが、それを機能させることは非常に簡単です。必要なのは、デフォルトの文字列テンプレートを調整して、MVCにレンダリング方法を指示することだけです。Darinと同じようにString.cshtmlを編集するだけです。ただし、から透かしを取得するのではなく、ModelMetadata.AdditionalValues直接取得します。ModelMetadata.Watermark

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

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

そして、それはそれです。

ご覧のとおり、すべてを機能させるための鍵はplaceholder = ViewData.ModelMetadata.Watermark少しです。

複数行のテキストボックス(textareas)にも透かしを有効にしたい場合は、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 })

6
@ブレット確かにあります。EditorFor()は、MVC 2で導入されたテンプレートヘルパーです。一見すると、TextBox()と同じように見えるかもしれませんが、HTMLの生成方法を正確に制御できるという大きな利点があります。私の答えは、Prompt属性をどうするかをMVCに「教える」というこの機能に基づいています。これらのテンプレートの詳細については、Brad Wilsonによるこの素晴らしい投稿を参照してください。bradwilson.typepad.com
Daniel Liuzzi

2
@DotNetWiseなぜそう言うのかよくわかりません。DisplayAttribute(プロンプトを含む)のすべての文字列パラメータはローカライズ可能です。アノテーションでResourceTypeを指定するだけです[Display(ResourceType = typeof(PeopleResources), Prompt = "AgePrompt")]。以上です。透かしテキストは、リソースPeopleResourcesのキーAgeGroupから取得されるようになりました
Daniel Liuzzi

1
.resxリソースではなくi18N .poローカリゼーションシステムを使用している場合はどうなりますか?
Adaptabi

3
@FrancisRodgers EditorTemplatesフォルダーはデフォルトではありません。Views\Sharedフォルダに作成するだけです(またはViews\{ControllerName}特定のコントローラに固有にする場合)。次に、このフォルダー内に.cshtmlテンプレートを配置します。これで問題ありません。
Daniel Liuzzi 2013

2
@RobertIvanc回答を編集し、ローリーバックナーが行った編集を元に戻しました。これにより、あなたとテッドが報告した問題が発生します。ありがとう。
Daniel Liuzzi

22

私は実際には、ほとんどの場合、プレースホルダーテキストに表示名を使用することを好みます。DisplayNameの使用例を次に示します。

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

1
透かしの特別なデータアノテーションプロンプトがあります。また、DisplayNameはフィールドラベル用です。それらを混ぜることは悪い考えです。適切なタスクに適切なものを使用します。私の答えを見てください。
Mike Eshva、2014年

1
おかげで、それが私が探していたもので、シンプルで、表示名を取得できるようになりました。それから、クラスを追加するのはなぜ
ですか

これはDisplayNameによって提供されたテキストをダブルエスケープします-フランスのようなアクセントのある言語の例としては良いソリューションではありません。
marapet

3

私はそのような単純なクラスを書きました:

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);
    }
}

そのような使用法:

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

そしてviewmodelのプロパティ:

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

プロンプトパラメータに注意してください。この場合、ローカライズにはリソースからの文字列を使用しますが、ResourceTypeパラメータを使用しないで、文字列のみを使用できます。


DisplayNameForメソッドを逆コンパイルし、透かしのアナログを作成しました。
Mike Eshva、2014年

こんにちは。Display-> Prompt値が指定されていない場合、DisplayName属性値を使用するようにメソッドMvcHtmlString WatermarkFor()を変更していただけますか?
ササタンセフ2015年

説明したとおりに使用できるように、WatermarkExtensionクラスをどこに保存しますか?Html.WatermarkFor(model => model.AddressSuffix)
Craig Gjerdingen 2015

3

私はこの方法でリソースファイルを使用します(もうプロンプトは必要ありません!)

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

1

以下は、TextBoxForと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));
    }
}

0

カスタムのEditorTemplateを作成することは良い解決策ではないと思います。なぜなら、さまざまなケース(文字列、数値、コンボボックスなど)で考えられる多くのテプレートを気にする必要があるからです。その他の解決策は、HtmlHelperのカスタム拡張です。

モデル:

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

HTMLヘルパー拡張:

   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);

}

対応するビュー:

@Html.BsEditorFor(x => x.Title)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.