ActiveForm, REST API, dropdownList

Всё что касается построения API
Ответить
medinsky
Сообщения: 4
Зарегистрирован: 2018.03.02, 11:25

ActiveForm, REST API, dropdownList

Сообщение medinsky »

Здравствуйте, существует такой вопрос.

Предметная область: Сервисные центры по обслуживанию по республике.
Каждый сервисный центр имеет адрес: area_id, city_id, street_id.

Пытаюсь сделать чтобы при изменении записи, в dropdownlist от activeForm устанавливались значения.
Всё бы ничего, но загрузка данных в dropdownlist идёт из API с другого сервера. Для реализации подобного на странице просмотра всех существующих сервисных центров, я писал js-ку, которая при загрузке страницы, загружала списки областей, городов и улиц в поиск сверху, а дальше, после загрузки, брала значение из GET массива и подставляла его в списки. Делал так:

для страницы service-center/index:

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

'use strict';

let city = $('select[name="ServiceCenterSearch[city_id]"]'); //для более короткого имени
let area = $('select[name="ServiceCenterSearch[area_id]"]');
let street = $('select[name="ServiceCenterSearch[street_id]"]');

$_GET['area_id'] = $_GET['ServiceCenterSearch[area_id]']; //для более короткого имени
$_GET['city_id'] = $_GET['ServiceCenterSearch[city_id]'];
$_GET['street_id'] = $_GET['ServiceCenterSearch[street_id]'];

area.change(function () {
    city.html('');
    city.val('');
    loadCities(area.val(), city, undefined, { 'prompt': true });
});

city.change(function () {
    street.html('');
    street.val('');
    loadStreets(city.val(), street, undefined, { 'prompt': true });
});

getAreas();

if (typeof $_GET['area_id'] !== 'undefined' && $_GET['area_id']!=='' && $_GET['area_id']!=='0') {
    getCities();
}

if (typeof $_GET['city_id'] !== 'undefined' && $_GET['city_id']!=='' && $_GET['city_id']!=='0') {
    getStreets();
}

function getAreas() {
    loadAreas(area, $_GET['area_id'], { 'prompt': true });
}

function getCities() {
    loadCities($_GET['area_id'], city, $_GET['city_id'], { 'prompt': true });
}

function getStreets() {
    loadStreets($_GET['city_id'], street, $_GET['street_id'], { 'prompt': true });
}
и это всё прекрасно работало, т.к. значения брались из строки url, и вставлялись как надо туда после прогрузки списков.
в переменной $_GET находятся распарсеные в ассоциативный массив параметры из URL. несмотря на именование, это Javascript. Просто сделал так.

Сами функции loadAreas, loadCities, loadStreets - это функции, которые возвращают промисы с данными.
Вот пример такой функции: (другие сделаны аналогично)

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

function loadCities(area = 3, targetElement, defValue, settings = []) {
    let fetchCities = fetch(MICRON_ADDR + '/belarus/areas/' + area + '/cities', {
        method: 'GET'
    });

    return fetchCities
        .then(response => response.json())
        .then(cities => {
            console.log(cities);
            if (cities) {
                let options = [];
                if (settings['prompt']) {
                    options.push(document.createElement('OPTION'));
                }
                for (let i=0; i<cities.length; ++i) {
                    let option = document.createElement('OPTION');
                    option.value = cities[i].cityId;
                    option.text = cities[i].cityName + ' ' + cities[i].cityTypeName+ ' (' + cities[i].district + ')';
                    options.push(option);
                }
                targetElement.html(options);
                console.log("Загрузили список городов");

                if (typeof defValue !== 'undefined') {
                    targetElement.val(defValue);
                }
            }
            return cities;
        })
        .catch(err => {
            console.error(err);
        });
}
функция если получает значение по умолчанию, то устанавливает его для списка когда тот прогрузится.

Теперь я начал делать страницу редактирования подобного сервисного центра. У меня всё также есть эти списки, но я не совсем понимаю откуда мне взять данные по модели и как и где их установить для списков как значения по умолчанию. При опять же учёте того, что данные по областям, городам и улицам, грузятся из REST API с другого сервера. Ведь теперь все данные передаются через POST, и модель я нахожу только по переданному в $_GET id сервисного центра по адресу /service-center/update?id=1
Меня сразу смутил и поставил в ступор тот вариант, что я не хочу в GET передавать ещё id области, города, улицы. ведь всё что надо по модели я получаю по id.

мой экшен апдейт:

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

    public function actionUpdate($id)
    {
        $modelServiceCenter = $this->findModel($id);
        $modelAddress = Address::findOne(['object_id' => $modelServiceCenter->object_id, 'object_type_id' => $modelServiceCenter->object_type_id]);

        if ($modelServiceCenter->load(Yii::$app->request->post()) && $modelServiceCenter->save() && $modelAddress->load(Yii::$app->request->post()) && $modelAddress->save()) {
            return $this->redirect(['view', 'id' => $modelServiceCenter->object_id]);
        }

        return $this->render('update', [
            'modelServiceCenter' => $modelServiceCenter,
            'modelAddress' => $modelAddress
        ]);
    }
    
адрес сервисного центра находится в отдельном файле _address.php, который я включаю в страницу редактирования, передавая сюда $modelAddress

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

use yii\helpers\Html;
use yii\widgets\ActiveForm;

/* @var $this yii\web\View */
/* @var $modelAddress app\models\Address */
/* @var $form ActiveForm */
?>
<div class="includes-_address">

    <div class="row">

        <div class="col-md-4">
            <?= $form->field($modelAddress, 'area_id')->dropDownList([], [
                'class' => 'form-control',
                ''
            ]) ?>
        </div>
        <div class="col-md-4">
            <?= $form->field($modelAddress, 'city_id')->dropDownList([], [
                'class' => 'form-control',
            ]) ?>
        </div>
        <div class="col-md-4">
            <?= $form->field($modelAddress, 'street_id')->dropDownList([], [
                'class' => 'form-control',
            ]) ?>
        </div>

    </div>

    <div class="row">

        <div class="col-md-2">
            <?= $form->field($modelAddress, 'house_number')->input('number') ?>
        </div>
        <div class="col-md-2">
            <?= $form->field($modelAddress, 'house_letter')->dropDownList([], [
                'class' => 'form-control',
            ]) ?>
        </div>

        <div class="col-md-2">
            <?= $form->field($modelAddress, 'housing_number')->input('number') ?>
        </div>
        <div class="col-md-2">
            <?= $form->field($modelAddress, 'housing_letter')->dropDownList([], [
                'class' => 'form-control',
            ]) ?>
        </div>

        <div class="col-md-2">
            <?= $form->field($modelAddress, 'flat_number')->input('number') ?>
        </div>
        <div class="col-md-2">
            <?= $form->field($modelAddress, 'flat_letter')->dropDownList([], [
                'class' => 'form-control',
            ]) ?>
        </div>

    </div>


    <?= $form->field($modelAddress, 'house') ?>
    <?= $form->field($modelAddress, 'housing') ?>
    <?= $form->field($modelAddress, 'flat') ?>
    <?= $form->field($modelAddress, 'post_code')->input('number') ?>
    <?= $form->field($modelAddress, 'comment')->textarea([
        'class' => 'form-control v-resize',
        'rows' => 5,
        'cols' => 100,
    ]) ?>

</div><!-- includes-_address -->
а в форме это выглядит так:

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


use yii\helpers\Html;
use yii\bootstrap\ActiveForm;
use app\models\Catalog;

/* @var $this yii\web\View */
/* @var $modelServiceCenter app\models\ServiceCenter */
/* @var $modelAddress app\models\Address */
/* @var $form yii\bootstrap\ActiveForm */
?>

<div class="service-center-form container">

    <?php $form = ActiveForm::begin(); ?>

    <div class="row">

        <div class="col-md-3">
            <?= $form->field($modelServiceCenter, 'object_type_id')->dropDownList(Catalog::getServiceCenterTypes()) ?>
        </div>

        <div class="col-md-4">
            <?= $form->field($modelServiceCenter, 'object_name')->textInput(['maxlength' => true]) ?>
        </div>

        <div class="col-md-4">
            <?php
            if ($modelServiceCenter->isNewRecord) {
                $modelServiceCenter->disable = 0;
            } else {
                echo $form->field($modelServiceCenter, 'disable')->radioList([
                    0 => "Нет",
                    1 => "Да"
                ], [
                    'class' => 'ml-2',
                    'item' => function($index, $label, $name, $checked, $value) {
                        return Html::radio($name,
                            $checked,
                            [
                                'label' => $label,
                                'value' => $value,
                                'name' => $name,
                                'class' => 'mr-2',
                                'labelOptions' => ['class' => 'mr-4'],
                            ]);
                    }
                ]);
            }
            ?>
        </div>

    </div>


    <?php
        if (!$modelServiceCenter->isNewRecord) {

            ?>

            <?= $this->render('..\includes\_address', [
                'modelAddress' => $modelAddress,
                'form' => $form,
            ]) ?>

            <?php
        }
    ?>

    <div class="form-group">
        <?= Html::submitButton(($modelServiceCenter->isNewRecord ? 'Создать' : 'Сохранить'), ['class' => ($modelServiceCenter->isNewRecord ? 'btn btn-success' : 'btn btn-primary')]) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

Изображение

в принципе он нормально включает этот файл, и загружает некоторые данные по адресу - проблем тут нет. но как мне установить значения для выпадающих списков которые должны ещё загрузится, и только потом из модели подставить данные я не знаю и прошу вашей помощи. Спасибо!
Ответить