占位符文字可编辑

时间:2016-05-04 03:57:00

标签: html twitter-bootstrap internet-explorer-11 placeholder

我的表格表现得很奇怪。我们系统中的其他形式表现得很好,但我在IE11中做了一些巧妙的事情。这似乎是因为有些组件不能很好地同居。

我的问题是:如何阻止它做这些奇怪的事情,为什么会发生这些奇怪的事情呢?

我的表单会在<table>中显示房产销售列表。每笔销售都有自己的<tbody>,其中包含<tr>display: none个。其中一个单元格包含一个文件输入,其中包含一个工具提示(来自Bootstrap)。我必须在首次显示表单时隐藏部分销售,我使用.hide()或JQuery <tr>执行此操作。该表单还使用占位符和一些“强制输入装饰”(根据here的代码自动在强制输入旁边添加星号。

通过消除过程,我发现了两件可以阻止奇怪事情发生的事情:不隐藏包含文件输入的任何nicefileinput,而不使用任何强制输入装饰。不幸的是,我需要做这两件事。

奇怪的事情

  1. 初始插入符号:在最初聚焦的文本框(地址字段,已预先填充)中,插入符号有时会出现在文本的开头,有时会出现在结尾处
  2. 可编辑占位符:见下文
  3. 标题标题:浏览器标签文字停留在“等待...”
  4. 奇怪行为的奇怪模式:见下文
  5. 可编辑占位符

    当我单击带有占位符的文本框时,正常行为是插入符号出现在文本框的左侧,(在Chrome中)占位符文本仍然可以在插入符右侧看到,或者(在IE11中)占位符文字消失了。但是当我的页面在IE11中表现得很奇怪时,插入符号出现在占位符之后:

    comment box with caret after placeholder

    ......并且可编辑......

    comment box with modified placeholder

    提交表单时,任何更新的占位符内容都不会随之提交,因此我的用户可能会输入他们认为会保存的文本,但不是。

    占位符的怪异也很微妙:它只发生在页面上的第一次鼠标点击;事情表现正常,后续点击或字段之间的键盘标签。

    怪异行为的奇怪模式

    根据页面显示之前发生的事情,事情会有所不同。

    在第一个显示屏上,占位符是可编辑的。如果我点击一个占位符(即让插入符号出现在占位符文本中或之后的某个位置),刷新后的页面行为与我没有点击占位符的行为不同。

    如果我首先使用占位符单击其中一个文本框并且占位符是可编辑的,则在F5之后,最初聚焦的文本框将在开始时具有插入符号。或者,如果最初聚焦的文本框在开始时已经插入符号,并且我没有对表单执行任何操作,则插入符号在F5之后再次启动。如果最初聚焦的文本框最后有插入符号,那么我可以编辑注释字段的占位符文本...这有点令人困惑。

    我尝试了什么

    我们通常使用this使占位符在旧版浏览器中运行。我试过删除它,但没有区别。

    我尝试了this script,但它只是使问题略有不同:插入符号移动到占位符的开头,但它仍然可以编辑。

    我已尝试删除@model OurCompany.Web.ViewModels.OurProductCompleteDesktopSalesComparisonViewModel @{ ViewBag.Title = "CompleteDesktopSalesComparison"; Layout = "~/Views/Shared/_Layout.cshtml"; } <link rel="stylesheet" href="~/content/css/typeahead.js-bootstrap.css"> <script type="text/javascript" src="~/Content/Scripts/DICurrencyInputFormatter.js"></script> <section class="container-wrap"> <div class="container"> @Html.Partial("~/Views/OurProduct/_CompleteHeaderPartial.cshtml") @using (Html.BeginForm("CompleteDesktopSalesComparison", "OurProduct", FormMethod.Post, new { enctype = "multipart/form-data" })) { @Html.ValidationSummary(false) @Html.AntiForgeryToken() @Html.HiddenFor(m => m.Valuation.OrderNumber) @Html.HiddenFor(m => m.Property.DIPID) @Html.HiddenFor(m => m.Property.FullAddress) @Html.HiddenFor(m => m.Valuation.CategoryCode) @Html.HiddenFor(m => m.Valuation.ValuationTypeCode) @Html.Partial("~/Views/OurProduct/_CompleteNavigationTabsPartial.cshtml") <div class="col-md-10 col-md-offset-1"> <div class="row">&nbsp;</div> <div> @*Sales comparisons==============================================================================*@ @Html.Hidden("saleCount", Model.ComparableSales.Count) <table class="table table-default"> @foreach (var sale in Model.ComparableSales) { var saleIndex = Model.ComparableSales.IndexOf(sale); var isVisible = sale.Visible; var shadedClass = saleIndex % 2 == 0 ? string.Empty : "shaded-rows"; var visibleStyle = isVisible ? string.Empty : "display: none;"; var saleTbodyId = string.Format("saleTbody{0}", saleIndex); var selectedId = string.Format("selected{0}", saleIndex); var visibleId = string.Format("visible{0}", saleIndex); <tbody id="@saleTbodyId" class="@shadedClass" style="@visibleStyle"> @*Address, selected*@ <tr> <td> @Html.HiddenFor(m => m.ComparableSales[saleIndex].Sequence) @Html.HiddenFor(m => m.ComparableSales[saleIndex].Visible, new{ id = visibleId}) Address </td> <td colspan="3"> @Html.TextBoxFor(m => m.ComparableSales[saleIndex].FullAddress, new {@class = "form-control tt-query", style = "width: 100%;", placeholder = "Full address of sale"}) @Html.ValidationMessageFor(m => m.ComparableSales[saleIndex].FullAddress) @Html.HiddenFor(m => m.ComparableSales[saleIndex].Dipid) <script> $("#Valuation_ComparableSales_@(saleIndex)__FullAddress").on("typeahead:selected typeahead:autocompleted", function(e, datum) { $("#Valuation_ComparableSales_@(saleIndex)__Dipid").val(datum.SearchKey); }) </script> </td> <td>@Html.DisplayNameFor(m => m.ComparableSales[saleIndex].Selected)</td> <td> @Html.CheckBoxFor(m => m.ComparableSales[saleIndex].Selected, new { id = selectedId }) </td> </tr> @*Date, Price*@ <tr> <td>@Html.DisplayNameFor(m => m.ComparableSales[saleIndex].Date)</td> <td> <span class="di-mandatory-field-container di-mandatory-field-text" style="position: relative;"> @Html.DropDownListFor(m => m.ComparableSales[saleIndex].Date, Model.GetSalesDateListInstance(Model.ComparableSales[saleIndex].Date), new { @class = "form-control" }) </span> </td> <td>@Html.DisplayNameFor(m => m.ComparableSales[saleIndex].PriceString)</td> <td> @Html.TextBoxFor(m => m.ComparableSales[saleIndex].PriceString, new { @class = "form-control currency-0-decimals", placeholder = "Sale price" }) @Html.ValidationMessageFor(m => m.ComparableSales[saleIndex].PriceString) @Html.ValidationMessageFor(m => m.ComparableSales[saleIndex].Price) </td> <td></td> <td></td> </tr> @*Floor Area, Bedrooms*@ <tr> <td>@Html.DisplayNameFor(m => m.ComparableSales[saleIndex].FloorArea)</td> <td> @Html.TextBoxFor(m => m.ComparableSales[saleIndex].FloorArea, new { @class = "form-control", placeholder = "Floor Area" }) @Html.ValidationMessageFor(m => m.ComparableSales[saleIndex].FloorArea) </td> <td>@Html.DisplayNameFor(m => m.ComparableSales[saleIndex].Bedrooms)</td> <td> @Html.TextBoxFor(m => m.ComparableSales[saleIndex].Bedrooms, new { @class = "form-control", placeholder = "Bedrooms" }) @Html.ValidationMessageFor(m => m.ComparableSales[saleIndex].Bedrooms) </td> <td></td> <td></td> </tr> @*Land Area, Bathrooms*@ <tr> <td>@Html.DisplayNameFor(m => m.ComparableSales[saleIndex].LandArea)</td> <td> @Html.TextBoxFor(m => m.ComparableSales[saleIndex].LandArea, new { @class = "form-control", placeholder = "Land Area" }) @Html.ValidationMessageFor(m => m.ComparableSales[saleIndex].LandArea) </td> <td>@Html.DisplayNameFor(m => m.ComparableSales[saleIndex].Bathrooms)</td> <td> @Html.TextBoxFor(m => m.ComparableSales[saleIndex].Bathrooms, new { @class = "form-control", placeholder = "Bathrooms" }) @Html.ValidationMessageFor(m => m.ComparableSales[saleIndex].Bathrooms) </td> <td></td> <td></td> </tr> @*Comment*@ <tr> <td>@Html.DisplayNameFor(m => m.ComparableSales[saleIndex].Comment)</td> <td colspan="5"> @Html.TextBoxFor(m => m.ComparableSales[saleIndex].Comment, new { @class = "form-control", placeholder = "Comments" }) @Html.ValidationMessageFor(m => m.ComparableSales[saleIndex].Comment) </td> </tr> @*Image*@ <tr> <td> <p>Image</p> <p>(@Html.DisplayFor(m => m.FileExtensionConstraintMessages["VALUATION_REPORT_SALE_IMAGE"]))</p> </td> <td colspan="5"> @if (Model.ComparableSales[saleIndex].Images != null) { foreach (var file in Model.ComparableSales[saleIndex].Images) { <span>@Html.DisplayFor(f => file.FileName) (Created: @Html.DisplayFor(f => file.CreateDate))</span> <a href="@Url.Action("PropertyFile", "Files", new { orderNumber = Model.Valuation.OrderNumber, fileTypeCode = file.FileTypeCode, userFileId = file.Id })"><i class="fa fa-file fa-lg"></i></a> <br/> } } <span data-toggle="tooltip" data-placement="top" title="@Html.DisplayFor(m => m.FileUploadConstraintMessages["VALUATION_REPORT_SALE_IMAGE"])"> <input type="file" name="sale@(saleIndex)Image"/> </span> @{ var validationMessageKey = String.Format("SaleComparisonImage{0}", saleIndex); } @Html.ValidationMessage(validationMessageKey) </td> </tr> @*Comparability*@ <tr> <td>@Html.DisplayNameFor(m => m.ComparableSales[saleIndex].Comparability)</td> <td colspan="5"> @Html.TextBoxFor(m => m.ComparableSales[saleIndex].Comparability, new { @class = "form-control", placeholder = "Comparability - e.g. Inferior, Comparable, Superior" }) @Html.ValidationMessageFor(m => m.ComparableSales[saleIndex].Comparability) </td> </tr> </tbody> } </table> </div> <div><input id="addSaleButton" type="button" value="Add a sale" class="btn btn-light" /></div> </div> @Html.Partial("~/Views/OurProduct/_CompleteNavigationButtonsPartial.cshtml") } <div class="row">&nbsp;</div> </div> <div class="push"></div> </section> <script src="~/Content/scripts/moment.js"></script> <script src="~/Content/scripts/bootstrap.min.js"></script> <script src="~/content/scripts/jquery.nicefileinput.min.js"></script> <script src="~/content/scripts/jquery.placeholder.js"></script> <script src="~/content/scripts/typeahead.js"></script> <script> $("#addSaleButton").click(function() { var saleCount = $("#saleCount").val(); for (var i = 0; i < saleCount; i++) { var saleTbodyId = "saleTbody" + i; if ($("#" + saleTbodyId + ":hidden").length > 0) { // make the sale visible $("#" + saleTbodyId).show(); // check the Selected checkbox var selectedId = "selected" + i; $("#" + selectedId).prop("checked", true); // set the hidden value to ensure it shows after validation errors var visibleId = "visible" + i; $("#" + visibleId).val("True"); // done one, don't do any more break; } } }); $(".tt-query").typeahead({ name: 'SearchValue', valueKey: 'SearchValue', limit: 20, remote: { url: '/properties/GetAddressSearchValues?partSearchValue=%QUERY' } }); $(document).ready(function() { // tooltips $("span").tooltip({ placement: 'top' }); // custom styling for file input $("input[type=file]").nicefileinput(); // placeholder attribute for old browsers $('input, textarea').placeholder(); $("#ComparableSales_0__FullAddress").focus(); }); </script> ,但这没有任何区别。

    这是我的整个表格。 “评论”字段显示在表单的一半左右

    // Add a CSS class to mandatory text input fields.
    
    // see http://www.robertgray.net.au/posts/2012/11/indicating-required-fields-with-twitter-bootstrap-and-aspnet-mvc-4#.VMqY0miUfeo
    function markRequired() {
        // look at every mandatory field
        $('input[data-val-required]').each(function () {
    
            // not all should be treated
            if (!$(this).parent().hasClass("input-append") && !(this).hasAttribute("readonly")) {
                if ($(this).is("input:text")) {
                    $(this).wrap("<div class='di-mandatory-field-container di-mandatory-field-text'>");
    
                    //$(this).wrap("<div class='input-group'>");
                    //$(this).after("<span class='input-group-addon'><i class='fa fa-asterisk required-asterisk'></i></span>");
                    //$(this).addClass("di-mandatory-field-container");
                    //$(this).addClass("di-mandatory-field-text");
                    //$(this).wrap("<span>");
                }
            }
        });
    }
    
    function addFootnote() {
        var parentForm;
    
        // check the form for mandatory class (may be manually- or automatically-added)
        var firstMandatory = $('.di-mandatory-field-container').first();
    
        // find the form containing that element
        if (firstMandatory != null) {
            var parentFinder = firstMandatory[0];
            while (parentForm == null && parentFinder != null) {
                if (parentFinder.tagName.toLowerCase() == "form") {
                    parentForm = parentFinder;
                }
                parentFinder = parentFinder.parentNode;
            }
        }
    
        // add the footnote
        if (parentForm != null) {
            var rubric = $('<span>', { text: "denotes a mandatory field", style: "position: absolute;" })
                .addClass("di-mandatory-field-footnote");
            rubric.appendTo($(parentForm).parent());
        }
    }
    
    $(document).ready(function () {
        markRequired();
        addFootnote();
    });
    

    这是强制输入装饰.js文件

    {{1}}

1 个答案:

答案 0 :(得分:1)

这只是答案的一半(仍然不知道为什么会发生奇怪的事情),但有人可能会觉得这有帮助......

$(document).ready(function() {
    $("#ComparableSales_0__FullAddress").focus();
    $("#selected0").focus();
});

由于虫子所说的“微妙”性质,只需聚焦两次就可以杀死它。