Html5 ตัวยึดตำแหน่งกับ. NET MVC 3 Razor Editor


92

มีวิธีเขียนตัวยึดตำแหน่ง Html5โดยใช้ @ Html.EditorFor หรือไม่หรือฉันควรใช้นามสกุล TextBoxFor เช่น

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

หรือจะเป็นการดีที่จะเขียนส่วนขยายที่กำหนดเองของเราเองซึ่งอาจใช้แอตทริบิวต์การแสดง "คำอธิบาย" ผ่าน DataAnnotations (คล้าย ๆนี้ )

แน่นอนว่าคำถามเดียวกันนี้ก็ใช้กับ 'ออโต้โฟกัส' เช่นกัน

คำตอบ:


68

คุณอาจจะใช้เวลาดูที่บทความต่อไปนี้DataAnnotationsModelMetadataProviderสำหรับการเขียนแบบกำหนดเอง

และนี่คืออีกวิธีหนึ่งของ ASP.NET MVC 3ish ที่เกี่ยวข้องกับอินเทอร์เฟซIMetadataAware ที่เพิ่งเปิดตัว

เริ่มต้นด้วยการสร้างแอตทริบิวต์ที่กำหนดเองโดยใช้อินเทอร์เฟซนี้:

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!
แสวงหา

4
สิ่งนี้ยังใช้ได้กับ MVC3 หรือไม่ ฉันสังเกตเห็น [แสดง (Prompt = "พิมพ์ลายน้ำที่นี่")] ใหม่ใน MVC3 แต่ไม่สามารถใช้งานได้ มีความคิดอย่างไร
smnbss

2
@smnbss คุณถูกต้อง ดูคำตอบของฉันเพื่อดูวิธีการPromptทำงาน
Daniel Liuzzi

6
ว้าวงานมากในการทำตัวยึดหรือไม่? ต้องมีอะไรที่ง่ายกว่านี้: S
krilovich

มีให้ดูที่คำตอบบางส่วนที่ร้อง Pax มีดีอย่างหนึ่ง
Termato

121

เป็นความคิดเห็น smnbss ในคำตอบของดารินทร์ดิมิทรอฟของPromptที่มีอยู่สำหรับตรงจุดประสงค์นี้จึงมีความจำเป็นที่จะต้องสร้างแอตทริบิวต์ที่กำหนดเอง จากเอกสารประกอบ:

รับหรือกำหนดค่าที่จะใช้ในการตั้งค่าลายน้ำสำหรับพร้อมต์ใน UI

ในการใช้งานเพียงแค่ตกแต่งคุณสมบัติของโมเดลมุมมองของคุณดังนี้:

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

ModelMetadata.Watermarkข้อความนี้แล้ววางอยู่ในทำเลที่สะดวก เทมเพลตเริ่มต้นใน MVC 3 นอกกรอบจะไม่สนใจWatermarkคุณสมบัติ แต่การทำให้มันใช้งานได้ง่ายมาก สิ่งที่คุณต้องทำคือปรับแต่งเทมเพลตสตริงเริ่มต้นเพื่อบอก MVC ถึงวิธีการแสดงผล เพียงแก้ไข 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
@Brett มีแน่นอน EditorFor () เป็นตัวช่วยเทมเพลตที่นำมาใช้ใน MVC 2 เมื่อมองแวบแรกดูเหมือนว่าจะทำสิ่งเดียวกันกับ TextBox () แต่ให้ประโยชน์อย่างมากในการช่วยให้คุณสามารถควบคุมวิธีที่คุณต้องการสร้าง HTML ได้ คำตอบของฉันขึ้นอยู่กับคุณลักษณะนี้เพื่อ "สอน" MVC ว่าจะทำอย่างไรกับPromptแอตทริบิวต์ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเทมเพลตเหล่านี้คุณสามารถดูโพสต์ดีๆนี้โดย Brad Wilson: bradwilson.typepad.com/blog/2009/10/…
Daniel Liuzzi

2
@DotNetWise ฉันไม่แน่ใจว่าทำไมคุณถึงพูดแบบนั้น พารามิเตอร์สตริงทั้งหมดของDisplayAttribute(รวมถึงพรอมต์) สามารถแปลได้ คุณเพียงแค่ต้องระบุ resourceType [Display(ResourceType = typeof(PeopleResources), Prompt = "AgePrompt")]ในบันทึกย่อของคุณ: และนั่นแหล่ะ ลายน้ำในขณะนี้มาจากคีย์AgeGroupทรัพยากรPeopleResources
Daniel Liuzzi

1
จะเกิดอะไรขึ้นถ้าคุณไม่ได้ใช้ทรัพยากร. resx แต่เป็น i18N .po localization system?
Adaptabi

3
EditorTemplatesโฟลเดอร์@FrancisRodgers ไม่มีตามค่าเริ่มต้น คุณเพิ่งสร้างในViews\Sharedโฟลเดอร์ของคุณ(หรือViews\{ControllerName}ถ้าคุณต้องการให้เฉพาะกับคอนโทรลเลอร์บางตัว) จากนั้นคุณวางแม่แบบ. cshtml ไว้ในโฟลเดอร์นี้และคุณควรจะไป
Daniel Liuzzi

2
@RobertIvanc ฉันได้แก้ไขคำตอบและเปลี่ยนกลับการแก้ไขของ Raleigh Buckner ที่ทำให้เกิดปัญหาที่คุณและ Ted รายงาน ขอบคุณ.
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

1
ขอบคุณนั่นคือสิ่งที่ฉันกำลังมองหาเรียบง่ายและตรงประเด็นเมื่อเราได้ชื่อที่แสดงแล้วทำไมต้องเพิ่มชั้นเรียนอีก
saqibahmad

สิ่งนี้จะหนีข้อความที่แสดงโดย 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

สวัสดีคุณช่วยเปลี่ยนวิธี MvcHtmlString WatermarkFor () ให้ใช้ค่าแอตทริบิวต์ DisplayName ได้ไหมหากไม่ได้ระบุค่า Display -> Prompt
Sasa Tancev

คุณบันทึกคลาส WatermarkExtension ไว้ที่ไหนเพื่อให้สามารถใช้งานได้ตามที่อธิบายไว้ Html.WatermarkFor (model => model.AddressSuffix)
Craig Gjerdingen

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 แบบกำหนดเองไม่ใช่วิธีแก้ปัญหาที่ดีเนื่องจากคุณต้องดูแลเกี่ยวกับ tepmlates ที่เป็นไปได้มากมายสำหรับกรณีต่างๆ: สตริงตัวเลขคอมโบบ็อกซ์และอื่น ๆ โซลูชันอื่นคือส่วนขยายที่กำหนดเองสำหรับ 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.