Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

foreach: $array, $isFirst, $isLast, $isEven, $isOdd, $next, $previous #2415

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

barsh
Copy link

@barsh barsh commented Sep 18, 2018

There are situations where you want access to the array bound to a foreach, for example:

var vm = {
  array: [0,1,2,3]
}
ko.applyBindings(vm)
<div data-bind="foreach: array.filter(el => el > 1)">
    <div>
        <span data-bind="text: $index"></span> 
        of 
        <span data-bind="text: $parent.array.length-1"></span>
    </div>
</div>

This produces

0 of 3
1 of 3

instead of

0 of 1
1 of 1

This PR introduces $array to the context, for example:

<div data-bind="foreach: array.filter(el => el > 1)">
    <div>
        <span data-bind="text: $index"></span> 
        of 
        <span data-bind="text: $array.length-1"></span>
    </div>
</div>

Which produces the desired result of

0 of 1
1 of 1

In addition to $array the following additional helpers were added:
$isFirst, $isLast, $isEven, $isOdd, $next, $previous

For example:

var vm = {
  array: ['a', 'b']
}
ko.applyBindings(vm)
<div data-bind="foreach: array">
    <div>$data: <span data-bind="text: $data"></span></div>
    <div>$isFirst: <span data-bind="text: $isFirst"></span></div>
    <div>$isLast: <span data-bind="text: $isLast"></span></div>
    <div>$isEven: <span data-bind="text: $isEven"></span></div>
    <div>$isOdd: <span data-bind="text: $isOdd"></span></div>
    <div>$previous: <span data-bind="text: $previous"></span></div>
    <div>$next: <span data-bind="text: $next"></span></div>
    <hr>
</div>

produces:

$data: a
$isFirst: true
$isLast: false
$isEven: true
$isOdd: false
$previous:
$next: b
----
$data: b
$isFirst: false
$isLast: true
$isEven: false
$isOdd: true
$previous: a
$next:

@brianmhunt
Copy link
Member

Conceptually I think this is useful, but we'd need to make sure it's consistent with the fast-foreach API in tko (since folks may move back-and-forth); the tko API is more complex since it's O(c) until $index is accessed, then it becomes O(1). A similar set of accessors could add quite a bit of complexity to fast-foreach.

@knockout knockout deleted a comment from allen2143 Sep 25, 2018
@bikeshedder
Copy link

I wonder why you want to perform such code in the template rather than adding a filteredArray to your model:

model.filteredArray = ko.pureComputed(() => model.array.filter(el => el > 1))

I don't see a huge downside of adding an $array to the context inside a forEach but I wonder if this kind of code isn't bad practice and should be avoided anyways.

@barsh
Copy link
Author

barsh commented Oct 3, 2018

@bikeshedder: Thanks for jumping in with a great point that I agree with. However, the situation that inspired this pull request was a bit more complex than the simplified example provided here and while your suggestion could be applied to that situation too, filtering in the template itself in that particular case led to a more developer-friendly solution.

@caseyWebb
Copy link
Contributor

caseyWebb commented Oct 19, 2018

I just realized that with the addition of the let binding in 3.5.0-rc, the need for $array is greatly reduced.

For example...

<!-- ko let: { myFilteredArray: arr().filter(...) } -->
<ul data-bind="foreach: myFilteredArray">
  <!-- myFilteredArray is still in scope -->
</ul>
<!-- /ko --> 

(I haven't actually tested this exact code)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants