ko.computed属性确定可见性不起作用

时间:2017-03-29 14:24:58

标签: javascript knockout.js

在我的KncokoutJS ViewModel中,我有以下计算属性:

self.SelectedUserHasRoles = ko.computed(function () {
  if (self.isLoaded()) {
    return self.selectedUser().roles().length > 0;
  }
  return false;
});

在我的HTML中,我有以下内容:

<!-- ko if: isLoaded() -->
  <!-- ko if: !SelectedUserHasRoles -->
  <div>
    <p>User has no Roles.</p>
  </div>
  <!-- /ko -->
  <!-- ko if: SelectedUserHasRoles -->
  <div class="roles-wrapper" data-bind="foreach: $root.selectedUser().roles()">
    <div class="role-token" data-bind="text: Name"></div>
  </div>
  <!-- /ko -->
<!-- /ko -->

在我的代码中,我是这样说的:

  

来自AJAX调用的数据已完成加载( isLoaded为true ),然后对于当前选定的用户,检查并查看他/她是否有任何角色即可。 如果是,那么循环播放并显示它们,如果不是,则显示一些文字说'用户没有角色'。

除了显示User has no Roles文字摘要外,所有内容似乎都有效。我不知道为什么没有显示!我将断点放入我的计算属性中,并且可以看到当我选择没有角色的用户时,表达式(在控制台窗口中)是假的,我在否定它,所以我应该看到那个文本片段!

我做错了什么?我创建了screencast以便于理解。

3 个答案:

答案 0 :(得分:4)

如果要在绑定中否定可观察值或计算值,则必须明确调用它:

<!-- ko if: !SelectedUserHasRoles() -->

if绑定的情况下,还有ifnot对应物:

<!-- ko ifnot: SelectedUserHasRoles -->

我认为理解为什么这是有用的,因为我发现它发生了很多。

您可以将data-bind属性视为以逗号分隔的键值对字符串。淘汰赛wraps each of the values in a function,称之为valueAccessor

基本上,你会来自:

 data-bind="if: SelectedUserHasRoles"

{ 
   "if": function() { return SelectedUserHasRoles }
}

SelectedUserHasRoles是一个可观察的实例,其评估为 truthy 。当您使用!否定此值时,它将始终为false

var myObs = ko.observable("anything");

var valueAccessor =    function() { return  myObs; };
var valueAccessorNeg = function() { return !myObs; };

console.log(valueAccessor());    // Returns the observable
console.log(valueAccessorNeg()); // Always prints false
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

valueAccessor函数被传递给绑定的init方法。通常,它由calling检索,然后unwrapped检索。由于unwrap实用程序不关心您是否将observable或普通值传递给它,因此当您犯错时

var myObs = ko.observable(false);

var va1 = function() { return myObs; };
var va2 = function() { return !myObs; };
var va3 = function() { return !myObs(); };

console.log(ko.unwrap(va1()));    // false
console.log(ko.unwrap(va2()));    // always false
console.log(ko.unwrap(va3()));    // true
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

我希望这个小小的窥视可能会帮助你(和那些犯了这个错误的人)能够确定将来需要()的时间。

答案 1 :(得分:1)

因为您没有绑定到变量而是绑定到表达式,所以需要在此处添加括号:

<!-- ko if: !SelectedUserHasRoles() -->
                               //^^ here

请参阅以下代码段

function CreateVM() {
    var self = this;
    this.isTrue = ko.observable(false);
    this.selectedUser = ko.observable();
    this.isLoaded = ko.observable();
    self.SelectedUserHasRoles = ko.computed(function () {
       if (self.isLoaded()) {
          return self.selectedUser().roles().length > 0;
       }
       return false;
    });
}

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

var userWithRoles = { roles: ko.observableArray([1,2]) }; 
var userWithoutRoles = { roles: ko.observableArray([]) }; 
vm.selectedUser(userWithoutRoles);
vm.isLoaded(true);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<!-- ko if: isLoaded() -->
  <!-- ko if: !SelectedUserHasRoles() -->
  <div>
    <p>User has no Roles.</p>
  </div>
  <!-- /ko -->
  <!-- ko if: SelectedUserHasRoles -->
  <div class="roles-wrapper" data-bind="foreach: $root.selectedUser().roles()">
    <div class="role-token" data-bind="text: $data"></div>
  </div>
  <!-- /ko -->
  SelectedUserHasRoles: <span class="role-token" data-bind="text: SelectedUserHasRoles"></span>
<!-- /ko -->

有关详细信息,请参阅user3297291's answer

答案 2 :(得分:0)

对isLoaded()进行两次相同的检查,实际上是

<!-- ko if: isLoaded() -->
  <!-- ko if: !SelectedUserHasRoles -->

如果isLoaded()evalutes为false,则您的SelectedUserHasRoles()甚至不会被评估。