Динамичные input в форме (Laravel + jQuery)

Динамичные input в форме (Laravel + jQuery)

В этой заметке разберемся как добавлять динамически генерируемые поля input в форму. В качестве примера выполним следующую задачу, добавим список ссылок на «полезные ресурсы по теме» к новостям из примера, который мы сделали в статье про работу с изображениями в Laravel.

Заодно вспомним как использовать поля JSON в Laravel.

Напомню, наш шаблон формы использует Bootstrap 4 и jQuery.

Добавим к нашей таблице в базе данных со списком новостей поле links типа JSON, для этого создадим миграцию:

php artisan make:migration add_links_to_news_table --table=news

В файле миграции database/migrations/XXXX_XX_XX_XXXX_add_links_to_news_table.php в методе up() добавим поле links:

Schema::table('news', function (Blueprint $table) {
            $table->json('links')->default('[]');
        });

«->default('[]')» — этим мы указали, что по умолчанию в поле будет пустой массив.

Выполняем миграцию php artisan migrate

Далее в шаблон формы resources/views/news/create.blade.php, после поля для добавления картинки, добавим таблицу с полем для ввода полезных ссылок и кнопкой «Еще ссылка».

Так же внизу подключим jQuery и напишем небольшой код JavaScript, в итоге шаблон должен выглядеть так:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">

    <title>Добавление новости</title>
</head>
<body>

<div class="container">
    <div class="col-8">
        <h1>Добавить новость</h1>
        <form method="post" action="{{ route('news.store') }}" enctype="multipart/form-data">
            @csrf
            <div class="form-group">
                <label for="name">Название новости</label>
                <input type="text" class="form-control" id="name" name="name">
            </div>
            <div class="form-group">
                <label for="body">Содержание</label>
                <textarea class="form-control" id="body" rows="3" name="body"></textarea>
            </div>
            <div class="form-group">
                <label for="image">Картинка для новости</label>
                <input type="file" class="form-control-file" id="image" name="image">
            </div>
            <div class="form-group">
                <label>Ссылки на дополнительную информацию</label>
                <table class="table table-bordered" id="linksTable">
                    <tr>
                        <td><input type="text" name="links[link0]" placeholder="Введите ссылку" class="form-control name_list" /></td>
                    </tr>
                </table>
                <button type="button" name="add" id="add" class="btn btn-success">Еще ссылка</button>
            </div>
            <button type="submit" class="btn btn-primary">Добавить</button>
        </form>
    </div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>

<script type="text/javascript">

    var i = 0;

    $("#add").click(function(){

        ++i;

        $("#linksTable").append('<tr><td><input type="text" name="links[link'+i+']" placeholder="Введите ссылку" class="form-control" /></td><td><button type="button" class="btn btn-danger remove-tr">Удалить</button></td></tr>');
    });

    $(document).on('click', '.remove-tr', function(){
        $(this).parents('tr').remove();
    });

</script>
</body>
</html>

Перейдем на http://нашсайт/news/create и удостоверимся что все работает:

Форма добавления новости из статьи Динамичные input в форме (Laravel + jQuery)

Следующем этапом сделаем сохранение ссылок в базу данных.

Первым делом в файле модели app/News.php добавим links в переменную $fillable.

Далее в модели мы добавили свойство $casts.

С помощью свойства $casts автоматически будет преобразовываться поле links из JSON формата в массив. Подробнее можно почитать в документации https://laravel.com/docs/6.x/eloquent-mutators#array-and-json-casting

В итоге наша модель выглядит так:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class News extends Model
{
    protected $fillable = ['name', 'body', 'image', 'links'];


    protected $casts = [
        'links' => 'array',
    ];
}

Теперь можно протестировать добавление ссылок, если вы повторили все в точности за мной, должно заработать.

Добавьте для теста новость и пару ссылок ней.

Добавляем новость и пару ссылок для теста примера из статьи

Осталось добавить вывод дополнительных ссылок в списке новостей под картинкой, чтобы убедиться в работоспособности всего того, чего мы только что сделали.

Для этого переходим в шаблон списка новостей resources/views/news/index.blade.php

Немного его изменим, добавим в цикл новостей, цикл вывода ссылок:

@foreach($news as $item)
        <div class="col-8">
            <h2>{{ $item->name }}</h2>
            <p><img src="{{ Storage::url('image/news/thumbnail/'.$item->image) }}" alt=""></p>
            @foreach($item->links as $link)
                <p>{{ $link }}</p>
            @endforeach
        </div>
    @endforeach

Идем на отображение всех новостей http://нашсайт/news/ и проверяем:

Работает, появилась новость с дополнительными ссылками

Работает, появилась новость с дополнительными ссылками.

Хостинг для ваших проектов