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

Include index in each block helper, aka each_with_index #250

Closed
rbu opened this issue May 31, 2012 · 49 comments
Closed

Include index in each block helper, aka each_with_index #250

rbu opened this issue May 31, 2012 · 49 comments

Comments

@rbu
Copy link

rbu commented May 31, 2012

It would be really nice to have access to the index of an each iteration.
There are ready-to-use block helpers out there, but having this upstream would be nice.

I can provide a pull request if that helps.

See also

https://gist.github.com/1048968
https://gist.github.com/1966803
http://stackoverflow.com/questions/5021495/in-mustache-how-to-get-the-index-of-the-current-section

@mpetrovich
Copy link
Contributor

The index of the current array item has been available for some time now via @index:

{{#each array}}
    {{@index}}: {{this}}
{{/each}}

For object iteration, use @key instead:

{{#each object}}
    {{@key}}: {{this}}
{{/each}}

Here's a live example using the latest build:
http://jsfiddle.net/mpetrovich/gER9M/

@wycats wycats closed this as completed Oct 17, 2012
@nathanlogan
Copy link

Any chance of also getting an option for a 1-based index, in addition to the 0-based? Perhaps something like this:
{{@index-base-1}}

@mpetrovich
Copy link
Contributor

What's your use case?

@nathanlogan
Copy link

Good point, mpetrovich, I should have included that.

The use case is outputting a numbered array when <ol> isn't the best HTML choice. For example, I have a list of questions (contained in an array) that I want to output as a table of data (given that there are also questions associated to each one). So the output would be something like this (where the circles are radio buttons in the app):

Select the best answer to these questions

# Question True False
1. I like peanut butter. O O
2. I like Captain Kirk more than Captain Picard. O O

Make sense?

@mpetrovich
Copy link
Contributor

A generalized math helper might be an even better fit for your needs: http://jsfiddle.net/mpetrovich/wMmHS/

Then, you could just do:

{{#each questions}}
    {{math @index "+" 1}}
{{/each}}

@cfjedimaster
Copy link

I know this issue is closed, but would there ever be a case where you would output, to a 'regular' use, a list that started with 0? It may make sense as coders, but I can't imagine the general public wanting a list like that, and since this is for output, shouldn't it probably default to starting with 1?

@perlun
Copy link

perlun commented Mar 24, 2013

How do you use this when you use the {{#each foo in bar}} syntax? Seems like I get 'Cannot call method 'replace' of undefined' when trying to use it with that syntax. With the {{#each bar}} syntax, it works like it should.

Any ideas?

@mpetrovich
Copy link
Contributor

@perlun, could you paste the code in question?

@jokesterfr
Copy link

@mpetrovich adding a math helper is a bad good idea. The JSON model has to be modified in that case.

@mpetrovich
Copy link
Contributor

@jokesterfr Yes, agreed. It'd be nice to just be able to do this:

{{@index + 1}}

@perlun
Copy link

perlun commented Mar 26, 2013

@mpetrovich: Trying to do something like this. http://jsfiddle.net/plundberg/3c5Pv/

However, I'm not sure if the {{#each item in array}} is an EmberJS-extension or if this is supposed to work with Handlebars. (I'm using EmberJS in my "real" use case.)

@mpetrovich
Copy link
Contributor

@perlun I don't quite follow—why doesn't the first (working) template suffice?

@perlun
Copy link

perlun commented Mar 26, 2013

I prefer to use the {{#each item in array}} syntax, since it doesn't pollute the context. Makes it easier to access stuff from the parent scope. That's why I tend to use the latter syntax.

@travisdahl
Copy link

Just curious if there are any other know ways of accessing the key or index. the @ symbol causes parse errors in my current grails project. I was hoping I could use something like {{this.index}} but that doesn't work, and it makes sense why, index isnt a part of that object. Just curious if there was any other syntax.

@mpetrovich
Copy link
Contributor

@Index is currently the only way to access the current array index.

-Mike

Sent from my iPhone

On Mar 29, 2013, at 5:32 PM, Travis Dahl notifications@github.com wrote:

Just curious if there are any other know ways of accessing the key or index. the @ symbol causes parse errors in my current grails project. I was hoping I could use something like {{this.index}} but that doesn't work, and it makes sense why, index isnt a part of that object. Just curious if there was any other syntax.


Reply to this email directly or view it on GitHub.

@mickaeltr
Copy link

Is there a way to get the "index" or "key" of an upper level?

{{#each foo}}
    {{#each bar}}
        <!-- How to get the foo index here? -->
    {{/each}}
{{/each}}

This does not work:

@../index
../@index

Thanks!

@mpetrovich
Copy link
Contributor

@mickaeltr Unless we're using the wrong syntax, it looks like that's not possible yet: http://jsfiddle.net/Z9g2q/2/

Sounds like a great feature request :)

@mickaeltr
Copy link

@mpetrovich There we go: #491

@lifeinafolder
Copy link

For an Object like this:

  data: {
        one: "un",
        two: "deux",
        three: "trois"
    }

Could we use the each helper to print it out?

  {{#each data}}
    {{@key}} : this
  {{/each}}

Expected Output:

  one : un
  two : deux
 three : trois

Doesn't seem to be working for me with Handlebars rc3

@mpetrovich
Copy link
Contributor

You need to wrap "this" in double curly braces as well:

{{@key}}: {{this}}

Other than that, the syntax looks correct.

On May 6, 2013, at 2:07 PM, Rajat Mittal notifications@github.com wrote:

For an Object like this:

data: {
one: "un",
two: "deux",
three: "trois"
}
Could we use the each helper to print it out?

{{#each data}}
{{@key}} : this
{{/each}}
Expected Output:

one : un
two : deux
three : trois
Doesn't seem to be working for me with Handlebars rc3


Reply to this email directly or view it on GitHub.

@lifeinafolder
Copy link

@mpetrovich Failing JSFiddle: http://jsfiddle.net/gdXfN/29/

@lifeinafolder
Copy link

It would be nice to get an answer on the failing jsFiddle. Sorely missing this.

@mitar
Copy link

mitar commented Jul 3, 2013

I like the variables Django provides. So not just zero-based index but also others.

@FoxGit
Copy link

FoxGit commented Jul 31, 2013

Same problem as @lifeinafolder here. Any update available? :(

@bobjackman
Copy link

+1 for @lifeinafolder -- running into the same failure in 1.0.0

@machineghost
Copy link

I had to write a whole Handlebars helper:

register('plusOne', function(number) {
    return number + 1;
});

Just to be able to do:

{{plusOne @index}}

So that I could do:

Thing #{{plusOne @index}}

This seems like such a painfully obvious use case: please provide one-based indices! No one uses zero-based indices in the presentation layer; human beings like 1-based indices :)

@cfjedimaster
Copy link

Surprised this is still open. Would a pull request with this feature be ok? If so - I'll try taking a stab at adding it.

@cfjedimaster
Copy link

How is this a backwards compat issue, Mickael? This would be a new
variable.

On Sun, Jan 26, 2014 at 12:04 PM, Mickaël Tricot
notifications@gh.neting.ccwrote:

-1, for backward compatibility reasons


Reply to this email directly or view it on GitHubhttps://github.com//issues/250#issuecomment-33324928
.

Raymond Camden, Web Developer for Adobe

Email : raymondcamden@gmail.com
Blog : www.raymondcamden.com
Twitter: cfjedimaster

@mickaeltr
Copy link

Alright, then why not!
I would prefer having support for operators, that could do this, though:
{{@Index + 1}}

On 26/01/14 19:22, Raymond Camden wrote:

How is this a backwards compat issue, Mickael? This would be a new
variable.

@cfjedimaster
Copy link

So - it was - afaik - one line change:
base.js, line 123 is:

        data.index = i;

I then added

        data.indexPlusOne = i+1;

and it just plain worked. Maybe index1 would be nicer, but crap, it is time to end this thread. ;) Making a PR now.

@mitar
Copy link

mitar commented Jan 31, 2014

I would suggest to have same naming as Django. Because index is currently 0-based, maybe then index1?

@tomasdev
Copy link

👍 for {{@Index + 1}}

@cfjedimaster
Copy link

I should point out - my PR was rejected. Afaik this is not going to happen. :\

@machineghost
Copy link

Well that's good, because every developer I know shows their users:

  1. Item Unexpected string in simple template #1
  2. Item Escaping quotes #2

etc.

@rbu
Copy link
Author

rbu commented Feb 21, 2014

For reference, @cfjedimaster's PR is #720.

@rebase-master
Copy link

The @key, @Index doesn't work me either in the #each block helper. Any idea why is this so?
I need to use the index in my code.

@rebase-master
Copy link

Upgraded to latest version of handlebars.js and it works!

@paynecodes
Copy link

@steady-daddy Which syntax works?

@rebase-master
Copy link

@jpdesigndev - @Index works inside #each block helper with handlebars v1.3.0

@paynecodes
Copy link

@steady-daddy Sorry. I hadn't paid close enough attention to the original issue. I was thinking you had gotten an @index + 1 to work without additional helpers. Seems this didn't ever happen, so I just used a simple helper.

@rebase-master
Copy link

@jpdesigndev - No issues mate!

@anshou
Copy link

anshou commented Jul 23, 2014

Ended up at this issue due to needing this exact features: @Index + 1

I don't understand how this has not been added; using a source-1 counting scheme is preferred for user-facing content in all cases. People do not start counting at zero, computers do.

So, I solved this by installing the 'plusOne' @machineghost shared above.

So, thanks, @machineghost; at least you helped in this issue.

@machineghost
Copy link

Glad I could help. I started a new ticket to try and get the developer's attention back to this use case; hopefully it result in a legitimate (ie. not my hack) fix.

@ThomasGreiner
Copy link

Another way to achieve this is to use CSS counters which are supported by all major browsers.

@cssagogo
Copy link

Any way to set the start point for the index? The use case being setting a unique ID per row within view more paged UI? Below is a rough use case. Is there a way to set the index?

<div id="my-div{{math @index "+" 1}}">Item 1 - Page 1</div>
<div id="my-div{{math @index "+" 1}}">Item 2 - Page 1</div>
[ VIEW MORE BUTTON ]



<div id="my-div{{math @index "+" 1}}">Item 1 - Page 1</div>
<div id="my-div{{math @index "+" 1}}">Item 20 - Page 1</div>
<div id="my-div{{math @index "+" 1}}">Item 21 - Page 2</div>  <!-- How do I set to 21?
<div id="my-div{{math @index "+" 1}}">Item 40 - Page 2</div>
[ VIEW MORE BUTTON ]

@jokesterfr
Copy link

Common, why won't you modify the JSON object?
let's give an id and a label :

var obj = { pages: [
    { id: "my-div-1", label: "Item 1" },
    { id: "my-div-2", label: "Item 2" },
    { id: "my-div-3", label: "Item 3" }
]}

and use the following template:

{{#pages}}
<div id="{{id}}">{{label}}</div>
{{/pages}}

What the point with {{math @index + 1}} when you can construct your JSON object like you want? With plenty of JS features?

@aaronharding
Copy link

If it helps, this was my solution. I edited the execIteration function within the each helper.

handlebars-3.0.3, line 2375

...
data.index = index;
data.humanIndex = index + 1; // added
data.first = index === 0;
...

This could very easily be added in with a pull request.

@jblotus
Copy link
Contributor

jblotus commented Oct 16, 2015

+1 for one based index

@handlebars-lang handlebars-lang locked and limited conversation to collaborators Oct 16, 2015
@kpdecker
Copy link
Collaborator

Locking this thread as we are set on the implementation here. Zero-based index will continue to be exposed from the native implementation. Those that need a 1-based index should write a simple helper to add this value. With subexpressions that helper can be used as arguments to other helpers too so this provides the option to have one-based anywhere without the overhead of tracking another field in the iteration logic that may or may not be used or breaking existing templates.

Handlebars.registerHelper('addOne', function(value) {
  return value + 1;
});
Like This: {{addOne @index}} or {{helper (addOne @index)}}

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

No branches or pull requests