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

Scope and Context: Adding @first and @index to Object iteration #432

Open
Psykoral opened this issue Jan 18, 2018 · 5 comments
Open

Scope and Context: Adding @first and @index to Object iteration #432

Psykoral opened this issue Jan 18, 2018 · 5 comments

Comments

@Psykoral
Copy link

While stache has @key / %key / scope.key when iterating over an object using {{#each...}}, there are times when you don't want the key name, but the index iterator, as if it was an array. This is implemented in Handlebars v1.2.0 handlebars-lang/handlebars.js#661

Description:
You have an object with named keys:

myObject: {
  value () {
    return {
      a: [],
      b: [],
      c: [],
      d: []
    }
  }
}

Using scope.key will return a, b, c, or d. However, If you don't know the names, or that a is the first one, instead you want to understand the order and position of each item in the Object. Handlebars allows you to do the following:

{{#each myObject}}
    {{#if @first}} 
        <h2>{{@index}}</h2>
    {{else}}
        <h2>Not the first item</h2>
    {{/if}}
{{/each}}

In the above scenario, @first would confirm it's the first item in the object, and @index would print 0

From http://handlebarsjs.com/builtin_helpers.html :

The first and last steps of iteration are noted via the @FIRST and @last variables when iterating over an array. When iterating over an object only the @FIRST is available.

@justinbmeyer
Copy link
Contributor

it's probably straightforward to do this as a helper now:

registerHelper("first", function(options){
  return options.scope.get("%index") === 0
})
/// this isn't going to perform great though
registerHelper("last", function(options){
  return options.scope.get("%index") === scope.get("..").length
})

@Psykoral
Copy link
Author

Awesome, thanks for the helper, I can certainly do that for now.

Though is it also easy enough to add into the product? It's probably something useful that a lot of people would take advantage of, and considering that Handlebars implemented it 3 major versions ago it might be beneficial to keep the can-stache items up to par.

@Psykoral
Copy link
Author

Actually, after testing this, this still only works with Array's and not Objects.

JS:

testArray: {
  value () {
    return ['one', 'two', 'three']
  }
},
testObject: {
  value () {
    return {
      one: 'one',
      two: 'two',
      three: 'three'
    }
  }
}

Stache:

{{#each testArray}}
  <h2> First testArray? {{first}}</h2>
{{/each}}
{{#each testObject}}
  <h2> First testObject? {{first}}</h2>
{{/each}}

Outcome:

First testArray? true
First testArray? false
First testArray? false
First testObject? false
First testObject? false
First testObject? false

With arrays it's fine, but we could already do {{#eq @index 0}} anyway. I'm looking for the Object support for it being the 'first item in the object' without having to know the key name of it. This is what @first does for an Object in Handlebars.

@justinbmeyer
Copy link
Contributor

Why do you loop through objects in this way? Looping through key-values has been 2nd-class priority for CanJS. Understanding use cases for this would help prioritize it.

@Psykoral
Copy link
Author

I have a component that I reuse in several different scenarios, all of which I send it a similar stack of data, but a lot of times they have different key names depending on the situation. For any given Object I send it, I need to know if this is the first one, because in this case I'm trying to add a checked value to an input tag if we're on the first item of of an Object.

If an {{#each}} tag essentially can loop through an object in order just like it would do an Array, then can't it also return an index of "which one we're on now"? Seems to be the same use case as this PR, and looks fairly easy enough to implement handlebars-lang/handlebars.js#661

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

No branches or pull requests

3 participants