0

I'm trying to create a chained select dropdown list in CakePHP 4. I've search several forum and found few solution and it is found that they are work with previous CakePHP version. I've follow the codes from CakePHP 4 Sandbox which is good sample project. However, when i request the chained selected value, it shows error "An error occurred: undefined".

My database tables:

  1. countries [id,name]
  2. states [id,name]
  3. locations [id,country_id, state_id]

I've bake the code and all relationship works very well. Then I've modified the following codes:

  1. Download Ajax Plugin and enable it.

  2. Create the public function chainedDropdowns and countryStates as follows:

public function chainedDropdowns()
{
    $location = $this->Locations->newEmptyEntity();
    if ($this->request->is('post')) {
        $location = $this->Locations->patchEntity($location, $this->request->getData());
        if ($this->Locations->save($location)) {
            $this->Flash->success(__('The location has been saved.'));

            return $this->redirect(['action' => 'index']);
        }
        $this->Flash->error(__('The location could not be saved. Please, try again.'));
    }
    $countries = $this->Locations->Countries->find('list', ['limit' => 200]);
    $states = $this->Locations->States->find('list', ['limit' => 200]);
    $this->set(compact('location', 'countries', 'states'));
}
public function countryStates() {
    $this->request->allowMethod('ajax');
    $id = (int)$this->request->getQuery('id');
    if (!$id) {
        throw new NotFoundException();
    }

    $this->viewBuilder()->setClassName('Ajax.Ajax');

    $this->loadModel('States');
    $states = $this->States->getListByCountry($id);

    $this->set(compact('states'));
}
  1. Create chaindropdown page at ...localhost\cake4\templates\Locations\chained_dropdowns.php
<?php
use Cake\Core\Configure;
?>
<div class="page index col-sm-8 col-xs-12">
<?= $this->Form->create($location) ?>
    <fieldset>
        <legend><?php echo __('Countries and States');?></legend>
    <?php
        $url = $this->Url->build(['controller' => 'locations', 'action' => 'countryStates', '_ext' => 'json']);
        $empty = $states ? Configure::read('Select.defaultBefore') . __('pleaseSelect') . Configure::read('Select.defaultAfter') : ['0' => Configure::read('Select.naBefore') . __('noOptionAvailable') . Configure::read('Select.naAfter')];

        echo $this->Form->control('country_id', ['id' => 'countries', 'rel' => $url]);
        echo $this->Form->control('state_id', ['id' => 'states', 'empty' => $empty]);
    ?>
    </fieldset>
    
<?php echo $this->Form->submit(__('Submit'));
echo $this->Form->end();?>
</div>

<?php $this->append('script'); ?>
<script>
$(function() {
    $('#countries').change(function() {
        var selectedValue = $(this).val();

        var targeturl = $(this).attr('rel') + '?id=' + selectedValue;
        $.ajax({
            type: 'get',
            url: targeturl,
            beforeSend: function(xhr) {
                xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
            },
            success: function(response) {
                if (response.content) {
                    $('#states').html(response.content);
                }
            },
            error: function(e) {
                alert("An error occurred: " + e.responseText.message);
                console.log(e);
            }
        });
    });
});
</script>
<?php $this->end();
  1. Create country_states at ...localhost\cake4\templates\Locations\ajax\country_states.php
<?php
use Cake\Core\Configure;

if ($states) {
    echo '<option value="">' . Configure::read('Select.defaultBefore') . __('pleaseSelect') . Configure::read('Select.defaultAfter') . '</option>';
    foreach ($states as $k => $v) {
        echo '<option value="' . $k . '">' . h($v) . '</option>';
    }
} else {
    echo '<option value="0">' . Configure::read('Select.naBefore') . __('noOptionAvailable') . Configure::read('Select.naAfter') . '</option>';
}

When selecting the country, eg: Thailand, the states will list Bangkok, Krabi, Phuket. However, it produce error: localhost says: An error occurred: undefined.

error message

The browser console shows error: toolbar.js?1589525179:91 GET http://localhost/cake4/locations/country-states.json?id=2 500 (Internal Server Error)

console error

Apache access log shows:

::1 - - [22/Jun/2020:12:25:49 +0800] "GET /myCake4/locations/country-states.json?id=2 HTTP/1.1" 500 281 "http://localhost/cake4/locations/chained-dropdowns" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36"

How can i solve this problem. Thanks for your help.

Foggies
  • 1
  • 1
  • look at your cakephp app logs. – Salines Jun 22 '20 at 07:08
  • There is no error shown in cakephp error log – Foggies Jun 22 '20 at 11:57
  • You need to check your browser errors, they usually contain the stack trace and info. Using e.g. Chrome, you just right click + inspect and you can see the ajax request and result. – mark Jun 22 '20 at 12:16
  • **In the console, it shows:** GET http://localhost/cake4/locations/country-states.json?id=2 500 (Internal Server Error) {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …} **the json response:** **responseJSON:** {message: "Unknown method "getListByCountry" called on App\Model\Table\StatesTable", url: "/locations/country-states.json?id=2", code: 500, file: "C:\xampp\htdocs\cake4\vendor\cakephp\cakephp\src\ORM\Table.php", line: 2561} – Foggies Jun 22 '20 at 12:24
  • 1
    >>>> `Unknown method "getListByCountry" called on App\Model\Table\StatesTable"`, you call this method inside `public function countryStates()... `.. – Salines Jun 22 '20 at 17:46
  • You can't just copy and paste stuff without understanding what it does, and why it does it. – mark Jun 25 '20 at 09:57

0 Answers0