【问题标题】:Working with checkboxes from javascript controller使用来自 javascript 控制器的复选框
【发布时间】:2011-05-08 00:48:50
【问题描述】:

我正在创建基于 ajax 的应用程序。现在我正在使用客户端javascript。我创建了根据应用程序逻辑正常工作的控制器,但是我在更新包含复选框的视图时遇到了问题。 这是我正在做的简短示例:

<script type='text/javascript'>
    var model = { 'chk1': true, 'chk2': false, 'chk3': false };
    var Controller = {
        'processCheck': function(chk, value) {
            model[chk] = value;
            if (chk == 'chk2')
                model.chk2 = true;
            if (chk == 'chk3' && value)
                model.chk1 = false;
            if (chk == 'chk1' && model.chk3)
                model.chk1 = false;
            Controller.updateView();
        },
        'updateView': function() {
            $('#chk1').attr('checked', model.chk1);
            $('#chk2').attr('checked', model.chk2);
            $('#chk3').attr('checked', model.chk3);
        }
    }
</script>
<input id='chk1' type="checkbox" onclick="Controller.processCheck('chk1', $('#chk1').attr('checked')); return false;" />
<input id='chk2' type="checkbox" onclick="Controller.processCheck('chk2', $('#chk2').attr('checked')); return false;" />
<input id='chk3' type="checkbox" onclick="Controller.processCheck('chk3', $('#chk3').attr('checked')); return false;" />

所以逻辑非常简化。 当我们单击复选框时会出现问题。它们更新不正确。 但是如果我用适当的参数调用控制器方法,然后检查模型,一切似乎都是正确的。 所以问题在于复选框中的点击事件。 我对输入字段和下拉菜单没有任何问题。

【问题讨论】:

  • 我知道如何选中和取消选中复选框。这是其他问题。实际上我正在使用 $('#id').attr('checked', true);和 $('#id').attr('checked', false);
  • 为什么“返回false;”在你的点击?点击没有被任何东西调用,因此没有返回值。
  • 我返回 false 以防止默认行为;我不希望通过单击更新复选框。我希望它们只调用控制器方法,然后控制器更新其中的一些方法。
  • 您能否确认第一次单击复选框 2 时的预期行为?

标签: javascript jquery model-view-controller checkbox click


【解决方案1】:

checkbox(和radio)上的click 事件既奇怪又令人困惑。

原则上,它发生在鼠标交互点,在单击导致复选框更改其状态之前。因此,应该可以return falseevent.preventDefault 取消进行该状态更改的默认操作。在这种情况下,复选框的状态不应被触及。

然而,这并不是在大多数浏览器中实际发生的情况。出于可以追溯到古代 Netscape 的一些历史怪癖,click 事件处理程序期间复选框的checked 属性实际上是新值。点击事件本身已经导致复选框改变状态。然后,如果您阻止默认操作 (return false),浏览器会说“哎呀,抱歉,该更改毕竟从未发生过”并主动将复选框翻转回原来的值

这意味着,如果您碰巧在点击处理程序内的脚本中故意设置复选框的状态,该值将会丢失,并被浏览器在原始点击更改上反转时钟的奇怪尝试覆盖。

因此,与直觉相反,未能return false 并阻止默认操作实际上会导致浏览器干扰更少!另一个解决方法是:

setTimeout(Controller.updateView, 0);

而不是直接在点击处理程序中调用updateView。这使浏览器有机会在您从模型覆盖它之前 翻转它的状态。您甚至可以将除 return false 之外的整个事件处理程序设置为 0 超时。

理论上,正确的解决方案是使用onchange 而不是onclick。此事件明确发生在状态更改之后,因此您完全不必担心这种怪异及其浏览器兼容性。 onchange 的问题在于 IE 没有以应有的速度启动它。它在触发之前等待焦点移出复选框,就像在文本输入上一样。所以至少在那个浏览器上,为了保持一致性,你需要 0-timeout-on-click 来代替。

【讨论】:

  • +1 对复选框单击事件和其他控件之间存在问题的差异的有趣解释。
  • 我同意@jball。这很有趣。
  • 谢谢! setTimeout(Controller.updateView, 0);为我工作!
  • 就像网络中许多阴暗、令人不快的历史包袱一样,这最终被记录和标准化by HTML5(“点击前激活步骤”、“取消激活步骤”)。
【解决方案2】:

Diodeus 是在正确的轨道上,return false; 正在导致您的问题。由于您的 updateView 函数每次都会设置所有检查,因此您不必担心它会被暂时检查,因为这一切都会比用户看到的更快。使用return false;,用户点击的复选框的updateView函数中checked状态的设置将被忽略。

简而言之,从所有onclick 函数中删除return false;,您的代码就会按照您想要的方式运行。

【讨论】:

  • 感谢您的回答,但它对我不起作用。这段代码只是简单的例子,在这里我们可以删除'return false',但在我的项目中,我正在处理嵌套元素的复杂结构。要求我的代码不应将任何事件冒泡到它的父控件。我可以通过使用事件对象来防止默认操作,但这会使我的代码更难理解和调试。为了避免现在和未来的开发人员出现问题,我们总是阻止来自控件的任何事件并只调用控制器方法,然后控制器在必要时更新适当的视图
  • @Serhiy Prysyazhnyy - 有道理,@bobince 使用setTimeout 提供的解决方案肯定会很好地适应这种结构。
猜你喜欢
  • 1970-01-01
  • 2016-08-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-18
相关资源
最近更新 更多