Framework: [Proposal] Add current index in Blade template loops

Created on 24 Feb 2013  路  22Comments  路  Source: laravel/framework

I find myself pretty often adding $i = 0; above my @foreach loops then incrementing on each iteration. It would be nice if we could reference {{ index }} to return the current step of where we're at in the loop. It seems appropriate for a templating language. I understand this may open the door to other arbitrary indexing methods like {{ first }} and {{ last }}, in which case using https://packagist.org/packages/smarty/smarty may be a better choice anyways.

Most helpful comment

@juninhodeluca
wy2av4yajsdxs

All 22 comments

Sweet idea! Though, I'm not sure that's within the scope of how Blade was written to be honest.

Blade, when it compiles, simply replaces your openings, such as foreach with the PHP equivilent, e.g., @foreach ($foo as $bar) is simply preg_replace'd to be <?php foreach ($foo as $bar): ?>.

There's no object holding each iteration of the loop in the context of compilation, unfortunately :(. If you want that, I'd be jumping ship to a full templating engine such as, as you said, smarty, or twig or something. You can easily integrate these with L4.

I highly doubt this will happen. Blade is a simple templating language which basically just makes stuff you use in PHP shorter.

To get your index like you want with {{ index }} you just do {{ key($theArrayYouAreLoopingThrough) }}.

As @bencorlett noted, this would be quite difficult to do in Blade. Going to defer it for now.

I know this is old, but just for reference, why not just use @foreach ($array as $index => $value)?

Hahaha so true.

@franzliedke, @robclancy : That wouldn't work with an associative array like "loop" does in twig. loop always returns the numeric index even in an associative array, whereas key() or foreach will actually return the name of the key.

Welcome to PHP.

Useful workaround example while wait for solution

/* UsersController */
$data = [

    'users' => [  

          [
              'name' => 'Juninho',
              'family' => 'De Luca',
          ],
          [  
              'name' => 'Homer',
              'family' => 'Simpson',
          ],
          [  
              'name' => 'Bart',
              'family' => 'Simpson',
          ],
     ],

    'i' => 0,
];

return view('users.index', $data);


/* users/index.php */
@foreach ($users as $user)
    {{ $i ++ }}
@endforeach

@juninhodeluca
wy2av4yajsdxs

lol like I said: workaround ;)

@juninhodeluca a better workaround is simply put it in the view. It's view logic, afterall.

You can do it this way:

@foreach ($collection as $index => $element)
    {{$index}} - {{$element['name']}}
@endforeach

Source: http://stackoverflow.com/a/24149137/2049990

Solution

For anyone waiting for a solution, implement this in your AppServiceProvider:

<?php

namespace Stori\Providers;

use Auth;
use Blade;
use Hash;
use Illuminate\Support\ServiceProvider;
use Validator;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        /**
         * Does not support nesting
         */
        Blade::directive('index', function($expression) {
            return '<?php echo $index; ?>';
        });
        Blade::directive('foreachIndexed', function($expression) {
            return '<?php $index = 1; foreach' . $expression . ': ?>';
        });
        Blade::directive('endforeachIndexed', function($expression) {
            return '<?php $index++; endforeach; ?>';
        });
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Usage

@foreachIndexed($array as $key)
    @index
@endforeachIndexed

Solution #2

@foreach ($fields as $field)
    {{ array_search($field, array_keys($fields)) + 1 }}
@endforeach

@CzajekDC That will break once you nest these loops, though.

Yeah, you are right.
In a doc block should be "Do not nest!". Haha

EDIT: Updated the code with Solution #2. Added a DocBlock.

I am creating Blade directive in my service provider

\Blade::directive('var', function($expression) {
    $regex = "/\((['\"])([\w_]+)\\1,\s*([^\)]+)\)/";
    return preg_replace($regex, '<?php $$2 = $3; ?>', $expression);
 });

Then you can easily use it in your views

@var('i', 0)
@foreach (...)
    {{{ $i++ }}}
@endforeach

Sorry for bringing this once again, but thought it either could be useful for someone or someone will prove me why this is bad

This also works but looks very ugly:

{{{ '' != $i = 0 }}}
@foreach (...)
    {{{ $i++ }}}
@endforeach

I find something like this to work (laravel 5.2), unless that isn't what the op is looking for
@foreach($something as $key=>$value)
{{ $key }} then {{ $value }}
@endforeach

where the $something is something like this:

[{
  "id": 1,
  "foo_id": "1",
  "title": "Duh",
}]

It's been closed - it's already coming in 5.3 I believe.

Old thread but just to add it here as a reference for someone who found this post and looking for the answer as I did. This is now implemented in Laravel 5.3

The index can be accessed by using $loop variable.

Refer: https://laravel.com/docs/5.3/blade#the-loop-variable

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ThomHurks picture ThomHurks  路  75Comments

JosephSilber picture JosephSilber  路  176Comments

mrahmadt picture mrahmadt  路  61Comments

GrahamCampbell picture GrahamCampbell  路  139Comments

PheRum picture PheRum  路  112Comments