KnockoutJS - 禁用绑定 - 当父元素有值时如何禁用子元素

Posted

技术标签:

【中文标题】KnockoutJS - 禁用绑定 - 当父元素有值时如何禁用子元素【英文标题】:KnockoutJS - disable binding - how to disable child elements when parent has value 【发布时间】:2015-04-05 19:49:06 【问题描述】:

我编写了一个 jsfiddle 来演示我在下面要完成的工作。有一个要求,当在父(旅行)支付金额输入中输入值时,应禁用子(费用)支付金额。反之亦然,当在任一子(收费)支付金额输入中输入支付金额时,父母禁用。我认为我让它对父级工作得很好——它禁用了两个子级输入——但是在第二个充电输入中输入一个值时,它不会禁用父级。它也是硬编码的,所以我需要这部分的帮助:

charges()[0].payAmount() != '' || charges()[0].payAmount() != 0

我已经看到这个 - Knockoutjs Update child when parent's observable changes - 添加订阅者,但我认为我仍然无法从那里访问/禁用孩子。或者也许我可以,用 jQuery?我也看到了这个 - Is there any way to disable a bunch of form elements at once? - 使用绑定处理程序可能会在孩子的输入中输入值时处理 $parent 的禁用。不过看起来很复杂。我注意到在 ko enable binding documentation 中,您可以传递一个任意表达式,但您似乎无法传递任何参数,例如当前对象。而且,在函数签名上,如果我将游览作为参数添加,我已经验证它是未定义的。这是我试图附加到父级禁用绑定的函数,但无济于事,因为遇到未定义:

function hasChildEntries(encounter) 
    ko.utils.arrayFirst(encounter.charges(), function (charge) 
        console.log(charge + ', ' + charge.payAmount() + '...');
        if (charge.payAmount() != '' || charge.payAmount() != 0)
            return true;
    );
    return false;
;

查看:

<div>
    <ul class="payments">
    <!-- ko foreach: excursions -->
    <li class="payments">
        <div class="payments">
        <a href='#' class="expand glyphicon glyphicon-minus-sign" style="color:grey"></a>
        <a href='#' class="collapse glyphicon glyphicon-plus-sign" style="color:grey"></a>
        </div>
        <div class="payments" data-bind="text: 'Excursion ID: ' + id + '&nbsp;&nbsp;Pay Amount: '"></div>
        <input class="payments" data-bind="
            textInput: payAmount,
            valueUpdate: 'afterkeydown',
            disable: charges()[0].payAmount() != '' || charges()[0].payAmount() != 0" />
        <ul class="payments bullet">
        <!-- ko foreach: charges -->
        <li class="payments">
            <div class="payments" data-bind="text: name + '&nbsp;&nbsp;Pay Amount: '"></div>
            <input class="payments" data-bind="
                textInput: payAmount,
                valueUpdate: 'afterkeydown',
                disable: $parent.payAmount() != '' || $parent.payAmount() != 0" />
        </li>
        <!-- /ko -->
        </ul>
    </li>
    <!-- /ko -->
    </ul>
</div>

查看模型/javascript

var viewModel = function () 
    var self = this;
    self.excursions = ko.observableArray().extend( rateLimit: 0 );

    function Excursion(id, name, chgAmount, payAmount, charges) 
    this.id = id;
    this.name = name;
    this.chgAmount = chgAmount;
    this.payAmount = ko.observable('');
    this.charges = ko.observableArray(charges).extend( rateLimit: 0 );
    ;

    function Charge(id, name, date, chgAmount, payAmount) 
    this.id = id;
    this.name = name;
    this.date = date;
    this.chgAmount = chgAmount;
    this.payAmount = ko.observable('');
    ;

    self.excursions.push(new Excursion('1234', 'Excursion 1', 90.00, 0, undefined));
    ko.utils.arrayFirst(self.excursions(), function (excursion) 
    if (excursion.id = '1234') 
        excursion.charges.push(new Charge(1, 'Trunk Bay', '02/10/2015', 50.00, 0));
        excursion.charges.push(new Charge(2, 'Cinnamon Bay', '02/10/2015', 40.00, 0));
    
    );
    self.excursions.push(new Excursion('1235', 'Excursion 2', 80.00, 0, undefined));
    ko.utils.arrayFirst(self.excursions(),  function (excursion) 
    if (excursion.id == '1235')
        excursion.charges.push(new Charge(3, 'Coral Bay', '02/11/2015', 80.00, 0));
    );


var vm = new viewModel();
ko.applyBindings(vm);

$(".expand").click(function ()  
    $(this).toggle(); 
    $(this).next().toggle(); 
    $(this).parent().parent().children().last().toggle();
); 
$(".collapse").click(function ()  
    $(this).toggle(); 
    $(this).prev().toggle(); 
    $(this).parent().parent().children().last().toggle();
);

CSS:

.altRow:nth-child(even) td  background-color: #D8D8D8; 
ul.payments  list-style:none; float:left; width:100% 
li.payments  padding-top:10px; float:left; width:100% 
div.payments  float:left 
.expand  width:15px;height:15px; 
.collapse  width:15px;height:15px;display:none 
ul.payments.bullet list-style-type: disc;
input.payments  width:80px;height:20px; 

JSFiddle

【问题讨论】:

【参考方案1】:

将计算添加到您的游览模型中:

this.hasCharges = ko.computed(function() 
  for(var i = 0, len = charges().length; i < len; i++ ) 
    if( charges()[i].payAmount() ) 
      return true;
    
  
  return false;
);

然后在你的标记中,替换

disable: charges()[0].payAmount() != '' || charges()[0].payAmount() != 0"

disable: hasCharges

这将禁用父母,无论它有多少孩子

编辑:给你一个小提琴: http://jsfiddle.net/8j8k7h1c/33/

尽量避免在你的函数中使用“this”,否则会搞砸范围。我用过

var self = this;

保持计算函数可观察到的费用。

【讨论】:

是的,完美。我读过你应该使用计算函数来控制它,但没有意识到你必须将它附加到函数上,这样父/子的实例才能相互认识。太棒了 - 非常感谢!在函数中使用 self 的好处 - 我已经看到了,但没有这样做。对 ko 来说还是有点新... 哦,对只使用 if(charges()[i].payAmount()) 而不是检查 != '' 或 != 0 的很好的更新,所以它正在检查“真实”的表达。不错的变化。 说实话。如果你没有初始化你的 observable,它也会捕获 null/undefined

以上是关于KnockoutJS - 禁用绑定 - 当父元素有值时如何禁用子元素的主要内容,如果未能解决你的问题,请参考以下文章

KnockoutJS 绑定

Knockoutjs 单页应用程序绑定问题

Knockoutjs(2.1.0 版):将布尔值绑定到选择框

KnockoutJS 3.X API 第四章 数据绑定 UI绑定

Knockoutjs单页应用程序绑定问题

knockoutjs data-bind 声明式绑定整理