Добавление новых полей через ajax

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Аватара пользователя
Chelobaka
Сообщения: 214
Зарегистрирован: 2018.06.01, 09:54

Добавление новых полей через ajax

Сообщение Chelobaka »

Здравствуйте, у yii есть замечательная возможность загружать формы через ajax с валидаторами. У меня задача добавлять поля динамически.

Насколько я понимаю что бы валидация работала нужно создавать форму и её загружать. То есть отдельно поля добавить можно но обработчик о них знать ничего не будет.

Получается что нужно добавлять каждый раз новую форму но в итоге оставлять только одну кнопку для отправки. Но у меня не получилось сделать одну кнопку. Возможно вы знаете как?

Я попробовал и у меня получилось перегенерировать форму. То есть я собираю данные, отправляю и генерирую новую форму. Потому ее возвращаю и заменяю старую и все работает как надо. Но есть проблема, иногда форма может содержать значения selectbox с 200+ option и гонять это по сети особого желания нет. Поэтому надеюсь что есть все же способ добавлять именно поля.

Существующие дополнения динамических форм имеют существенный недостаток. У меня содержимое select-ов зависит от выбора в другом select а динамические формы создают html шаблон из которого делают клонов и получается я не могу изменить содержимое. Возможно вы знаете подходящий?

Использование встроенного валидатора уии, то есть вставлять html и навешивать на него ошибки тоже затратно, нужно либо передавать интернационализированные тексты ошибок либо ставить транслятор для js.
Аватара пользователя
proctoleha
Сообщения: 298
Зарегистрирован: 2016.07.10, 19:00

Re: Добавление новых полей через ajax

Сообщение proctoleha »

Вот смотрите. Не знаю с чего начать, может будет сумбурно.

1. Если у вас 200+ полей в select, может стоит задуматься, что данные в них тоже подтягивать через ajax?

2. В Yii2 уже есть такая интересная фича: табличный ввод данных
Но, слегка, чуть-чуть, возможно, недоделанная. Если со стороны сервера мы можем использовать Model::loadMultiple() и Model::validateMultiple() для работы с динамически добавленными данными, то как это делать в жизни мануал умалчивает. Эта часть страницы находится в разработке.

Т.е. инструмент есть, а как им пользоваться в реальной жизни непонятно.

Попробуем формализовать решение задачи:

1. Мы хотим, чтобы при нажатии на Плюсик, у нас форму добавлялось одно, или несколько полей
2. При нажатии на Минус, любое, заранее обозначенное поле должно корректно удаляться.
3. Все это безобразие должно валидироваться, хотя бы на стороне сервера, и если валидация не прошла, в форму должны приходить все данные, которые ввел юзер, с сообщениями об ошибках.

Есть ли готовые решения? Есть https://github.com/unclead/yii2-multipl ... put-widget
Но, когда дело дошло до боевого применения, и его покрутил, и понял, что он мне не подходит. Для конкретно моей боевой задачи.

А почему ничего нет, толком? А потому, что Yii велик, Yii могуч, но некоторые его инструменты ужасны, когда нужно сделать шаг в сторону, от генеральной линии партии, и решить нестандартную задачу.

В данном случае речь идет об ActiveForm. Удобнейшая штука, несколько строк кода, и вот тебе и js, и css, и вообще все здорово. По большому счету, и фиг с ним, что туда bootstrap 3 гвоздями намертво приколочен, это проблему Yii2 в целом, не только ActiveForm.

Проблема в другом. Вот нам потребовалось динамически работать с формой, а у нас там еще и Select2 от Картика зашит, и что наступает? Правильно - полная опа. А всего сделали шаг в сторону динамической работы с данными в форме.

Если использовать ActiveForm, при решении данной задачи, то, как написал ТС, остается только одно - гонять тонны html кода в обе стороны. Вот мы нажали на Плюсик - серверу летит запрос: Эй, вот тебе вся наша форма, добавь нам после этого места еще одно, или несколько полей.
Легко, отвечает сервер. Вот тебе renderAjax, вставь этот кусок html, со всеми скриптами, вместо своей формы. Я правда тебе вообще все скрипты повторно загрузил, и дебагер, в том числе, но это же ерунда?

Ну, в принципе, на одном из боевых проектов, у меня так и работает, и работает хорошо, и ничего особо страшного в этом нет. Как обычно бывает, задачу надо было сделать вчера, быстрей-быстрей.

А что нужно, чтобы в душе не царапало, чтобы всё было более-менее красиво? Уйти от общепринятых инструментов, и использовать Yii2 на более низком уровне. Чуть-чуть поработать ручками и головой.
Например:

1. Уйти от ActiveForm, использовать тот же прекрасный Html helper. Валидации на клиенте не будет? Но, если мы провалидируем на стороне сервера, и вернем клиенту заполненную форму с полями об ошибках, для него это будет критично?

2. Если какой-то виджет, например Select2 от Картика не вписывается, не удается его настроить так, как надо, для конкретной задачи, что нам мешает работать напрямую с jquery плагином Select2? Все документировано, все настраивается легко. К нам пришел через ajax, какой-то select, мы на него ручками повесили Select2, и вот все у нас в DOM дереве, все работает как надо.

Т.е. общий посыл, я думаю понятен. Ну а учебный пример для работы с динамически добавляемыми данными, у меня на гитхабе: https://github.com/ale10257/learning_task. Там реализовано все о чем я тут писал: уходим от ActiveForm, работаем напрямую с jquery плагином Select2, валидируем только на стороне сервера, возвращаем клиенту заполненную форму с ошибками. Пример учебный, смотрим код, спрашиваем если что непонятно.
Вот за что я не люблю линукс, так это за свои кривые, временами, руки
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Добавление новых полей через ajax

Сообщение yiiliveext »

proctoleha писал(а): 2019.11.01, 16:43 Проблема в другом. Вот нам потребовалось динамически работать с формой, а у нас там еще и Select2 от Картика зашит, и что наступает? Правильно - полная опа. А всего сделали шаг в сторону динамической работы с данными в форме.

Если использовать ActiveForm, при решении данной задачи, то, как написал ТС, остается только одно - гонять тонны html кода в обе стороны. Вот мы нажали на Плюсик - серверу летит запрос: Эй, вот тебе вся наша форма, добавь нам после этого места еще одно, или несколько полей.
Легко, отвечает сервер. Вот тебе renderAjax, вставь этот кусок html, со всеми скриптами, вместо своей формы. Я правда тебе вообще все скрипты повторно загрузил, и дебагер, в том числе, но это же ерунда?
Не надо гонять тонны html кода, с клиента идет GET запрос на добавление полей, назад возвращаются только нужные поля и валидаторы, которые вешаются на эти поля, сами поля добавляются в существующую форму. Для экономии трафика можно хранить шаблон полей на клиенте и подставлять индекс. После renderAjax все лишние скрипты чистятся. С select2 от картик все работает прекрасно.
Но можно, конечно, и без ActiveForm.
Аватара пользователя
Chelobaka
Сообщения: 214
Зарегистрирован: 2018.06.01, 09:54

Re: Добавление новых полей через ajax

Сообщение Chelobaka »

yiiliveext писал(а): 2019.11.01, 17:47
proctoleha писал(а): 2019.11.01, 16:43 Проблема в другом. Вот нам потребовалось динамически работать с формой, а у нас там еще и Select2 от Картика зашит, и что наступает? Правильно - полная опа. А всего сделали шаг в сторону динамической работы с данными в форме.

Если использовать ActiveForm, при решении данной задачи, то, как написал ТС, остается только одно - гонять тонны html кода в обе стороны. Вот мы нажали на Плюсик - серверу летит запрос: Эй, вот тебе вся наша форма, добавь нам после этого места еще одно, или несколько полей.
Легко, отвечает сервер. Вот тебе renderAjax, вставь этот кусок html, со всеми скриптами, вместо своей формы. Я правда тебе вообще все скрипты повторно загрузил, и дебагер, в том числе, но это же ерунда?
Не надо гонять тонны html кода, с клиента идет GET запрос на добавление полей, назад возвращаются только нужные поля и валидаторы, которые вешаются на эти поля, сами поля добавляются в существующую форму. Для экономии трафика можно хранить шаблон полей на клиенте и подставлять индекс. После renderAjax все лишние скрипты чистятся. С select2 от картик все работает прекрасно.
Но можно, конечно, и без ActiveForm.
Спасибо за ответ. Не совсем понял про возврат нужного валидатора.
Как мне вернуть валидатор на группу полей или вновь добавленное поле?
Аватара пользователя
Chelobaka
Сообщения: 214
Зарегистрирован: 2018.06.01, 09:54

Re: Добавление новых полей через ajax

Сообщение Chelobaka »

Вопрос так и остался открытым. Кроме как парсить responce вариантов валидатор получить нет(
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Добавление новых полей через ajax

Сообщение yiiliveext »

Валидаторы находятся в $form->attributes
Пакуйте в json и передавайте на клиент
Аватара пользователя
Chelobaka
Сообщения: 214
Зарегистрирован: 2018.06.01, 09:54

Re: Добавление новых полей через ajax

Сообщение Chelobaka »

yiiliveext писал(а): 2019.11.06, 19:58 Валидаторы находятся в $form->attributes
Пакуйте в json и передавайте на клиент
Действительно, валидаторы можно получить через метод getValidators().
Возвращает метод массив объектов. В JSON так:

Код: Выделить всё

[
  {
    "skipOnEmpty": false,
    "requiredValue": null,
    "strict": false,
    "message": "{attribute} cannot be blank.",
    "attributes": [
      "client_id",
      "country_id",
      "phone",
      "city",
      "street",
      "building",
      "apartment",
      "status"
    ],
    "on": [],
    "except": [],
    "skipOnError": true,
    "enableClientValidation": true,
    "isEmpty": null,
    "when": null,
    "whenClient": null
  }
]
При более детальном рассмотрении валидатора формы в HTML увидел такие параметры.
Они добавлены просто в HTML.

Код: Выделить всё


jQuery('#w0').yiiActiveForm([{
"id": "form-country_id",
"name": "form",
"container": ".field-form-package",
"input": "#form-package",
"validate": function(attribute, value, messages, deferred, $form) {
    yii.validation.required(value, messages, {
        "message": "Country ID cannot be blank."
    });
    yii.validation.number(value, messages, {
        "pattern": /^\s*[+-]?\d+\s*$/,
        "message":"Country ID must be an integer.",
        "skipOnEmpty": 1
    });
}

Тут не ясно как JSON валидаторов формы можно использовать в том виде как они есть.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Добавление новых полей через ajax

Сообщение yiiliveext »

в контроллере

Код: Выделить всё

foreach ($form->attributes as $attribute) {
            $attributes[] = json_encode($attribute);
        }
на клиенте

Код: Выделить всё

$.each(data.attributes, function (key, value) {
           var attribute = $.parseJSON(value);
           attribute.validate = eval("(function(){return " + attribute.validate.expression + ";})();"); 
           $("#product_form").yiiActiveForm("add", attribute);
       });
Аватара пользователя
Chelobaka
Сообщения: 214
Зарегистрирован: 2018.06.01, 09:54

Re: Добавление новых полей через ajax

Сообщение Chelobaka »

yiiliveext писал(а): 2019.11.11, 13:07 в контроллере

Код: Выделить всё

foreach ($form->attributes as $attribute) {
            $attributes[] = json_encode($attribute);
        }
на клиенте

Код: Выделить всё

$.each(data.attributes, function (key, value) {
           var attribute = $.parseJSON(value);
           attribute.validate = eval("(function(){return " + attribute.validate.expression + ";})();"); 
           $("#product_form").yiiActiveForm("add", attribute);
       });
$form->attributes - создаёт массив с пустыми значениями:
На валидатор это вообще не похоже.

Код: Выделить всё

Array
(
    [0] => null
    [1] => null
    [2] => null
    [3] => null
    [4] => null
    [5] => 10
    [6] => [{"box_id":null,"client_id":1,"product_id":null,"amount":null}]
)
Если использовать validators или getActiveValidators то возвращает что то похожее на валидатор но использовать это через eval не ясно как.

Код: Выделить всё

{

    "targetClass":"common\\models\\box\\Box",
    "targetAttribute":{
        "0":"box_id",
        "client_id":"user_id"
    },
    "targetRelation":null,
    "filter":null,
    "allowArray":false,
    "targetAttributeJunction":"and",
    "forceMasterDb":true,
    "attributes":[
        "box_id",
        "client_id"
    ],
    "message":"{attribute} is invalid.",
    "on":[
    ],
    "except":[
    ],
    "skipOnError":true,
    "skipOnEmpty":true,
    "enableClientValidation":true,
    "isEmpty":null,
    "when":null,
    "whenClient":null

}
$.each(data.attributes, function (key, value) {
От куда берется data.attribute?
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Добавление новых полей через ajax

Сообщение yiiliveext »

Сделаю демку на выходных и выложу ссылку на репозиторий, так проще будет.
Аватара пользователя
Chelobaka
Сообщения: 214
Зарегистрирован: 2018.06.01, 09:54

Re: Добавление новых полей через ajax

Сообщение Chelobaka »

yiiliveext писал(а): 2019.11.12, 16:01 Сделаю демку на выходных и выложу ссылку на репозиторий, так проще будет.
Это благородно с вашей стороны. Буду презнателен.
Ответить