JavaScript code for sorting a list - including translation for all questions type | XM Community
Skip to main content

JavaScript code for sorting a list - including translation for all questions type


Forum|alt.badge.img+5
  • Level 2 ●●
  • 19 replies

Hi, As I was looking for it and didn’t find it, I wanted to share with you the code that was written for me, so everyone can enjoy it and give back to the community. 

 

This code should be copied to the JS of a specific question where you have a list of items, and you want customers to see your list of options sorted in all languages alphabetically.  

This code is applying the following rules: 

 

  1. Fixed choices – you should provide all the choices you do not want to be sorted and they will appear *In the order provided AT THE END OF THE SORTED LIST*… here are 3 scenarios:

  • One choice only – for example “other”, just add it for each language, as in the following 'EN': 'Other' 
  • List of some choices – here you should provide the words in the following format: 'ES': ['Perro', 'Gato', 'Niño', 'Bebé', 'Globo', 'Otro'] 

  • All the choices of the question –  You will have to do it for languages that their sorting rules are complicated in Java Script. We tested AR, HE, TH, SR, RU, UK, VI, KO, ES, PT-BR, TR.  All of them are working great.  ZH-S and JA doesn’t and need to use this all choices as fixed. Please make sure that for the JA and ZH-S localization you ask it against the English + ask them to provide next to it the order it should be in. It will help you then sort in excel by the numbers and put it into the list following format should be used: 'JA': ['XXX', 'XXX', 'XXX'] 

     

  1. Rest of the choices – the rest of the choices that are not in fixed, will be sorted according to the language rules, followed first by the check if the choice starts with an English word. For example: IT・ネットワーク(テクニカルサポート)- The word IT is in English, so this choice will appear first. or like  in Russian 2 words are sorted as first based on English (See image at end of point 4)

  2. If an option is provided with text entry box, it will always be the last choice presented (for example “other, please specify”) 

  3. The code will work on all list options questions, including using columns.  

Here is an example of all the options in Russian 

 

 

So now the code itself and I left an example in JA and EN for the fixedchoices: 

 

Qualtrics.SurveyEngine.addOnReady(function () {
    var $this = jQuery(this.questionContainer);
    
    var fixedChoices = {
        'EN': 'Other (Please specify)',
        'ES': '',
        'PT-BR': '',
        'SR': '',
        'VI': '',
        'TR': '',
        'RU': '',
        'UK': '',
        'HE': '',
        'AR': '',
        'TH': '',
        'KO': '',
        'JA': ['IT・ネットワーク(テクニカルサポート)', 'ウェブ、モバイル、ソフトウェア開発']'],
        'ZH-S': ''
    };

    var sortChoices = function () {
        var lang = jQuery("#Q_lang").length > 0 ? jQuery("#Q_lang").val() : '${e://Field/Q_Language}';
        var $el = jQuery(".ChoiceStructure", $this);

        if ($el.is("table")) {
            let targetElement = $el[0];
            var tds = Array.from(targetElement.querySelectorAll('td.ControlContainer, td.LabelContainer'));
            var sortedTds = [];
            
            for (var i = 0; i < tds.length; i += 2) {
                sortedTds.push({ control: tds[i], label: tds[i + 1] });
            }

            // Sort choices
            sortedTds.sort(function (a, b) {
                if (jQuery(".LabelWrapper .InputText", jQuery(a.label)).length > 0) {
                    return 1;
                }
                if (jQuery(".LabelWrapper .InputText", jQuery(b.label)).length > 0) {
                    return -1;
                }

                var textA = a.label.querySelector('span').textContent.trim();
                var textB = b.label.querySelector('span').textContent.trim();

                if (Array.isArray(fixedChoices[lang])) {
                    var indexA = fixedChoices[lang].indexOf(textA);
                    var indexB = fixedChoices[lang].indexOf(textB);

                    if (indexA !== -1 && indexB !== -1) {
                        return indexA - indexB;
                    }
                }

                if (/^[A-Za-z]/.test(textA) && !/^[A-Za-z]/.test(textB)) {
                    return -1;
                }
                if (!/^[A-Za-z]/.test(textA) && /^[A-Za-z]/.test(textB)) {
                    return 1;
                }

                return textA.localeCompare(textB, lang, { sensitivity: 'base', ignorePunctuation: true, numeric: true });
            });

            let totalCols = jQuery("tr:first .ControlContainer", $el).length;
            let curTdIndx = 0;

            for (let col = 0; col < totalCols; col++) {
                for (let i = 0; i < Math.ceil(sortedTds.length / totalCols); i++) {
                    let row, isAddRow = false;

                    if (col == 0) {
                        row = document.createElement('tr');
                        row.className = (i % 2 === 0 ? 'reg' : 'alt') + ' cust-row';
                        isAddRow = true;
                    } else {
                        row = jQuery("tr.cust-row:eq(" + i + ")", $el);
                    }

                    let pair = curTdIndx <= (sortedTds.length - 1) ? sortedTds[curTdIndx] : { control: '<td>&nbsp;</td>', label: '<td>&nbsp;</td>' };
                    row.append(pair.control, pair.label);
                    isAddRow ? targetElement.tBodies[0].append(row) : "";
                    curTdIndx++;
                }
            }
            
            jQuery("tr:not(.cust-row)", $el).remove();
        } else {
            let targetElement = $el[0];
            let opChoices = targetElement.children;
            opChoices = Array.prototype.slice.call(opChoices);

            // Sort choices
            opChoices.sort(function (a, b) {
                if (jQuery(".LabelWrapper .InputText", jQuery(a)).length > 0) {
                    return 1;
                }
                if (jQuery(".LabelWrapper .InputText", jQuery(b)).length > 0) {
                    return -1;
                }

                var textA = a.textContent.trim();
                var textB = b.textContent.trim();

                if (Array.isArray(fixedChoices[lang])) {
                    var indexA = fixedChoices[lang].indexOf(textA);
                    var indexB = fixedChoices[lang].indexOf(textB);

                    if (indexA !== -1 && indexB !== -1) {
                        return indexA - indexB;
                    }
                }

                if (/^[A-Za-z]/.test(textA) && !/^[A-Za-z]/.test(textB)) {
                    return -1;
                }
                if (!/^[A-Za-z]/.test(textA) && /^[A-Za-z]/.test(textB)) {
                    return 1;
                }

                return textA.localeCompare(textB, lang, { sensitivity: 'base', ignorePunctuation: true, numeric: true });
            });

            for (let i = 0; i < opChoices.length; i++) {
                targetElement.appendChild(opChoices[i]);
            }
        }
    }

    sortChoices();
});

2 replies

Forum|alt.badge.img+5
  • Author
  • Level 2 ●●
  • 19 replies
  • February 7, 2024

Please see a revision in the code here, as we found Turkish has a rule that should be applied. 

 

Qualtrics.SurveyEngine.addOnReady(function () {
    var $this = jQuery(this.questionContainer);
    
    var fixedChoices = {
        'EN': '',
        'ES': '',
        'PT-BR': '',
        'SR': '',
        'VI': '',
        'TR': '',
        'RU': '',
        'UK': '',
        'HE': '',
        'AR': '',
        'TH': '',
        'KO': '',
        'JA': ['IT・ネットワーク(テクニカルサポート)', 'ウェブ、モバイル、ソフトウェア開発', '運送、物流', '映像編集', '音楽 - 作曲、編集', '会計・コンサルティング', 'カスタマーサービス', '管理サポート(バーチャルアシスタント、プロジェクトマネージャー)', '教育 - 教職', '金融サービス', '建築', 'ゲーム関連', '鉱業および採石業', '個人向けサービス(ライフコーチ、アドバイザー、フィットネスコーチ)', '執筆 / 翻訳', '商品販売', '製造業', 'デザインと芸術', 'データサイエンス・アナリスト', '農業(林業、農作物、漁業)', 'ホスピタリティ - レンタルサービス','法務', 'マーケティング・広告代理店', 'その他(具体的にご記入ください)'],
        'ZH-S': ''
    };
    
    const orderTR = 'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVWXYZabcçdefgğhıijklmnoöprsştuüvwxyz';

    var sortChoices = function () {
        var lang = jQuery("#Q_lang").length > 0 ? jQuery("#Q_lang").val() : '${e://Field/Q_Language}';
        var $el = jQuery(".ChoiceStructure", $this);

        if ($el.is("table")) {
            let targetElement = $el[0];
            var tds = Array.from(targetElement.querySelectorAll('td.ControlContainer, td.LabelContainer'));
            var sortedTds = [];
            
            for (var i = 0; i < tds.length; i += 2) {
                sortedTds.push({ control: tds[i], label: tds[i + 1] });
            }

            // Sort choices
            sortedTds.sort(function (a, b) {
                if (jQuery(".LabelWrapper .InputText", jQuery(a.label)).length > 0) {
                    return 1;
                }
                if (jQuery(".LabelWrapper .InputText", jQuery(b.label)).length > 0) {
                    return -1;
                }

                var textA = a.label.querySelector('span').textContent.trim();
                var textB = b.label.querySelector('span').textContent.trim();

                if (Array.isArray(fixedChoices[lang])) {
                    var indexA = fixedChoices[lang].indexOf(textA);
                    var indexB = fixedChoices[lang].indexOf(textB);

                    if (indexA !== -1 && indexB !== -1) {
                        return indexA - indexB;
                    }
                }
                
                if (lang == 'TR') {
                    let i = 0;
                    while (i < textA.length && i < textB.length) {
                        let diff = orderTR.indexOf(textA[i]) - orderTR.indexOf(textB[i]);
                        if (diff !== 0) return diff;
                        i++;
                    }
                    return textA.length - textB.length;
                }

                if (/^[A-Za-z]/.test(textA) && !/^[A-Za-z]/.test(textB)) {
                    return -1;
                }
                if (!/^[A-Za-z]/.test(textA) && /^[A-Za-z]/.test(textB)) {
                    return 1;
                }

                return textA.localeCompare(textB, lang, { sensitivity: 'base', ignorePunctuation: true, numeric: true });
            });

            let totalCols = jQuery("tr:first .ControlContainer", $el).length;
            let curTdIndx = 0;

            for (let col = 0; col < totalCols; col++) {
                for (let i = 0; i < Math.ceil(sortedTds.length / totalCols); i++) {
                    let row, isAddRow = false;

                    if (col == 0) {
                        row = document.createElement('tr');
                        row.className = (i % 2 === 0 ? 'reg' : 'alt') + ' cust-row';
                        isAddRow = true;
                    } else {
                        row = jQuery("tr.cust-row:eq(" + i + ")", $el);
                    }

                    let pair = curTdIndx <= (sortedTds.length - 1) ? sortedTds[curTdIndx] : { control: '<td>&nbsp;</td>', label: '<td>&nbsp;</td>' };
                    row.append(pair.control, pair.label);
                    isAddRow ? targetElement.tBodies[0].append(row) : "";
                    curTdIndx++;
                }
            }
            
            jQuery("tr:not(.cust-row)", $el).remove();
        } else {
            let targetElement = $el[0];
            let opChoices = targetElement.children;
            opChoices = Array.prototype.slice.call(opChoices);

            // Sort choices
            opChoices.sort(function (a, b) {
                if (jQuery(".LabelWrapper .InputText", jQuery(a)).length > 0) {
                    return 1;
                }
                if (jQuery(".LabelWrapper .InputText", jQuery(b)).length > 0) {
                    return -1;
                }

                var textA = a.textContent.trim();
                var textB = b.textContent.trim();

                if (Array.isArray(fixedChoices[lang])) {
                    var indexA = fixedChoices[lang].indexOf(textA);
                    var indexB = fixedChoices[lang].indexOf(textB);

                    if (indexA !== -1 && indexB !== -1) {
                        return indexA - indexB;
                    }
                }
                
                if (lang == 'TR') {
                    let i = 0;
                    while (i < textA.length && i < textB.length) {
                        let diff = orderTR.indexOf(textA[i]) - orderTR.indexOf(textB[i]);
                        if (diff !== 0) return diff;
                        i++;
                    }
                    return textA.length - textB.length;
                }

                if (/^[A-Za-z]/.test(textA) && !/^[A-Za-z]/.test(textB)) {
                    return -1;
                }
                if (!/^[A-Za-z]/.test(textA) && /^[A-Za-z]/.test(textB)) {
                    return 1;
                }

                return textA.localeCompare(textB, lang, { sensitivity: 'base', ignorePunctuation: true, numeric: true });
            });

            for (let i = 0; i < opChoices.length; i++) {
                targetElement.appendChild(opChoices[i]);
            }
        }
    }

    sortChoices();
});


Forum|alt.badge.img+5
  • Author
  • Level 2 ●●
  • 19 replies
  • February 7, 2024

If you use Turkish, please add this line for the code.

const orderTR = 'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVWXYZabcçdefgğhıijklmnoöprsştuüvwxyz';


Leave a Reply