1

I'm trying to create a Dynamic Dependent Dropdown via Ajax and CodeIgniter 4. However, I could not make it work. Can you help me figure out what's wrong? I'm trying to follow this tutorial online: LINK

Error on the console

jquery.min.js:2 
POST http://localhost/sidsci/public/sd/getAjaxBrgy 500 (Internal Server Error)

Database

mcb_id | mcb_name | mcb_brgy

View

<div class="form-row">
   <div class="form-group col-md-6">
      <label><b>Municipal / City<span class="text-danger">*</span></b></label>
      <select name="s_muncity" class="form-control" id="s_muncity" required>
         <option value="">-Select-</option>
         <?php foreach($mcb as $mcb_row):?>
         <option value="<?= $mcb_row->mcb_name;?>"><?= $mcb_row->mcb_name;?></option>
         <?php endforeach;?>
      </select>
   </div>
   <div class="form-group col-md-6">
      <label><b>Barangay<span class="text-danger">*</span></b></label>
      <select class="form-control" name="s_brgy" id="s_brgy" required></select>
   </div>
</div>

$('#s_muncity').change(function(){
        var mcb_name = $(this).val();

        $.ajax({
            url:'<?=base_url('/sd/getAjaxBrgy')?>',
            method: 'POST',
            data: {mcb_name: mcb_name},
            dataType: 'json',
            success: function(response){
                $('#s_brgy').find('option').not(':first').remove();
                $.each(response,function(index,data){
                $('#s_brgy').append('<option value="'+data['mcb_brgy']+'">'+data['mcb_brgy']+'</option>');
                });
            }
        });
    });

Controller

public function getAjaxBrgy(){

        $model = new McbModel();
        $postData = array(
            'mcb_name' => $this->request->getPost('mcb_name'),
        );

        $data = $model->getBrgyData($postData);
        echo json_encode($data);
    }

Model

  public function getBrgyData($postData) {
      $sql = 'select mcb_brgy from mcb where mcb_name ='.$postData['mcb_name'];
      $query =  $this->db->query($sql);
      return $query->getResult();
  }

I also have <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> in my header part.

2
  • You say your database has a column named mcb_barangay but you're using select mcb_brgy ... in your query, which is slightly different. Are you sure the column name you're using in your query is correct?
    – Marleen
    Commented Jul 7 at 12:09
  • @Marleen i already edited it. it is mcb_brgy.
    – cjvdg
    Commented Jul 7 at 12:36

1 Answer 1

2

In the View markup, identify options reliably by assigning the database id as the option value attribute value. In the great majority of cases, relationships should be built on ids, not names.

<div class="form-row">
    <div class="form-group col-md-6">
        <label for="s_muncity">
            <b>Municipal / City<span class="text-danger">*</span></b>
        </label>
        <select name="s_muncity" class="form-control" id="s_muncity" required>
            <option value="">-Select-</option>
            <?php foreach ($mcb as $mcb_row) { ?>
                <?php printf('<option value="%d">%s</option>', $mcb_row->mcb_id, $mcb_row->mcb_name); ?>
            <?php } ?>
        </select>
    </div>
    <div class="form-group col-md-6">
        <label for="s_brgy"><b>Barangay<span class="text-danger">*</span></b></label>
        <select class="form-control" name="s_brgy" id="s_brgy" required>
            <option value="">-Select-</option>
        </select>
    </div>
</div>

In your Javascript, if you aren't going to use mcb_id as option values, then omit the value attribute value entirely -- there is no benefit in repeating the option's text as the value attribute. This ajax request is merely "reading" data (not "writing") data, therefore it is generally accepted practice to perform a GET request rather than a POST request.

$('#s_muncity').change(function() {
    $.get(
        '<?php echo base_url("/sd/getAjaxBrgy/"); ?>' + $(this).val(),
        function (response) {
            $('#s_brgy').find('option').not(':first').remove();
            $.each(response, function(index, data) {
                $('#s_brgy').append(
                    '<option>' + data.mcb_brgy + '</option>'
                );
            });
        },
        'json'
    );
});

The Controller

public function getAjaxBrgy(int $mcbId)
{
    echo json_encode(
        (new McbModel())->getBrgy(['mcb_id' => $mcbId])
    );
}

The Model: (your earlier attempt was not quoting the variable being passed in -- I assume the value was not an integer or float)

public function getBrgy(array $where, string $order = 'mcb_name'): array
{
    return $this->db
        ->table('mcb_brgy')
        ->orderBy($order)
        ->getWhere($where)
        ->getResult();
}

All that said, I wouldn't perform any AJAX requests at all!

Since you already have a single result set that contains all of the database table data, you should declare a lookup object in javascript as a constant. The properties will be the mcb_id values and the values for each mcb_id will be a subarray containing all related mcb_brgy values.

Everything you need will be readily available for instant Javascript access and you won't need to bother your server.

Populating the lookup:

const mcbLookup = <?php echo json_encode(
    array_reduce(
        $mcv,
        function ($result, $row) {
            $result[$row->mcb_id][] = $row->mcb_brgy;
            return $result;
        },
        []
    )
); ?>;

Adding the listener:

$('#s_muncity').change(function(){
    $('#s_brgy').find('option').not(':first').remove();
    $.each(
        mcbLookup[$(this).val()],
        function(index, data) {
            $('#s_brgy').append('<option>' + data.mcb_brgy + '</option>');
        }
    );
});

Not the answer you're looking for? Browse other questions tagged or ask your own question.