1

Hello i have this smarty code that generate a list of state in determinate country ordered by states ISO CODE

countries = new Array();
{foreach from=$countries item='country'}
    {if isset($country.states)}
        countries[{$country.id_country|intval}] = new Array();
        {foreach from=$country.states item='state' name='states'}
            countries[{$country.id_country|intval}]['{$state.id_state|intval}'] = '{$state.name|escape:'htmlall':'UTF-8'}';
        {/foreach}
    {/if}
{/foreach}

Te restult is this and is ok for me because is ordered by ISO CODE

countries = new Array();
countries[10] = new Array();
countries[10]['53'] = 'AG';
countries[10]['54'] = 'AL';
countries[10]['55'] = 'AN';
countries[10]['56'] = 'AO';
countries[10]['58'] = 'AP';
countries[10]['93'] = 'AQ';
countries[10]['57'] = 'AR';
countries[10]['59'] = 'AT';
countries[10]['60'] = 'AV';
countries[10]['61'] = 'BA';
countries[10]['64'] = 'BG';
countries[10]['65'] = 'BI';
countries[10]['62'] = 'BL';
countries[10]['63'] = 'BN';
countries[10]['66'] = 'BO';
countries[10]['69'] = 'BR';
countries[10]['68'] = 'BS';
countries[10]['162'] = 'BT';
countries[10]['67'] = 'BZ';
countries[10]['70'] = 'CA';
countries[10]['72'] = 'CB';
countries[10]['73'] = 'CE';
countries[10]['76'] = 'CH';
countries[10]['156'] = 'CI';
countries[10]['71'] = 'CL';
countries[10]['81'] = 'CN';
countries[10]['77'] = 'CO';
countries[10]['79'] = 'CR';
countries[10]['78'] = 'CS';
countries[10]['74'] = 'CT';
countries[10]['75'] = 'CZ';
countries[10]['82'] = 'EN';

In the same page i have this javascript that populate a select html tag but order the option tag by ID not by ISO CODE and i dont know why

$(document).ready(function(){
    $('select#id_country').change(function(){
        updateState();
    });
    updateState();
});

function updateState()
{
    $('select#id_state option:not(:first-child)').remove();
        var states = countries[$('select#id_country').val()];
        if( typeof(states) != 'undefined' )
        {
            for (indexState in states)
            {
                //ie bug fix
                if (indexState != 'indexOf')
                    $('select#id_state').append('<option value="'+indexState+'"'+ (idSelectedCountry == indexState ? ' selected="selected' : '') + '">'+states[indexState]+'</option>');
            }
            $('p.id_state:hidden').slideDown('slow');
        }
        else
            $('p.id_state').slideUp('fast');
}
tlenss
  • 2,609
  • 2
  • 22
  • 26
user1499315
  • 139
  • 1
  • 1
  • 8
  • 1
    Use JSON, not that custom template! – Bergi Nov 03 '13 at 09:16
  • 2
    simpler and cleaner using `json_encode()` than running data through smarty. Not to mention unnecessary extra nesting level – charlietfl Nov 03 '13 at 09:16
  • Can you reconstruct your array, countries[10][$i] = array('AG','53'); //$i is loop count, 'AG' is ISO code and 53 is stateid – Krish R Nov 03 '13 at 09:18
  • Hello, thank you for support but what is the correct code? I have to change all code? – user1499315 Nov 03 '13 at 09:21
  • you haven't even explained what your problem is. Give better details of issue – charlietfl Nov 03 '13 at 09:22
  • The javascript populate options of html select tag ordered by states ID but i need ordered by states ISO code. – user1499315 Nov 03 '13 at 09:25
  • re-sort them at server when you get rid of the smarty **`is ok for me because is ordered by ISO CODE`** makes no sense if you need them sorted otherwise. Go to php manual site...look up array sorting , and json_encode() – charlietfl Nov 03 '13 at 09:26
  • The smarty foreach return results ordered by iso code but when javascript populate select option tag return values ordered by ID. I checked json_encode() but i don't know how i can use this in my script. – user1499315 Nov 03 '13 at 09:35

1 Answers1

0

The problem is that your objects of ISO CODES acts like an array and not like an object. When you add an item to an array with numeric index, it will put it in a specific order in that array automatically, that's the way array works in javascript.
For example, if you try this code it Chrome's console:

var arr = [];
arr[4] = "data"; //same for arr['4'] - javascript will convert it to arr[4]
arr;

It will show you the following result:

[undefined × 4, "data"]

Which means that the it'll create all 5 indexes (from 0 to 4), when the first 4 will be undefined, and the fifth one (index 4) will be the value you set.
Now if you'll add another index which is lower than 4, let's say arr[2] = "Z Data";, now the array will be:

[undefined × 2, "Z Data", undefined × 1, "data"]

As you see now, the value ordered by it's natural array's way (No matter the content and the insert order).

In your case, if you want it to be ordered, there are several options to complete it:
1 - The best option is to create an ordered array that contains an object of your data:

var countries = new Array();
{foreach from=$countries item='country'}
    {if isset($country.states)}
        countries[{$country.id_country|intval}] = new Array();
        {foreach from=$country.states item='state' name='states'}
            countries[{$country.id_country|intval}].push({state_id: {$state.id_state|intval}, iso: '{$state.name|escape:'htmlall':'UTF-8'}'});
        {/foreach}
    {/if}
{/foreach}

Which will be compiled into:

var countries = new Array();
countries[10] = new Array();
countries[10].push({id: 53, iso:'AG'});
countries[10].push({id: 54, iso:'AL'});
countries[10].push({id: 55, iso:'AN'});
countries[10].push({id: 56, iso:'AO'});
countries[10].push({id: 58, iso:'AP'});
countries[10].push({id: 93, iso:'AQ'});
countries[10].push({id: 57, iso:'AR'});
countries[10].push({id: 59, iso:'AT'});
countries[10].push({id: 60, iso:'AV'});
//etc...

2 - Another option is to convert the array into object by prefixing the array's index with string:

var countries = new Array();
{foreach from=$countries item='country'}
    {if isset($country.states)}
        countries[{$country.id_country|intval}] = {}; //object initialization
        {foreach from=$country.states item='state' name='states'}
            countries[{$country.id_country|intval}]['s{$state.id_state|intval}'] = '{$state.name|escape:'htmlall':'UTF-8'}';
        {/foreach}
    {/if}
{/foreach}

Which will be compiled into:

var countries = new Array();
countries[10] = {};
countries[10]['s53'] = 'AG';
countries[10]['s54'] = 'AL';
countries[10]['s55'] = 'AN';
countries[10]['s56'] = 'AO';
countries[10]['s58'] = 'AP';
countries[10]['s93'] = 'AQ';
countries[10]['s57'] = 'AR';
countries[10]['s59'] = 'AT';
countries[10]['s60'] = 'AV';
//ect...

Once you use it as an object, it will order the list the order you set it.

3 - This option is about converting the array into object too, but this time switching the index with the value:

var countries = new Array();
{foreach from=$countries item='country'}
    {if isset($country.states)}
        countries[{$country.id_country|intval}] = {}; //object initialization
        {foreach from=$country.states item='state' name='states'}
            countries[{$country.id_country|intval}]['{$state.name|escape:'htmlall':'UTF-8'}'] = {$state.id_state|intval};
        {/foreach}
    {/if}
{/foreach}

Which will be compiled into:

var countries = new Array();
countries[10] = {};
countries[10]['AG'] = 53;
countries[10]['AL'] = 54;
countries[10]['AN'] = 55;
countries[10]['AO'] = 56;
countries[10]['AP'] = 58;
countries[10]['AQ'] = 93;
countries[10]['AR'] = 57;
countries[10]['AT'] = 59;
countries[10]['AV'] = 60;
//ect...

4 - Of corse the best option is to encode an ordered object (as described in option 1) into a JSON on the server side (PHP), and decode it on the client side (JavaScript), but it takes more time to fix it.

Hope it helps, and you understand the behavior of the array in JavaScript.

Good luck!

Slavik Meltser
  • 9,712
  • 3
  • 47
  • 48