2

我有一个页面,其中包含使用 jquery-validate 插件验证的字段,并希望在字段上包含一个类似 twitter 的字符计数器,以查看剩余的字符数

这是我的演示 http://jsfiddle.net/4k1vokgv/1/

$(document).ready(function() {
    $(".counter").characterCounter({
    counterCssClass: 'text-counter',
    limit: 1000,
    counterFormat: 'Characters Remaining: %1',
    });

    var validatorStrat = $("#strategyForm").validate({
      rules:{
        exampleInputEmail1: {
          required: true,
          },
        ZB_note: {
          required: true,
          maxlength: 140,
        },
        ZC_note: {
          required: true,
          maxlength: 140,
        },

      },
      submitHandler: function(form) {}
    });
});

两个字符计数器都可以正常工作,直到出现问题,当 jquery-validate 触发验证错误(必需、最大长度等)时,字符计数器然后停止对任何有错误的元素工作。

我不认为这是字符计数器插件本身的问题。我认为 jquery 验证的错误生成确实会导致这种情况。

无论如何,包括下面的完整片段,非常感谢任何帮助

/**
* Character Counter v1.0
* ======================
*
* Character Counter is a simple, Twitter style character counter.
*
* https://github.com/dtisgodsson/jquery-character-counter
*
* @author Darren Taylor
* @author Email: shout@darrenonthe.net
* @author Twitter: darrentaytay
* @author Website: http://darrenonthe.net
*
*/
(function($) {

    $.fn.characterCounter = function(options){

        var defaults = {
            exceeded: false,
            limit: 150,
            counterWrapper: 'span',
            counterCssClass: 'help-block',
            counterFormat: '%1',
            counterExceededCssClass: 'exceeded',
            onExceed: function(count) {},
            onDeceed: function(count) {},
            customFields: {},
        };

        var options = $.extend(defaults, options);

        return this.each(function() {
            $(this).after(generateCounter());
            bindEvents(this);
            checkCount(this);
        });

        function customFields(params)
        {
            var html='';

            for (var i in params)
            {
                html += ' ' + i + '="' + params[i] + '"';
            }

            return html;
        }

        function generateCounter()
        {
            var classString = options.counterCssClass;

            if(options.customFields.class)
            {
                classString += " " + options.customFields.class;
                delete options.customFields['class'];
            }

            return '<'+ options.counterWrapper +customFields(options.customFields)+' class="' + classString + '"></'+ options.counterWrapper +'>';
        }

        function renderText(count)
        {
            return options.counterFormat.replace(/%1/, count);
        }

        function checkCount(element)
        {
            var characterCount  = $(element).val().length;
            var remaining        = options.limit - characterCount;

            if( remaining < 0 )
            {
                $(element).next("." + options.counterCssClass).addClass(options.counterExceededCssClass);
                options.exceeded = true;
                options.onExceed(characterCount);
            }
            else
            {
                if(options.exceeded) {
                    $(element).next("." + options.counterCssClass).removeClass(options.counterExceededCssClass);
                    options.onDeceed(characterCount);
                    options.exceeded = false;
                }
            }

            $(element).next("." + options.counterCssClass).html(renderText(remaining));
        };    

        function bindEvents(element)
        {
            $(element)
                .bind("keyup", function () {
                    checkCount(element);
                })
                .bind("paste", function () {
                    var self = this;
                    setTimeout(function () { checkCount(self); }, 0);
                });
        }
    };

})(jQuery);

$.validator.setDefaults({
    errorElement: "span",
    errorClass: "help-block",
//	validClass: 'stay',
    highlight: function (element, errorClass, validClass) {
    $(element).addClass(errorClass); //.removeClass(errorClass);
        $(element).closest('.form-group').removeClass('has-success').addClass('has-error');
    },
    unhighlight: function (element, errorClass, validClass) {
    $(element).removeClass(errorClass); //.addClass(validClass);
        $(element).closest('.form-group').removeClass('has-error').addClass('has-success');
    },

    errorPlacement: function(error, element) {
        if(element.parent('.input-group').length) {
           error.insertAfter(element.parent());
         } else if (element.hasClass('select2')) {
           error.insertAfter(element.next('span'));
        } else {
            error.insertAfter(element);
        }

    }
});

$(document).ready(function() {
    $(".counter").characterCounter({
    counterCssClass: 'text-counter',
    limit: 140,
    counterFormat: 'Characters Remaining: %1',
    });
  
    var validatorStrat = $("#strategyForm").validate({
      rules:{
        exampleInputEmail1: {
          required: true,
          },
        ZB_note: {
          required: true,
          maxlength: 1000,
        },
        ZC_note: {
          required: true,
          maxlength: 1000,
        },

      },
      submitHandler: function(form) {}
    });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet"/>
<script src="http://cdn.jsdelivr.net/jquery.validation/1.14.0/jquery.validate.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css" rel="stylesheet"/>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" rel="stylesheet"/>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>

<form role="form" id="strategyForm">
 <div class="form-group">
   <label for="exampleInputEmail1" class="control-label">Email address</label>
     <input type="email" class="form-control" name="exampleInputEmail1" placeholder="Enter email" />
 </div>
 <div class="form-group">
            <label class="control-label">What amount is to be solicited and when?</label>
            <textarea class="form-control counter" rows="1" id="ZB_note" name="ZB_note" ></textarea>
          </div>


          <div class="form-group">
            <label class="control-label">Who will be involved in the soliciation?</label>
            <textarea class="form-control counter" rows="1" id="ZC_note" name="ZC_note" ></textarea>
          </div>
 <button type="submit" class="btn btn-default">Submit</button>
</form>

4

3 回答 3

1

我在这里制作了具有此功能的代码笔。

密码笔

我也会在这里添加和讨论代码,这真的不是那么难。

$( document ).ready(function() {
  $('#text').on('keypress', function(e) {
  var count = $(this).val().length;
   if(count != 0) {
     count += 1;
   } else {
     count = count;
   }
  $('#characterCount').text(count);   
})  
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div class="row">
  <div class="col m-2">
    <textarea id="text" rows="4" cols="50"></textarea>
  </div>
  <div class="col m-2">
    <textarea id="characterCount" rows="4" cols="50"></textarea>
  </div>
</div>

document.ready 函数确保函数在 DOM 准备就绪时加载。然后你有一个函数,只要在文本区域上按下一个键就会触发。然后,您将 count 变量设置为当前文本 ID 值的长度。然后将计数设置为加一,因为它是零索引。然后,您在另一个文本区域中表示该值。

于 2020-12-31T08:43:25.543 回答
0

问题是由于与用于设置计数器文本的遍历相比,插入错误元素的位置。

在您的计数器插件中,您正在寻找next()使用以下内容设置计数显示:

$(element).next("." + options.counterCssClass).html(renderText(remaining));

这是基于以下结构:

<inputElement/>
<counterDisplay/>

但是验证器 errorPlacment 正在做:

<inputElement/>
<validatorError/>
<counterDisplay/>

所以现在插件next(classSelector)没有返回匹配项

您可以简单地使用nextAll()而不是next()在插件中...或将 errorPlacement 更改为:

error.parent().append(element); 

nextAll()插件中使用的演示

于 2015-07-23T15:02:12.550 回答
0

寻找原因(问题)

我相信我找到了问题所在。当 a 字段未通过验证规则时,它会显示错误。错误被附加到 DOM 为:

这是必填栏。

当我使用控制台删除它时,计数器工作了。这让我很奇怪——也许 checkCount 函数仍然有效,但“输出”(span计数器)却没有。

所以在第 72 行,我补充说:

console.log(characterCount);

再次复制了那个场景——它确实打印了计数。所以问题是由于某种原因 - 当“错误”出现时,它与“文本计数器”冲突。请注意,在重新开始编写之后 - 似乎“错误”消失了 - 但事实是它仍在 DOM 中,它只是使用 CSS 隐藏了。

<span id="ZB_note-error" class="help-block" style="display: none;"></span>

然后,我在第 92 行添加了以下代码:

     console.debug( options.counterCssClass );
     console.debug( $(element).next("." + options.counterCssClass).html());

猜猜输出是什么。对于第一个调试行:text-counter(很好) 对于第二个调试行:未定义(不好)

如何解决?

解决方案1:next()错误地使用了该功能。

描述:获取匹配元素集中每个元素的紧随其后的兄弟。如果提供了选择器,则仅当它与该选择器匹配时,它才会检索下一个兄弟。

添加“错误”元素时,文本计数器字段不再适用于next()规则。考虑将其更改为:.parent().find('.text-counter')如果每个字段+文本计数器都有一个共同的父级。

解决方案 2:当用户开始输入时,从 DOM 中删除“error”元素。

于 2015-07-23T15:02:19.223 回答