How to refresh a dropdown acording to other dropdown in CakePHP 3.5


#1

Does anyone have an example of how to do this with version 3.5 of cakephp?

This example works in version 3.0, but I can not make it work in version 3.5.


#2

This is not a unique thing to any framework. You could probably do a google search as there are so many examples on the web. Also try youtube. But decide if you are going to do it with or without ajax. I know there is an example floating around of a car site using dependant dropdowns, sorry I don’t have the link.

I’m not sure if x-editable handles this or not.

Start here https://www.youtube.com/watch?v=0dn8PGBi5PQ


#3

This is my example.
The whole circuit works correctly, but I can not update the select state (stateField).

src/Controller/DropdownController.php

<?php
namespace App\Controller;

use App\Controller\AppController;

class DropdownController extends AppController 
{
    public function index()
    {
        $countries = $this->getCountry();
        $states = $this->getState();

        $this->set(compact(['countries', 'states']));
        $this->set('_serialize', ['countries', 'states']);
    }

    private function getCountry()
    {
        //$this->loadModel('Country');
        //return $this->Countries->find('list');
        return ['Argentina', 'Brasil', 'Chile'];
    }

    private function getState($country_id = null)
    {
        switch ($country_id) 
        {
            case 0:
                $states = ['Buenos Aires', 'Córdoba', 'Tucumán'];
                break;
            case 1:
                $states = ['Curitiva', 'Florianópolis', 'San Pablo'];
                break;
            case 2:
                $states = ['Iquique', 'Santiago de Chile', 'Valparaiso'];
                break;
            default:
                $states = [];
        }
        return $states;
    }

    public function ajaxStateByCountry()
    {
        if ($this->request->is(['ajax', 'post'])) 
        {
            $id = $this->request->query('id');
            $data = ['data' => ['states' => $this->getState($id)]];
            return $this->json($data);
        }
    }
}

src/Template/Dropdown/index.ctp

<?= $this->Html->script('dropdown.js'); ?>

<nav class="large-3 medium-4 columns" id="actions-sidebar">
    <ul class="side-nav">
        <li><?= $this->Html->link('Home', ['controller' => 'pages']) ?></li>
    </ul>
</nav>

<div class="form large-9 medium-8 columns content">
    <?= $this->Form->create() ?>
    <fieldset>
        <legend>Prueba con AJAX</legend>
        <?php
            //echo $this->Form->control('País', ['id' => 'countryField', 'options' => $countries]);
            $request = $this->Url->build(['action' => 'ajaxStateByCountry', 'ext' => 'json']);
            echo $this->Form->control('País', ['id' => 'countryField', 
                                               'rel' => $request,
                                               'options' => $countries]);
            echo $this->Form->control('Ciudad', ['id' => 'stateField','options' => $states]);
        ?>
    </fieldset>
    <?= $this->Form->button('Enviar') ?>
    <?= $this->Form->end() ?>
</div>

webroot/js/dropdown.js

$(function() 
{
    $('#countryField').change(function() 
    {
        var targeturl = $(this).attr('rel');
        var country_id = $(this).val();

        $.ajax({
            type: 'get',
            url: targeturl + '&id=' + country_id,
            beforeSend: function(xhr) 
            {
                xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            },
            success: function(response) 
            {
                if (response.data) 
                {
                    $('#stateField').html(response.data.states);
                }
            },
            error: function(e) 
            {
                alert("An error occurred: " + e.responseText.message);
                console.log(e);
            }
        });
    });
});

#4

My solution was as follows:
I do not know if it’s correct, but it works.

src/Controller/DropdownController.php

class DropdownController extends AppController 
{
    public function index()
    {
        $countries = $this->getCountry();
        $states = $this->getState(1);

        $this->set(compact(['countries', 'states']));
        $this->set('_serialize', ['countries', 'states']);
    }

    private function getCountry()
    {
        //$this->loadModel('Country');
        //return $this->Countries->find('list');
        return [1=>'Argentina', 2=>'Brasil', 3=>'Chile'];
    }

    private function getState($country_id = null)
    {
        switch ($country_id) 
        {
            case 1:
                $states = [1=>'Buenos Aires', 2=>'Córdoba', 3=>'Tucumán'];
                break;

            case 2:
                $states = [4=>'Curitiva', 5=>'Florianópolis', 6=>'San Pablo'];
                break;

            case 3:
                $states = [7=>'Iquique', 8=>'Santiago de Chile', 9=>'Valparaiso'];
                break;
            
            default:
                $states = [];
        }
        return $states;
    }

    public function ajaxStateByCountry()
    {
        if ($this->request->is(['ajax', 'post'])) 
        {
            $id = $this->request->query('id');
            $states = $this->getState($id);

            $combo = [];
            foreach ($states as $key => $value) 
            {
                $combo[] = "<option value='".$key."'>".$value."</option>";
            }            

            $data = ['data' => ['states' => $combo]];
            return $this->json($data);
        }
    }
}