【问题标题】:ko.computed property to determine visibility not workingko.computed 属性来确定可见性不起作用
【发布时间】:2017-03-29 23:41:55
【问题描述】:

在我的 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 为真),那么对于当前选择的用户,检查他/她是否有任何角色。 如果是,则遍历它们并显示它们,如果不是,显示一些文字说“用户没有角色”。 p>

除了显示 User has no Roles 文本 sn-p 之外,一切似乎都可以正常工作。我不知道为什么没有显示!我在我的计算属性中设置了断点,并且可以看到当我选择一个没有角色的用户时,表达式(在控制台窗口中)为假,我正在否定它,所以我应该看到那个文本sn-p!

我做错了什么?我创建了一个screencast 让事情更容易理解。

【问题讨论】:

  • 可能是 CSS 问题,即文本显示在别处?
  • 你确定self.selectedUser().roles() 不为空吗?
  • 不,当我添加一个用户时,我也调用了setCurrentUser(user) 函数,你可以see here 认为.roles() 是一个空数组,这是新添加的用户所期望的。跨度>

标签: javascript knockout.js


【解决方案1】:

当你想否定绑定中的可观察值或计算值时,你必须显式调用它:

<!-- 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
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"&gt;&lt;/script&gt;

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
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"&gt;&lt;/script&gt;

我希望这个小细节可以帮助您(以及其他犯过此错误的人)能够确定将来何时需要 ()。

【讨论】:

  • 很遗憾你的解释不在documentation
  • 我只知道这件事。正如@GôTô 所说,如果将其添加到文档中会很好。
【解决方案2】:

因为你不是绑定到变量而是绑定到表达式,所以这里需要加括号:

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

看下面的sn-p

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。

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

    • 但已加载是真的,因为当我在isLoaded() 检查之后放置一个测试人员&lt;h6&gt;boo!&lt;/h6&gt; 时,显示我选择了一个新添加的用户
    • isLoaded 是可观察的吗?如果不是,并且 SelectedUserHasRoles 在 isLoaded 为真之前首先被评估,它可能不会对 selectedUser 设置依赖项跟踪(因为 selectedUser() 从未被调用,因为 isLoaded 之前为假)。
    • 是的,这是可以观察到的。 self.isLoaded = ko.observable(false); 然后我将它设置为 true,当我的 ajax 调用成功时。
    • 很难说没有看到实际代码。也许您分配给 selectedUser() 的用户对象尚未包装在 viewModel 中?或者你应该试试
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-16
    • 1970-01-01
    • 1970-01-01
    • 2011-06-21
    • 2018-10-08
    • 1970-01-01
    相关资源
    最近更新 更多