从 Knockout.js 选项数组中移除后重新初始化 Materialize.css 选择框

7

我有一个选择框,其中选项和选择是通过Knockout.js处理的。 我想使用Materialize CSS对其进行样式设置。

这对于选择框的初始显示以及通过使用'optionsAfterRender'绑定将选项添加到Knockout.js的'选项'可观察数组来重新初始化(浪费但有效)时效果还不错。

当删除选项时,Knockout.js不提供类似于'optionsAfterRender'的东西,因此没有明显的方法来触发Materialize CSS magic的重新初始化。

问题:您能看到任何非疯狂的选项吗?

代码:

<select data-bind="

      options: options,
      optionsText: function(item) { return optionsText[item] },
      value: displayedValue,

      optionsAfterRender: function (option, item) {
         setTimeout(function() {
            $(option.parentElement).material_select();
         }, 0);
      }
     ">
</select>

(由于否则所选的选项不会被选择,因此“setTimeout”是必需的。)
2个回答

8

使用自定义绑定处理程序更适合将类似material_select的自定义UI组件与KnockoutJS集成。以下是一种构建这样的处理程序的方法:

ko.bindingHandlers["materializeSelect"] = {
  after: ['options'],
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // Initial initialization:
    $(element).material_select();
    
    // Find the "options" sub-binding:
    var boundValue = valueAccessor();
    
    // Register a callback for when "options" changes:
    boundValue.options.subscribe(function() {
      $(element).material_select();
    });
  },
  update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    
  }
};

function RootViewModel() {
  var self = this, i = 2;
  self.options = ko.observableArray([{id: 1, txt: "Option A"}, {id: 2, txt: "Option two"}]);
  self.selectedOption = ko.observable(null);
  
  // For testing purposes:
  self.addOption = function() { self.options.push({id: ++i, txt: "Dynamic option " + i}); };
}

ko.applyBindings(new RootViewModel());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.4/js/materialize.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.4/css/materialize.min.css" rel="stylesheet"/>

<select data-bind="materializeSelect: { options: options },
                   options: options,
                   optionsText: 'txt',
                   value: selectedOption">
</select>

<button data-bind="click: addOption">Add option dynamically</button>

坦白地说,我觉得这是MaterializeCSS中的一个问题/遗漏或者甚至是一个bug,因为它显然没有注意到select选项的变化。如果我没记错,像Select2和Chosen这样的库确实有这个功能。
无论如何,如果MaterializeCSS能够正确地注意到动态添加的选项,我仍然建议使用自定义绑定处理程序,只需要一个更简单的处理程序即可:
ko.bindingHandlers["materializeSelect"] = {
  after: ['options'],
  init: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    $(element).material_select();
  },
  update: function(element, valueAccessor, allBindings, viewModel, bindingContext) {
    // Handle ViewModel changes of which MaterializeCSS needs custom
    // notification here.
  }
};

我通常在重新初始化之前调用.material_select('destroy');,以确保。在我看来,materializecss有点年轻。 - Andrei C
感谢您提供一个完美运作的答案 - 这也解决了我在KO模型中如何在值更改后重新初始化的下一个问题! - gzost

0
Jeroen的回答很好也是正确的,我想补充一个附注使用SO评论,但这更好地使用完整的格式,我认为。
当放置在select上时,Materialize对于disable绑定似乎有些奇怪,特别是如果该disable依赖于另一个knockout可观察对象的更新(通常是这样)。
我在我的更新函数中使用以下内容:
if(allBindings().disable != undefined && allBindings().disable == true){
   $(element).prop("disabled", true);
}
else{
   $(element).prop("disabled", false);     
}

$(element).material_select();

我最初尝试在更新函数中仅调用$(element).material_select(),但似乎有点不稳定,只有在某些时候才能正常工作。明确更改元素上的禁用属性似乎每次都有效。

可能有更简洁的方法来解决这个问题,但希望这个例子说明了一个要点:根据绑定状态明确设置禁用属性。

我不知道是否使用其他绑定(例如visible等)会遇到类似的问题,但如果有,这些问题可能可以用类似的方式解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接