复选框绑定的选中状态倒置在Chrome

Checkbox binding of checked state inverted in Chrome

本文关键字:Chrome 状态 绑定 复选框      更新时间:2023-09-26

我使用Ember v2.5.1和Ember data v2.6.2,并且我有一系列嵌套组件来呈现类别的分层树。在最底层组件categories-tree-node中有一个闭包动作,它调用categories-select组件动作中的toggleAddCategory函数,并向上传递相关的类别对象。

它在Safari中按预期工作,但由于某种原因,检查状态在Chrome和FF中被反转。奇怪的是,当复选框被更改时,值本身的选中状态绑定在模板的其他位置正确地呈现。

我在这里创建了一个演示,如果你尝试在Chrome/FF vs Safari中勾选/取消勾选框,你应该会看到这个问题。是否有一种更好的方法来处理这种带有复选框选中状态的操作绑定?我读到过,在Ember 2及以上的版本中,使用观察者被认为是一种反模式,而且当我尝试这样做时,它对子类别不起作用。

好的,所以你的旋转显示状态在Chrome中不变,但在Safari中改变。

这很可能是Safari中jQuery的一个bug,因为Ember。复选框设置checked使用jQuery prop方法:

change() {
  set(this, 'checked', this.$().prop('checked'));
}

一个变通的解决方案是使用复选框作为一个尖括号组件(默认情况下有单向绑定),以确保checked绑定不被input组件更改,而是使用传入的闭包操作来手动切换选中状态。

这也符合Ember推荐的使用Data Down - Actions Up模式设置组件父属性的最佳实践。

注意:您可能希望使用onchange事件而不是onclick

Child components/categories-tree-node.hbs

<input type="checkbox"
       checked={{category.checked}} <!-- checked is just passed from above, not set within the component -->
       onchange={{action toggle category}} <!-- onchange calls the passed in action which toggles checked -->
       id={{concat elementId '-' category.slug}}
>
...

父节点 components/categories-select.js

export default Ember.Component.extend({
  // ...
  actions: {
    toggleAddCategory(category) {
      category.toggleProperty('checked'); // toggle the property yourself
      // ...  
    }
  }
});

如果您的父操作只执行切换而不执行其他操作,则可能不需要它,可以在components/categories-tree-node.hbs中使用mut helper进行切换:

<input type="checkbox"
       checked={{category.checked}} <!-- checked is just passed from above, not set within the component -->
       onchange={{action (mut category.checked) value="target.checked"}} <!-- onchange automatically sets category.checked -->
       id={{concat elementId '-' category.slug}}
>