laravel 在blade和laravel中简化这个@foreach/if

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29498084/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 11:18:35  来源:igfitidea点击:

simplify this @foreach/if in blade and laravel

phplaravellaravel-5

提问by Ronnie

I am fairly new to laravel (L5 specifically) and I am making my own version of a todo app rather than following one of the tutorials out there. I've learned quite a bit so far but the way I have this piece of code currently laid out in my blade template makes me think their might be a simpler way of doing this.

我对 laravel(特别是 L5)相当陌生,我正在制作自己的待办事项应用程序版本,而不是遵循那里的教程之一。到目前为止,我已经学到了很多东西,但是我目前在刀片模板中布置这段代码的方式让我认为它们可能是一种更简单的方法。

My TodosController@indexfn is

我的TodosController@indexfn 是

public function index()
{
    $todos = Todo::get();
    return view('todos', compact('todos'));
}

App\Todoextends an Eloquentmodel which makes data handling very easy!

App\Todo扩展了一个Eloquent模型,使数据处理变得非常容易!

My route is:

我的路线是:

Route::bind('todos', function($slug)
{
    return App\Todo::whereSlug($slug)->first();
});

So my page simply displays an unorded list of "todos". I want to have two separate lists. One that is for completed todos and one for incomplete. My blade template looks like this so far and looks a bit messy. Also I am looping over the results twice which is where I think I can improve on.

所以我的页面只是显示一个无序的“todos”列表。我想要两个单独的列表。一种用于已完成的待办事项,一种用于未完成的。我的刀片模板到目前为止看起来像这样,看起来有点凌乱。此外,我将结果循环两次,这是我认为可以改进的地方。

<h3>Incomplete</h3>
<ul>
    @foreach ($todos as $todo)
        @if ($todo->completed == 'No')
            <li>
                <a href="{{ route('todos.show', [$todo->slug]) }}">{{ $todo->title }}</a>
            </li>
        @endif
    @endforeach
</ul>

<h3>Complete</h3>
<ul>
    @foreach ($todos as $todo)
        @if ($todo->completed == 'Yes')
            <li>
                <a href="{{ route('todos.show', [$todo->slug]) }}">{{ $todo->title }}</a>
            </li>
        @endif
    @endforeach
</ul>

Any suggestions to simplify that blade template?

有什么建议可以简化刀片模板吗?

回答by Martin Bean

DRY your code out. You could streamline it by moving the actual item mark-up to a partial template since it's repeated in both the complete and incomplete lists:

干掉你的代码。您可以通过将实际项目标记移动到部分模板来简化它,因为它在完整和不完整列表中重复:

<h3>Incomplete</h3>
<ul>
    @foreach ($todos as $todo)
        @if ($todo->completed == 'No')
            @include('partials.items.todo')
        @endif
    @endforeach
</ul>

<h3>Complete</h3>
<ul>
    @foreach ($todos as $todo)
        @if ($todo->completed == 'Yes')
            @include('partials.items.todo')
        @endif
    @endforeach
</ul>

And partials.items.todowould look like this:

而且partials.items.todo应该是这样的:

<li>
    <a href="{{ route('todos.show', [$todo->slug]) }}">{{ $todo->title }}</a>
</li>

I would also re-factor your loops. Instead of looping over the same list twice, you could split them in your controller:

我也会重新考虑你的循环。您可以将它们拆分到控制器中,而不是在同一个列表上循环两次:

public function index()
{
    $todos = Todo::where('user_id', '=', Auth::id())->get();

    $complete = $todos->filter(function ($item) {
        return $item->completed = 'Yes';
    });

    $incomplete = $todos->filter(function ($item) {
        return $item->completed = 'No';
    });

    return view('todos', compact('complete', 'incomplete'));
}

Looking at your Todomodel, I'd also make your completedcolumn in the database a boolean field instead of a column containing “Yes” or “No” strings. You could then cast that column value to a proper boolean (since MySQL doesn't have a native boolean field type):

查看您的Todo模型,我还会completed将数据库中的列设为布尔字段,而不是包含“是”或“否”字符串的列。然后,您可以将该列值转换为适当的布尔值(因为 MySQL 没有本机布尔字段类型):

class Todo extends Model
{
    protected $casts = [
        'completed' => 'boolean',
    ];

    public function isComplete()
    {
        return $this->completed;
    }
}

And then re-factor your controller action to use this instead:

然后重构您的控制器操作以使用它:

public function index()
{
    $todos = Todo::where('user_id', '=', Auth::id())->get();

    $complete = $todos->filter(function ($item) {
        return $item->isComplete() === true;
    });

    $incomplete = $todos->filter(function ($item) {
        return $item->isComplete() === false;
    });

    return view('todos', compact('complete', 'incomplete'));
}

You could even move those collection filters to a custom TodoCollectionclass:

您甚至可以将这些集合过滤器移动到自定义TodoCollection类:

use Illuminate\Database\Eloquent\Collection as EloquentCollection;

class TodoCollection extends EloquentCollection
{
    public function complete()
    {
        return $this->filter(function ($item) {
            return $item->isComplete() === true;
        });
    }

    public function incomplete()
    {
        return $this->filter(function ($item) {
            return $item->isComplete() === false;
        });
    }
}

Sorry for the lengthy reply, but should give you food for though on how to re-factor your code.

抱歉回复太长,但应该为您提供有关如何重构代码的食物。

回答by Edgar Orozco

Only a bit simplified but...

只是稍微简化了一点,但是......

You can try in your controller:

您可以在控制器中尝试:

public function index()
{
    $completed = Todo::where('completed','Yes')->get();
    $incompleted = Todo::where('completed','No')->get();
    return view('todos', compact('completed', 'incompleted'));
}

in Your template:

在您的模板中:

<h3>Incomplete</h3>
<ul>
    @foreach ($incompleted as $todo)
            <li>
                <a href="{{ route('todos.show', [$todo->slug]) }}">{{ $todo->title }}</a>
            </li>
    @endforeach
</ul>

<h3>Complete</h3>
<ul>
    @foreach ($completed as $todo)
            <li>
                <a href="{{ route('todos.show', [$todo->slug]) }}">{{ $todo->title }}</a>
            </li>
    @endforeach
</ul>

Another approach using a subtemplate like this:

使用这样的子模板的另一种方法:

    //_list_todos.blade.php

    @foreach ($todos as $todo)
            <li>
                <a href="{{ route('todos.show', [$todo->slug]) }}">{{ $todo->title }}</a>
            </li>
    @endforeach

And your main template like this:

你的主模板是这样的:

<h3>Incomplete</h3>
<ul>
     @include('_list_todos',['todos'=>$incompleted] )
</ul>

<h3>Complete</h3>
<ul>
     @include('_list_todos',['todos'=>$completed] )
</ul>

The advantege to use a subtemplate like the last one is you can reuse the code, and simplify your main templates.

使用上一个子模板的好处是您可以重用代码,并简化您的主模板。