skip to Main Content

I have a country, state and city chained dropdown which loads a state depending on the country and loads the cities depending on the state. The code works perfectly fine on my local server but when pushing to the live one, the dropdown is not functioning correctly, for example in some cases it works fine for all 3 but for some cases it just does not load anything and in the console I am seeing a simple false and nothing else.

Here is the JS:

$(document).ready(function() {    
    var country_id = localStorage.getItem("select2CountryValue");
    var state_id = localStorage.getItem("select2StateValue");
    var page_load = true; //added this 

    // Triggering the deleteLocalStorage function in case the client is not 
    // created and the back button is clicked
    $('.del-ls').click(function() {
        deleteLocalStorage();
    });

    // This function is also called by PHP using script tags when the create
    // client form is successfully submitted
    function deleteLocalStorage() {
        var country_id = localStorage.getItem("select2CountryValue");
        var state_id = localStorage.getItem("select2StateValue");

        localStorage.removeItem('select2CountryValue');
        localStorage.removeItem('select2StateValue');
    }

    //$('.csc-select').select2(); 
    $('#country').select2({
        placeholder: 'Select Country'
    });

    $('#state').select2({
        placeholder: 'Select State/Region'
    });

    $('#city').select2({
        placeholder: 'Select City'
    });

    $('select[name="country"]').on('change',function() {
        var country_id= $(this).val();
        localStorage.setItem("select2CountryValue", country_id);
        if (country_id) {
            $.ajax({
                url: "/src/Pages/world/getStates.php",
                type: "GET",
                data: {'country_id':country_id},
                dataType: "json",
                success: function(data) {
                    console.log(data);
                    $('select[name="state"]').empty();
                    $('select[name="state"]').append('<option value="">Select State</option>');
                    $.each(JSON.parse(data), function(key,value) {
                        $('select[name="state"]').append('<option value="'+value.id+'">'+value.name+'</option>');
                    });
                    //check if the change is called on page load
                    if (page_load == true) {
                        $('#state').val(state_id).trigger('change'); //assign slected value after element option is added in dom
                        page_load = false; //adding this so that next time this doesn't get execute
                    }
                }
            });
        } else {
            $('select[name="state"]').empty();
       }
    });
    
    $('#country').val(country_id).trigger('change');

    $('select[name="state"]').on('change',function() {
        var country_id = $('#country').val();
        var state_id = $(this).val();
        localStorage.setItem("select2StateValue", state_id);
        if (state_id) {
            $.ajax({
                url: "/src/Pages/world/getCities.php",
                type: "GET",
                data: {'country_id': country_id, 'state_id': state_id},
                dataType: "json",
                success: function(data) {
                    console.log(data);
                    $('select[name="city"]').empty();
                    $('select[name="city"]').append('<option value="">Select City</option>');
                    $.each(JSON.parse(data),function(key,value) {
                        $('select[name="city"]').append('<option value="'+value.id+'">'+value.name+'</option>');
                    });
                }
            });
        } else {
            $('select[name="city"]').empty();
        }
    });
});

And this is the HTML and just a some simple PHP to load the countries which is working fine:

<p>
    <span>Country</span>
    <select class="csc-select" name="country" id="country">
        <option value="">Select Country</option>
        <?php foreach($countries as $country) { ?>
        <option value="<?php echo $country[$columnName['COLUMN_NAME']]; ?>"
        >
            <?php echo $country['name']; ?>
        </option>
        <?php } ?>
    </select>
</p>
<p>
    <span>State</span>
    <select class="csc-select" name="state" id="state">
        <option value="">Select State</option>
    </select>
</p>
<p>
    <span>City</span>
    <select class="csc-select" name="city" id="city">
        <option value="">Select City</option>
    </select>
</p>

I am a bit clueless now since locally it works perfectly however on the live server it doesn’t work for every option you pick, I rechecked the countries, states and cities database and all the info is there so its not missing, the database is identical to the one I am using in the local version too. If anyone has any idea or suggestions, I would appreciate it a lot.

And here is the console log error that appears sometimes:

> Uncaught SyntaxError: Unexpected end of JSON input
>     at JSON.parse (<anonymous>)
>     at Object.success (add:977:29)
>     at c (jquery-3.6.0.min.js:2:28327)
>     at Object.fireWith [as resolveWith] (jquery-3.6.0.min.js:2:29072)
>     at l (jquery-3.6.0.min.js:2:79901)
>     at XMLHttpRequest.<anonymous> (jquery-3.6.0.min.js:2:82355)

and now I am adding a screenshot of the console.log, this happens when I choose the country United States, the state Caliornia, so it does not show anything for California but it should:

enter image description here

Here is the getStates.php file code:

<?php 

use AppSession;
use AppLogin;
use AppLocation;

require_once("../../../vendor/autoload.php");

$objSession = new Session();
if(!$objSession->isLogged()) {
    Login::redirectTo("/login");
}

$country_id = $_GET['country_id'];

if(isset($_GET['country_id'])) {
    $objLocation = new Location();
    echo json_encode($getStates = $objLocation->getStates($country_id));
}

and here is the getCities.php file code:

<?php 

use AppSession;
use AppLogin;
use AppLocation;

require_once("../../../vendor/autoload.php");

$objSession = new Session();
if(!$objSession->isLogged()) {
    Login::redirectTo("/login");
}

$state_id = $_GET['state_id'];
$country_id = $_GET['country_id'];

if(isset($_GET['state_id']) && isset($_GET['country_id'])) {
    $objLocation = new Location();
    echo json_encode($getCities = $objLocation->getCities($state_id, $country_id));
}

and this is the code in the Location class that fetches the data:

public function getStates(string $id): ?string
    {

        $sql = "SELECT `id`, `name` FROM {$this->table_3}
                WHERE `country_id` = '". $this->escape($id) ."'
                ORDER BY `name` ASC";
                $result = $this->fetchAll($sql);
                return json_encode($result);

    }

    public function getCities(string $state, string $country): bool|string
    {

        $sql = "SELECT `id`, `name` FROM {$this->table_4}
                WHERE `state_id` = '". $this->escape($state) ."'
                AND `country_id` = '". $this->escape($country) ."'
                ORDER BY `name` ASC";
                $result = $this->fetchAll($sql);
                return json_encode($result);

    }

3

Answers


  1. Chosen as BEST ANSWER

    So I am adding the solution which @SeanReyes led me to.

    Actually it led me to 2 solutions, and they are:

    Solution 1. I could simply do an if condition in my Location::class to check if the json_encode is working correctly and if not simply add a JSON flag like so (JSON_INVALID_UTF8_IGNORE or JSON_INVALID_UTF8_SUBSTITUTE):

       public function getStates(string $id): ?string
        {
    
            $sql = "SELECT `id`, `name` FROM {$this->table_3}
                    WHERE `country_id` = '". $this->escape($id) ."'
                    ORDER BY `name` ASC";
                    $result = $this->fetchAll($sql);
                    if(json_encode($result)) {
                        return json_encode($result);
                    } else {
                        return json_encode($result, JSON_INVALID_UTF8_IGNORE);
                    }
    
        }
    

    and did the same with the getCities method.

    Solution 2. While this did fix it, it displayed the latin characters incorrectly and so that made me find another easy solution by simply adding a charset to my mysqli connection like so:

            $this->db->set_charset("utf8mb4");
    

    and like magic everything worked perfectly, but this was a rookie mistake on my end as this should of been set anyway, thanks to everyone for pointing me in the right direction.


  2. Hi I think it could be the $.ajax AND the echo json_decode the issue….

    I made my own AJAX function that I share in github https://github.com/jintor/stubajax

    async function stubajax (divid,phphat,postix = [],pend = 'html') {
    
        var pcache = (Math.floor(Math.random() * 100000000) + 1);
        
        postix["preventcache"] = pcache; // prevent browser caching
        postix["divid"] = encodeURIComponent(divid);
        postix["mojax_height"] = encodeURIComponent($(window).height());
        postix["mojax_width"] = encodeURIComponent($(window).width());
    
        // if you need to send cookies
        postix["cookies"] = decodeURIComponent(document.cookie); 
        
        // if you need to send localStorage or sessionStorage stuff
        for (var i = 0; i < localStorage.length; i++){ postix[localStorage.key(i)] = localStorage.getItem(localStorage.key(i)); }
        for (var i = 0; i < sessionStorage.length; i++){ postix[sessionStorage.key(i)] = sessionStorage.getItem(sessionStorage.key(i)); }
            
        await fetch(phphat+"?pcache="+pcache, {
          method: "POST", body: JSON.stringify(Object.assign({}, postix)), headers: {"Content-type": "application/json; charset=UTF-8"}
        }).then( response => { return response.text(); }).then( html => { 
            switch ( pend ){
                case 'append' : $("#"+divid).append(html); break;
                case 'prepend' : $("#"+divid).prepend(html); break;
                default : $("#"+divid).html(html); break;
            }
        }).catch( err => console.log(err) );
          
    }
    

    AND YOU USE IT LIKE THIS

    <input onchange="stubajax ('div_id_that_will_reseive_the_ajax_message','/path/to_php.php',{'extra1':this.value},'html');
    

    On the PHP side :
    a the end simply echo (WITHOUT json_encode)….

    Login or Signup to reply.
  3. So, I have asked on the comments and you have provided… here is what I think is happening… and what I think you should do.

    your method getCities on the Location::class is returning a boolean… and sometimes a string…

    json_encode will only return false on failure, this means json_encode has failed on encoding your sql result…

    you can use json_last_error() and json_last_error_msg() to debug your json_encode() problem

    you can find the documentation here

    You can debug your problem on Local but, please make sure your local machine is running the same things on the live server, to replicate the error…

    1. PHP version
    2. Database Data
    3. MySql Version (But I don’t think it’s necessary)
    4. Browser (but just for testing, app should work on all browser)

    if you can’t replicate the error, you need to do it LIVE. (please be very careful, this should be your LAST RESORT)

    I could not provide a specific answer because I don’t know if $this->fetchAll() only returns an array or maybe sometimes it returns an error message…

    I have provided you this answer, because your main concern on this question is why your program returning a simple false value…

    for example in some cases it works fine for all 3 but for some cases it just does not load anything and in the console I am seeing a simple false and nothing else.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search