dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

Здравствуйте!
Есть форма:

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

<?php $form = ActiveForm::begin(); ?>
            <?= $form->field($model, 'category_id')->dropDownList($treeSelect->getTree($categories), ['prompt' => 'Select category']) ?>
            <div id="filters_result"></div>
<?php ActiveForm::end(); ?>
При выборе category_id я делаю аякс запрос подгрузить фильтры в виде селектов:
вот view аякс запроса:

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

<?php if(!empty($filters)):?>

<?php foreach ($filters as $filter): ?>
    <label><?=$filter->title?></label>
    <?php
    $items = ArrayHelper::map($filter->filters, 'id', 'title');
    $selection = null;
    foreach ($model->filter as $item_filter) {
        if(array_key_exists($item_filter->id, $items)) {
            $selection = $item_filter->id;
            break;
        }
    }
    $params = [
        'prompt' => 'Выберите',
        'class' => 'form-control'
    ];
    echo Html::dropDownList('Product[filter][]', $selection, $items, $params);
    ?>
<?php endforeach; ?>

<?php else:?>
    Выберите категорию с фильтрами!
<?php endif;?>
Вопрос, если бы я использовать мог в место Html::dropDownList использовать $form->field->dropDownList тогда бы я не прописывал название с моделью "Product[filter][]'" и мне бы не пришлось делать $selection . Но форма в форме подгруженная аяксом не может быть - это не правильно. В общим может быть есть более удачное решение второго кода - (подгрузка аяксом) чем я сделал. Мне кажет если бы это в теги $form = ActiveForm::begin(); было и инпуты шли $form->инпут то тода меньше бы было у меня в подгружаемой части кода аяксом.
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение yiiliveext »

В действии, которое вызываете ajax-ом делаете $form = new ActiveForm();
А дальше передаете $form и $model в представление, где вместо Html::dropDownList(...) выводите $form->field($model, 'filter')->dropDownList(...)
И список фильтров в контроллере формируйте, негоже такое в представлении делать.
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

yiiliveext писал(а): 2019.12.10, 01:16 делаете $form = new ActiveForm();
Спасибо большое, помогло!
Сделал так в коде который ajax подгружает:

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

<?php if (!empty($filters)): ?>

    <?php foreach ($filters as $key => $filter): ?>
        <?php
        $items = ArrayHelper::map($filter->filters, 'id', 'title');
        $params = [
            'prompt' => 'Выберите',
        ];
        $form = new ActiveForm();
        echo $form->field($model, '[]filter')->dropDownList($items, $params)->label($filter->title);
        ?>
    <?php endforeach; ?>

<?php else: ?>
    Выберите категорию с фильтрами!
<?php endif; ?>
в контроллере так:

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

        $model = $this->findModel($id);

        if (Yii::$app->request->isPost) {
            $post = Yii::$app->request->post();
            $post['Product']['filter'] = array_diff(array_column($post['Product'], 'filter'), ['']);
            if ($model->load($post) && $model->save()) {
                return $this->redirect(['view', 'id' => $model->id]);
            }
        } else {
            return $this->render('update', [
                'model' => $model,
            ]);
        }
    }
Смущает это

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

$post['Product']['filter'] = array_diff(array_column($post['Product'], 'filter'), ['']);
. Это из за того что с вьюхи идет такое свойство []filter , пробовал так filter[] - тогда сохраняет без этой строчки в контроллере

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

$post['Product']['filter'] = array_diff(array_column($post['Product'], 'filter'), ['']);
, но потом при редактировании не подставляет данные в селекты, а подставляет их только если свойства такое []filter - но с этим свойством надо строчку в контроллере разбора массива. Думал может можно использовать как то

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

Model::loadMultiple
- но с ним у меня эту задачу решить не получилось.
Для сохранения этих фильтров я использую поведение

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

"la-haute-societe/yii2-save-relations-behavior": "*"
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение yiiliveext »

webplus писал(а): 2019.12.10, 15:31 но потом при редактировании не подставляет данные в селекты,
Об этом подробнее, не понял что имеется в виду.
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

yiiliveext писал(а): 2019.12.10, 18:05
webplus писал(а): 2019.12.10, 15:31 но потом при редактировании не подставляет данные в селекты,
Об этом подробнее, не понял что имеется в виду.
Вот

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

echo $form->field($model, '[]filter')->dropDownList($items, $params)->label($filter->title);
при использовании свойства []filter данные с модели подставляются в инпут, вот скрин: Изображение - это при редактировании,
но при []filter не сохраняет поведение данные, мне приходится делать

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

$post['Product']['filter'] = array_diff(array_column($post['Product'], 'filter'), ['']);
, а вот если использовать $form->field($model, 'filter[]'), т.е. с filter[] то не заполняются те селекты значениями из модели что я фото прикрепил (т.е. при редактировании). Но при этом сохранение происходит без этой фигни

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

$post['Product']['filter'] = array_diff(array_column($post['Product'], 'filter'), ['']);
. т.е. как надо все. , но инпуты не заполняются с filter[], а заполняются только с []filter
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение yiiliveext »

Скиньте пример значения $post['Product']
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

yiiliveext писал(а): 2019.12.10, 18:05 Скиньте пример значения $post['Product']

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

            $post = Yii::$app->request->post();
            print_r($post);die;
Array ( [Product] => Array ( [category_id] => 16 [title_ru] => fdfgffgffg [title_uk] => [title_en] => [description_ru] => [description_uk] => [description_en] => [price] => 6666.00 [0] => Array ( [filter] => 3 ) [1] => Array ( [filter] => 6 ) ) )
потом мне приходится делать:

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

            $post['Product']['filter'] = array_diff(array_column($post['Product'], 'filter'), ['']);
а если бы инпуты были filter[] т.е.

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

        echo $form->field($model, 'filter[]')->dropDownList($items, $params)->label($filter->title);

то было бы

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

Array ( [Product] => Array ( [category_id] => 16 [title_ru] => fdfgffgffg [title_uk] => [title_en] => [description_ru] => [description_uk] => [description_en] => [price] => 6666.00 [filter] => Array ( [0] => 3 [1] => 5 ) ) )
но при редактировании продукта в инпуты фильтров не подставляются значения, потому что в форме используется свойства filter[] и с ней сохраняется но не выводится при редактировании, а выводится при редактировании с []filter - но с этим не сохраняется и приходится костыль перевода массива писать

В модели у меня:

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

    public function getFilter()
    {
        return $this->hasMany(Filter::className(), ['id' => 'filter_id'])->viaTable(ProductFilter::tableName(), ['product_id' => 'id']);
    }
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение yiiliveext »

Если используете "la-haute-societe/yii2-save-relations-behavior": "*"
то попробуйте так.

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

<?php if (!empty($filters)): ?>
    <?php $i = 0;
        foreach ($filters as $key => $filter){
            $items = ArrayHelper::map($filter->filters, 'id', 'title');
            $params = [
               'prompt' => 'Выберите',
            ];
            $form = new ActiveForm();
            echo $form->field($filter, "[$i]id")->dropDownList($items, $params)->label($filter->title);
            $i++;
        } 
    ?>

<?php else: ?>
    Выберите категорию с фильтрами!
<?php endif; ?>
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

yiiliveext писал(а): 2019.12.10, 19:34 Если используете "la-haute-societe/yii2-save-relations-behavior": "*"
ну без этого перед $model->load($post) && $model->save()

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

           $post['Product']['filter'] = array_diff(array_column($post['Product'], 'filter'), ['']);
не сохраняет.
Вот смотрел инпут listCheckbox так там все инпуты типа id[] - т.е. скобки в конце.
Если сделать скобки в конце в dropDownList то сохраняет правильно, но при редактировании данными из модели он не selected
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение yiiliveext »

Вы точно мой код полностью скопировали?
Эта строчка не нужна $post['Product']['filter'] = array_diff(array_column($post['Product'], 'filter'), ['']);
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

yiiliveext писал(а): 2019.12.10, 19:53 Вы точно мой код полностью скопировали?
да, только не id в инпуте, а filter. т.е. [$i]filter
потому что у меня в модели:
в rules

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

[['filter'], 'safe'],
в поведении

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

    public function behaviors()
    {
        return [
            'saveRelations' => [
                'class' => SaveRelationsBehavior::className(),
                'relations' => [
                    'filter',
                ],
            ],
        ];
    }
и данные которые в форму подставляются из модели

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

    public function getFilter()
    {
        return $this->hasMany(Filter::className(), ['id' => 'filter_id'])->viaTable(ProductFilter::tableName(), ['product_id' => 'id']);
    }
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

yiiliveext писал(а): 2019.12.10, 19:53 Вы точно мой код полностью скопировали?
при вашем коде у dropDownList name равно "Filter[0][id]" и т.д.
А у меня экшен:

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

    public function actionUpdate($id)
    {
        $model = $this->findModel($id);

        if (Yii::$app->request->isPost) {
            $post = Yii::$app->request->post();
            //$post['Product']['filter'] = array_diff(array_column($post['Product'], 'filter'), ['']);
            if ($model->load($post) && $model->save()) {
                return $this->redirect(['view', 'id' => $model->id]);
            }
        } else {
            return $this->render('update', [
                'model' => $model,
            ]);
        }
    }
- я работаю с моделью Product, а если у меня будет идти Filter[0][id] то мне тогда как то логику экшена надо переписать - пока не пойму как - как то?
Я выше топиком описал какие у меня поведения в модели Product
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение yiiliveext »

webplus писал(а): 2019.12.10, 20:29 - я работаю с моделью Product, а если у меня будет идти Filter[0][id] то мне тогда как то логику экшена надо переписать - пока не пойму как - как то?
Я выше топиком описал какие у меня поведения в модели Product
Так и надо, читайте документацию по save relaition behaivior, там есть пример, вам нужно подключить SaveRelationsTrait

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

class Product extends ActiveRecord
{
    use SaveRelationsTrait;
    ....
}
Либо, если не подключать трейт, можно дополнительно сделать $model->loadRelations(Yii::$app->getRequest()->post())
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

yiiliveext писал(а): 2019.12.10, 23:08 Так и надо, читайте документацию по save relaition behaivior, там есть пример, вам нужно подключить SaveRelationsTrait

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

class Product extends ActiveRecord
{
    use SaveRelationsTrait;
    ....
}
Либо, если не подключать трейт, можно дополнительно сделать $model->loadRelations(Yii::$app->getRequest()->post())
Решил проблему мультиселектом:
вот код:

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

<?php if (!empty($filters)): ?>

    <p>
        <?php
        echo Html::a('Очистить', '#', ['id' => 'clear-filters', 'class' => 'btn btn-danger']);
        ?>
    </p>
    <?php 
    $items = [];
    foreach ($filters as $key => $filter): ?>
        <?php
        $items[$filter->title] = ArrayHelper::map($filter->filters, 'id', 'title');
        ?>
    <?php endforeach; ?>

    <?php
    $params = [
        //'prompt' => 'Выберите',
        'multiple' => 'multiple',
        'size' => 15
    ];
    $form = new ActiveForm();
    echo $form->field($model, 'filter')
        ->dropDownList($items, $params)
        ->label(false)
        ->hint('Для выбора нескольких фильтров удерживайте клавишу Ctrl');

    ?>

<?php else: ?>
    <?php
    $form = new ActiveForm();
    echo $form->field($model, 'filter')->hiddenInput(['value' => ''])->label(false);
    ?>
    Выберите категорию с фильтрами!
<?php endif; ?>
вот скрин как получилось Изображение
само свойство в хтмл мулитиселекта называется так: Product[filter][]
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

yiiliveext писал(а): 2019.12.10, 19:34 Если используете "la-haute-societe/yii2-save-relations-behavior": "*"
Здравствуйте!
Сделал так как вы привели пример:

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

    <?php $i = 0;
    foreach ($filters as $filter){
        $items = ArrayHelper::map($filter->filters, 'id', 'title');
        $params = [
            'prompt' => 'Выберите',
        ];
        $form = new ActiveForm();
        echo $form->field($filter, "[$i]id")->dropDownList($items, $params)->label($filter->title);
        $i++;
    }
    ?>
в модели Product подключил:

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

use SaveRelationsTrait;
Если option в select выбран, то связи сохраняются, а если ничего не выбрано, т.е. стоит 'prompt' => 'Выберите' то пытается создастся запись в таблице filters , а потом с ней связи в таблице product_filter . Мне нужно только сохранение выбранных dropDownList, но если ничего не выбрано то создавать запись в тбл.filters ни нужно. Наверно все же опять перед передачей в load метода пост нужно делать удаление с пустыми значениями, чтобы новый фильтр ни создавался
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение yiiliveext »

Правила модели Filter не должны давать сохранять пустую модель
Аватара пользователя
webplus
Сообщения: 336
Зарегистрирован: 2012.02.24, 22:05

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение webplus »

yiiliveext писал(а): 2019.12.11, 13:29 Правила модели Filter не должны давать сохранять пустую модель
в модели Filter - rules прописано.

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

    public static function tableName()
    {
        return 'filter';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['parent_id'], 'default', 'value' => null],
            [['parent_id', 'category_id'], 'integer'],
            [['title_ru', 'category_id'], 'required'],
            [['title_ru', 'title_uk', 'title_en'], 'string', 'max' => 255],
        ];
    }
Я сделал echo $form->errorSummary($model); и мне выдаются ошибки валидации! И они не дают сохранить без выбранных фильтров!
Сайт по работе в Украине: https://jobis.com.ua/. Сайт по поиску строителей: https://stroyzakaz.com.ua/
Создание сайтов в Киеве: https://webplus.com.ua/ по доступной цене.
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: dropDownList подгруженный аяксом нужно взять в ActiveForm::begin();

Сообщение yiiliveext »

Вообще-то это немного не так делается. Вы должны валидировать фильтры на клиенте и не давать сохранять пустой, а давать возможность удалить фильтр, если его нет у товара. Так же нужна возможность и добавить фильтр динамически.
Но в вашем случае можете таки перед load() удалить поля id c пустым значением, если не хотите делать полноценную реализацию.
Ответить