KnockoutJS - 如何使用 Observable 数组在 foreach 中隐藏某些元素?

KnockoutJS - How to hide certain elements inside foreach using Observable Arrays?

我有一个网站所有者列表。我正在尝试构建一个 UI,当我点击所有者时,它将显示有关所有者的更多信息。

       this.toExpand = ko.observableArray(); //initialize an observable array
       this.invertExpand = ko.observable("");


        this.invertExpand = function (index) {
                if (self.invertExpand[index] == false) {
                self.invertExpand[index] = true;
                alert(self.invertExpand[index]); //testing whether the value changed
            }
            else {
                self.invertExpand[index] = false;
                alert(self.invertExpand[index]); //testing whether the value changed
            }
           
        };

这是 HTML 代码:

  <div data-bind="foreach: WebsiteOwners">
  <div>
        <button data-bind="click: $root.invertExpand.bind(this,$index())" class="label label-default">>Click to Expand</button>
    </div>
  <div data-bind="visible: $root.toExpand()[$index]">
   
  

  Primary Owner: <span data-bind="text:primaryOwner"></span>
  Website Name : <span data-bind="text:websiteName"></span>
  //...additional information

  </div>
  </div>

您可以将 WebsiteOwner 项中的一项直接存储在您的可观察对象中。无需使用索引。

不要忘记您通过不带参数调用它来读取一个可观察对象(例如 self.invertExpand<b>()</b>)并且您通过调用一个值来写入它(例如 self.invertExpand<b>(true)</b>)

我在这个答案中包含了 3 个示例:

  • 只允许使用敲除打开一个细节
  • 允许使用敲除独立打开和关闭所有细节的一个
  • 不使用敲除但使用普通 HTML 的

1。手风琴

下面是支持单个扩展元素的列表示例:

const websiteOwners = [
  { name: "Jane", role: "Admin" },
  { name: "Sarah", role: "Employee" },
  { name: "Hank", role: "Employee" }
];

const selectedOwner = ko.observable(null);

const isSelected = owner => selectedOwner() === owner;
const toggleSelect = owner => {
  selectedOwner(
    isSelected(owner) ? null : owner
  );
}

ko.applyBindings({ websiteOwners, isSelected, toggleSelect });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<ul data-bind="foreach: { data: websiteOwners, as: 'owner' }">
  <li>
    <span data-bind="text: name"></span>
    <button data-bind="
      click: toggleSelect,
      text: isSelected(owner) ? 'collapse' : 'expand'"></button>
      
    <div data-bind="
      visible: isSelected(owner),
      text: role"></div>
  </li>
</ul>

2。独立

如果您希望它们中的每一个都能够 expand/collapse 独立,我建议将该状态添加到所有者视图模型中:

const websiteOwners = [
  { name: "Jane", role: "Admin" },
  { name: "Sarah", role: "Employee" },
  { name: "Hank", role: "Employee" }
];

const OwnerVM = owner => ({
  ...owner,
  isSelected: ko.observable(null),
  toggleSelect: self => self.isSelected(!self.isSelected())
});
  
ko.applyBindings({ websiteOwners: websiteOwners.map(OwnerVM) });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<ul data-bind="foreach: websiteOwners">
  <li>
    <span data-bind="text: name"></span>
    <button data-bind="
      click: toggleSelect,
      text: isSelected() ? 'collapse' : 'expand'"></button>
      
    <div data-bind="
      visible: isSelected,
      text: role"></div>
  </li>
</ul>

3。使用 <details>

这个利用了 <details> 元素的力量。它可能更易于访问并且更容易实施!

const websiteOwners = [
  { name: "Jane", role: "Admin" },
  { name: "Sarah", role: "Employee" },
  { name: "Hank", role: "Employee" }
];

ko.applyBindings({ websiteOwners });
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<ul data-bind="foreach: websiteOwners">
  <li>
    <details>
      <summary data-bind="text: name"></summary>
      <div data-bind="text: role"></div>
    </details>
  </li>
</ul>