javascript - 使用Knockout.js将按钮类与选项控件同步

标签 javascript html twitter-bootstrap user-interface knockout.js

通常,我可以找出一种方法来使Knockout-js执行我想要的操作。但是,在这种情况下,我有点挣扎,所以我向SO方面的社区开放这个问题。

介绍

我正在使用Typescript,bootstrap,knockoutjs和nodejs后端编写HTML5 Web应用程序。

在我的用户界面中,这些用户都可以通过剔除JS进行控制,我有一组按钮,这些按钮构成了可选项的自举3按钮组。

这个合理的组水平地给了我4个按钮,但是允许按钮选择的行为与一组选项按钮保持一致。

这种一致性很重要,因为一次只能选择一个按钮,因此单击一个按钮时,其余按钮将被取消选择。

这是BS3中的默认组件,如下图所示:



如您在图像中看到的,选择了“ Discarded”按钮,要实现此目的,必须将“活动”类添加到构成控件的内部单选元素周围的标签元素的现有类列表中。以下HTML用于创建此图像:

<div class="btn-group btn-group-justified" data-toggle="buttons">
  <label class="btn btn-primary">
    <input type="radio" name="options" id="option1" checked >Rejected
  </label>
  <label class="btn btn-primary active">
    <input type="radio" name="options" id="option2">Discarded
  </label>
  <label class="btn btn-primary">
    <input type="radio" name="options" id="option3">Held
  </label>
  <label class="btn btn-primary">
    <input type="radio" name="options" id="option3">Header Added
  </label>
</div>


除一个小缺陷外,所有这些都很好用,我正在使用淘汰赛JS来管理UI。

我正在尝试解决的问题

每个选项的选中状态都绑定到应用于HTML的视图模型中的一个属性,因此,例如,拒绝按钮上的内部选项具有一个常规的剔除js检查绑定,如下所示:

<input type="radio" name="options" id="option1" checked data-bind="checked: reject">Rejected


每个选项都有各自的支持字段:

reject
discard
hold
addheader


并且这些支持字段中的每一个都是标准布尔值,包含true / false,我不知道如何在封闭标签上添加/删除“ active”类,以反映已选择了哪些状态。

更准确地说,我想不出优雅的最佳方法。

我尝试过的方法

我知道的工作是向返回的每个标签添加一个简单的可计算观察值

"btn btn-primary active"


当该选项设置为true时,以及

"btn btn-primary"


当不是。

我知道这一点,因为在我的视图模型中,我有一个简单的函数:

SenderDialogViewModel.prototype.isRejectSelected = function () {
        if (this.reject == true) {
            return "btn btn-primary active";
        }
        return "btn btn-primary";
    };


但是,这种方法意味着有4种功能,每个标志要测试一个,因此很难在以后添加新标志。

我想要做的是如下所示:

<label class="btn btn-primary" data-bind="class: isSelected(reject)">


举个例子。

我几乎对上面的内容进行了一些修改:

SenderDialogViewModel.prototype.isSelected = function (selectionVariable) {
        if (selectionVariable == true) {
            return "active";
        }
        return "";
    };


选择变量可以是传入的视图模型中可用的任何标志。

这里的问题是,这仅在第一次绘制UI时更新,随后对标志进行了更改,未能更新UI来反映给定的状态。

为了尝试解决此问题,我将该函数更改为一个可计算的可观察对象,然后才在绘制UI时收到JS错误,并指出已向该计算的可观察对象添加了“写入”处理程序,因为我正在传递一个输入参数。

如果我需要添加写处理程序,那很好,但是我宁愿不这样做。

摘要

因此,总而言之,有一些方法可以与其他选项同步地更改类列表,但是大多数方法都是混乱的,我想做的是创建一种易于添加新按钮时进行扩展的方法(这一点很重要按钮集是动态生成的),而不是添加一个处理程序来单独检查和报告每个变量的状态,而只需一个函数调用即可将其简单地添加到视图模型中并一次又一次地重复使用。

最佳答案

好的...而且总是会发生的,我不会立即发布此帖子,而实际上我不知道该如何使其工作。

解决方案一直以淘汰赛js css绑定的形式盯着我。

引用基因敲除js文档:


  css绑定向关联的DOM元素添加或删除一个或多个命名CSS类。例如,如果它变为负值,则用红色突出显示某些值很有用。


这就是说,“根据视图模型中变量的值,我可以将一个类应用于或删除一个已经存在的类的集合”

因此,我的问题的答案非常简单地变成了:

<div class="btn-group btn-group-justified" data-toggle="buttons">
  <label class="btn btn-primary" data-bind="css: { active: reject }">
    <input type="radio" name="options" id="option1" checked >Rejected
  </label>
  <label class="btn btn-primary" data-bind="css: { active: discard }">
    <input type="radio" name="options" id="option2">Discarded
  </label>
  <label class="btn btn-primary" data-bind="css: { active: hold }">
    <input type="radio" name="options" id="option3">Held
  </label>
  <label class="btn btn-primary" data-bind="css: { active: addheader }">
    <input type="radio" name="options" id="option3">Header Added
  </label>
</div>


除此之外,如果我现在仅将适当的选项/选中的绑定添加到选项控件本身,那么在单击按钮时,所有内容都应根据需要正确更新。

关于自己制定答案的一点说明

我认为有时候,只需要仔细思考您的问题,而“虚拟地”尝试向他人描述问题,就会触发大脑朝不同的方向思考。

当然,这是有帮助的,当我一分钱掉下来时我一直在输入,但是我继续进行,然后适当地回答/更新,因为我发现这是一个也会使其他人绊倒的问题,希望这可以作为一种教育。可能喜欢我的同行旅行者正遭受着周日晚上的放屁。

2014年6月30日星期一更新

事实证明,这比我最初预期的要复杂得多。当然,我已经解决了有关上述按钮的CSS同步问题的主要答案。但是...同步“选项”按钮也是一个很大的挑战,此更新旨在提供一个完整的端到端解决方案。

首先,您需要像这样标记HTML:

<p><strong>Rule type:</strong></p>
<div class="btn-group btn-group-justified" data-toggle="buttons">
  <label class="btn btn-primary" data-bind="css: { active: reject }, click: function(){ changeType('reject'); }">
    <input type="radio" name="ruletype" value="reject" data-bind="checked: selectedOptionString" >Rejected
  </label>
  <label class="btn btn-primary" data-bind="css: { active: discard }, click: function(){ changeType('discard'); }">
    <input type="radio" name="ruletype" value="discard" value="true" data-bind="checked: selectedOptionString">Discarded
  </label>
  <label class="btn btn-primary" data-bind="css: { active: hold }, click: function(){ changeType('hold'); }">
    <input type="radio" name="ruletype" value="hold" data-bind="checked: selectedOptionString">Held
  </label>
  <label class="btn btn-primary" data-bind="css: { active: addheader }, click: function(){ changeType('addheader'); }">
    <input type="radio" name="ruletype" value="addheader" data-bind="checked: selectedOptionString">Header Added
  </label>
</div>


钥匙拿走的地方如下:


1)CSS规则必须指定“活动”类,并绑定到您的独立选项标志,该标志对于所选的选项显示true / false。
2)您必须在按钮上具有单击处理程序,BS3(如我所知)会在选项控件上处理按钮上的单击,这是由于敲除如何使该HAS成为内联函数,并传入单个参数,不要试图将其直接与该选项使用的已计算可观察值绑定,它将无法工作。
3)您必须如图所示标记选项元素,即它们必须全部具有相同的名称属性,该值必须与您希望所选选项描述的内容匹配,并且必须与按钮处理程序发送的字符串匹配
4)每个选项元素都不能绑定到一个简单变量,您需要通过一个可计算的可观察变量传递它,这不仅是因为我如何处理它们,而且即使对于简单的单个布尔开关,它也使用“ true”和“ false”作为字符串,而不是您可能期望的布尔值。


标记完HTML后,您需要构建一个视图模型来支持所有功能,在我的情况下,我实际上是使用Typescript做到这一点,然后编译为JS,我要粘贴的代码是由TS编译器。

首先,首先需要确保您的视图模型具有以下属性:

this.reject = ko.observable(false);
this.discard = ko.observable(false);
this.hold = ko.observable(false);
this.addheader = ko.observable(false);


(使用self,this,me ...或您用来定义淘汰模型的任何方法)重要的是,它们是简单的ko可观察的boolean模型

您还需要同时具有写入和读取功能的已计算可观察对象:

this.selectedOptionString = ko.computed({
    read: function () {
        if (this.reject())
            return "reject";
        if (this.discard())
            return "discard";
        if (this.hold())
            return "hold";
        if (this.addheader())
            return "addheader";
    },
    write: function (value) {
        console.log("rejectstr:");
        console.log(value);
        if (value == "reject") {
            this.reject(true);
            this.discard(false);
            this.hold(false);
            this.addheader(false);
        }
        if (value == "discard") {
            this.reject(false);
            this.discard(true);
            this.hold(false);
            this.addheader(false);
        }
        if (value == "hold") {
            this.reject(false);
            this.discard(false);
            this.hold(true);
            this.addheader(false);
        }
        if (value == "addheader") {
            this.reject(false);
            this.discard(false);
            this.hold(false);
            this.addheader(true);
        }
    }
}, this);


这可能可以做得更优雅一些,但是从本质上讲,当在剔除下激活组中的一个选项时,剔除会采用'Value'属性中的所有内容,并将其作为字符串发送到您的视图模型中。

如果将其绑定到简单的可观察对象,则该可观察对象将设置为该属性的字符串值。但是对我来说,因为我要设置一系列的4个标志来控制UI上的各种状态,所以如果合适的话,可以使用链接的标志(也可以使用开关或查找数组或哈希表)

可观察到的最终结果是一次只能设置一个布尔值,并且一次只能设置一个布尔值,因为按钮中的CSS绑定到了此标志,所以活动类将应用于给定的按钮,并且该按钮被设置为true 。

对于读取,您需要将标志状态转换回字符串以进行剔除,以便与它所知道的值进行比较,因此读取操作相反。

对于按钮单击处理程序,您必须按照标记中的说明进行内联,这是因为敲除保留了一些自动参数,例如元素名称,事件信息和其他参数,在这里我们不需要这些参数,因此最简单的方法是内联它。

但是,衬里意味着您不绑定属性,因此不能将其直接与选项控件使用的已计算可观察值绑定。

相反,您需要做的是向视图模型添加一个小的存根函数,如下所示:

SenderDialogViewModel.prototype.changeType = function (newType) {
    this.selectedOptionString(newType);
};


不需要以任何方式观察到此情况,因为仅在单击按钮时才以一种方式调用它。

如果您想查看完整的解决方案,我将使该应用程序可以在我的git-hub页面上免费提供给人们使用,但尚未完成。

我必须承认,希望以上所有内容对某些人有用,但事实证明,这比我预期的要困难得多。

美女

关于javascript - 使用Knockout.js将按钮类与选项控件同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24479117/

相关文章:

javascript - 有人可以建议一些更好的方法来编写这个 Javascript 代码吗

Javascript setTimeout 调用添加 Dom 节点,所有节点同时添加

html - 如何在表格上方添加空间?填充不起作用

javascript - 固定 iOS 导航工具栏下的元素

html - 如何让固定的侧边栏在从智能手机查看时很好地显示

html - 表单中各列之间的连字符

javascript - 滚动直到组件可见时如何更改导航栏上的事件选项卡?

javascript - ImageBitmap 和 ImageData 的区别

jquery - TextBox 的启用禁用动态使用 knockout 观察?

javascript - 有什么方法可以在 jssor slider 中为图像添加框阴影?