Reduce the amount of if in Javascript

Asked

Viewed 530 times

0

I’m building an app on the bird site. Inside the site will have an article informing the possible genetics that will be generated through a mating of two different breeds.

Example: Ring Neck - Albino x Ring Neck - Blue can generate Ring Neck - Violet.

For this I created in HTML a select listing all males, and depending on the chosen male will be generated another list (another select below), with all females that pair with it.

After selected the male and the female, when you click on button check, it will bring within a textarea the result.

PROBLEM

As there are several races, there are several validations, I would like your help if I can reduce the amount of if, Else if.

var box01  = document.getElementById("box01");
var box02  = document.getElementById("box02");
var txtArea = document.getElementById("txtArea");

function myChange(){
    box02.innerHTML = "";
    box02.removeAttribute("disabled");

    if(box01.value == "nenhum"){
        box02.setAttribute("disabled");
    }

    if(box01.value == "albino"){
        var optionArray = ["0|Nenhum","albino|Albino","azul|Azul",
        "canela|Canela","cremino|Cremino","turquesa-azul|Turquesa Azul","verde-azul|Verde/Azul","lutino|Lutino","lutino-azul|Lutino/Azul","turquesa-cinza|Turquesa Cinza","skyblue|SkyBlue"];
    }
    else if(box01.value == "azul"){
        var optionArray = ["0|Nenhum","azul|Azul","lutino|Lutino","lutino-azul|Lutino/Azul","albino|Albino","cinza|Cinza","verde-azul|Verde/Azul","verde-cinza-azul|Verde Cinza/Azul","turquesa-azul|Turquesa Azul","silver|Silver","skyblue|SkyBlue","turquesa-cinza|Turquesa Cinza","cremino|Cremino"];
    }
    else if(box01.value == "canela"){
        var optionArray = ["0|Nenhum","cinza|Cinza"];
    }
    else if(box01.value == "canela-azul"){
        var optionArray = ["0|Nenhum","skyblue|SkyBlue","cinza|Cinza","azul|Azul","canela-verde-cinza-azul|Canela Verde Cinza/Azul","silver|Silver"];
    }       
    for(var option in optionArray){
        // Método .sort() ordena o elementos do próprio array.
       //  Método foi utilizado para organizar a exibição da box02(fêmeas) em ordem alfabetica. 
            optionArray.sort(); 
        var pair = optionArray[option].split("|");
        var newOption = document.createElement("option");

            newOption.value = pair[0];
            newOption.innerHTML = pair[1];

            box02.options.add(newOption);       
    } 
}
function myFunction(){

    // Validação Albino
    if(box01.value == "albino" && box02.value == "0"){
        txtArea.innerHTML = "";
    }
    else if(box01.value == "albino" && box02.value == "verde-azul"){
        txtArea.innerHTML = "M Verde/Azul\nM Azul\nF Lutino/Azul\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "albino"){
        txtArea.innerHTML = "M Albino\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "azul"){
        txtArea.innerHTML = "M Azul\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "cremino"){
        txtArea.innerHTML = "M Cremino\nM Albino\n\nF Cremino\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "turquesa-azul"){
        txtArea.innerHTML = "M Turquesa/Azul\nM Azul\n\nF Cremino\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "lutino"){
        txtArea.innerHTML = "M Lutino/Azul\nF Lutino/Azul";
    }
    else if(box01.value == "albino" && box02.value == "lutino-azul"){
        txtArea.innerHTML = "M Lutino/Azul\nM Albino\n\nF Lutino/Azul\nF Albino";
    }

}
<form>
    <div id="container-form">
        <label for="box01">Macho</label>
        <select id="box01" name="box01" onchange="myChange()">
            <option value="nenhum">Nenhum</option>
            <option value="albino">Ring Neck - Albino</option>
            <option value="azul">Ring Neck - Azul</option>
            <option value="canela">Ring Neck - Canela</option>
            <option value="canela-azul">Ring Neck - Canela Azul</option>
            <option value="canela-verde-cinza">Ring Neck - Canela Verde Cinza</option>
            <option value="cinza">Ring Neck - Cinza</option>
            <option value="cremino">Ring Neck - Cremino</option>
            <option value="lutino">Ring Neck - Lutino</option>
            <option value="silver">Ring Neck - Silver</option>
            <option value="skyblue">Ring Neck - SkyBlue</option>
            <option value="turquesa-azul">Ring Neck - Turquesa Azul</option>
            <option value="turquesa-cinza">Ring Neck - Turquesa Cinza</option>
            <option value="turquesa-skyblue">Ring Neck - Turquesa SkyBlue</option>
            <option value="turquesa-silver">Ring Neck - Turquesa Silver</option>
            <option value="verde-cinza">Ring Neck - Verde Cinza</option>
            <option value="verde">Ring Neck - Verde</option>
            <option value="pallids">Ring Neck - Pallids</option>
        </select>
        <label for="box01">Fêmea</label>
        <select id="box02" disabled>

        </select>
        <button type="button" onclick="myFunction()">Verificar</button>
    </div>
    <textarea id="txtArea" rows="10" cols="29" disabled></textarea>
</form>

1 answer

2


To update the list of female options, you can create a male mapping for the respective female possibilities, something like this:

var mapMachoFemeas = {
    "albino": [ {"valor": "albino", "texto": "Albino"}, {"valor": "verde-azul", "texto": "Verde/Azul"} ],
    "azul": [ {"valor": "lutino-azul", "texto": "Lutino/Azul"}, {"valor": "skyblue", "texto": "SkyBlue"} ],
    "canela": [ {"valor": "cinza", "texto": "Cinza"} ],
    "canela-azul": [ {"valor": "cinza", "texto": "Cinza"}, {"valor": "canela-verde-cinza-azul", "texto": "Canela Verde Cinza/Azul"} ]
};

I left the above example incomplete, but the basic idea is: for each type of male ("albino", "blue", etc.), there is an array with possible females. And each element of the female array is an object that holds the "value" and "text" keys, which are used to construct the options of the select. Note that you do not need to include the "None" option, because if it is always added, just add it every time you have to change.

It would look like this (left incomplete, with only a few options, to be shorter, but just add all the options on mapMachoFemeas - and already get them in order, so you don’t need to call sort all the time):

var box01  = document.getElementById("box01");
var box02  = document.getElementById("box02");
var txtArea = document.getElementById("txtArea");

// mapeia cada macho para as respectivas opções de fêmeas
var mapMachoFemeas = {
    "albino": [ {"valor": "albino", "texto": "Albino"}, {"valor": "verde-azul", "texto": "Verde/Azul"} ],
    "azul": [ {"valor": "lutino-azul", "texto": "Lutino/Azul"}, {"valor": "skyblue", "texto": "SkyBlue"} ],
    "canela": [ {"valor": "cinza", "texto": "Cinza"} ],
    "canela-azul": [ {"valor": "cinza", "texto": "Cinza"}, {"valor": "canela-verde-cinza-azul", "texto": "Canela Verde Cinza/Azul"} ]
};

function novaOpcao(valor, texto) {
    var newOption = document.createElement("option");
    newOption.value = valor;
    newOption.label = texto;
    return newOption;
}
function atualizarFemeas(){
    box02.innerHTML = "";
    box02.removeAttribute("disabled");

    var macho = box01.value;
    if (macho == "nenhum") {
        box02.setAttribute("disabled");
    } else if (mapMachoFemeas[macho]) {
        box02.options.add(novaOpcao("0", "Nenhum"));       
        for (var femea of mapMachoFemeas[macho]) {
            box02.options.add(novaOpcao(femea.valor, femea.texto));       
        }
    }
}

function verificarCruzamentos(){
    // Validação Albino
    if(box01.value == "albino" && box02.value == "0"){
        txtArea.innerHTML = "";
    }
    else if(box01.value == "albino" && box02.value == "verde-azul"){
        txtArea.innerHTML = "M Verde/Azul\nM Azul\nF Lutino/Azul\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "albino"){
        txtArea.innerHTML = "M Albino\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "azul"){
        txtArea.innerHTML = "M Azul\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "cremino"){
        txtArea.innerHTML = "M Cremino\nM Albino\n\nF Cremino\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "turquesa-azul"){
        txtArea.innerHTML = "M Turquesa/Azul\nM Azul\n\nF Cremino\nF Albino";
    }
    else if(box01.value == "albino" && box02.value == "lutino"){
        txtArea.innerHTML = "M Lutino/Azul\nF Lutino/Azul";
    }
    else if(box01.value == "albino" && box02.value == "lutino-azul"){
        txtArea.innerHTML = "M Lutino/Azul\nM Albino\n\nF Lutino/Azul\nF Albino";
    }
}
<form>
    <div id="container-form">
        <label for="box01">Macho</label>
        <select id="box01" name="box01" onchange="atualizarFemeas()">
            <option value="nenhum">Nenhum</option>
            <option value="albino">Ring Neck - Albino</option>
            <option value="azul">Ring Neck - Azul</option>
            <option value="canela">Ring Neck - Canela</option>
            <option value="canela-azul">Ring Neck - Canela Azul</option>
        </select>
        <label for="box01">Fêmea</label>
        <select id="box02" disabled>

        </select>
        <button type="button" onclick="verificarCruzamentos()">Verificar</button>
    </div>
    <textarea id="txtArea" rows="10" cols="29" disabled></textarea>
</form>

I also changed the function names to something more meaningful (because myFunction is very generic and does not help to indicate what the function does). It may seem a silly detail, but giving better names helps a lot when programming.


For the function that shows the result, I did not understand the logic of the combinations, but you could have a similar idea: create a mapping with the possibilities and refer it with the indicated values. Something like that:

var cruzamentos = {
    "albino": {
        "verde-azul": "resultado do cruzamento de macho albino com fêmea verde-azul",
        "cremino": "resultado do cruzamento de macho albino com fêmea cremino"
    },
    "azul": {
        "verde-azul": "resultado do cruzamento de macho azul com fêmea verde-azul",
        "cremino": "resultado do cruzamento de macho cremino com fêmea cremino"
    }
};


function verificarCruzamentos(){
    if (cruzamentos[box1.value] && cruzamentos[box1.value][box02.value]) {
        txtArea.innerHTML = cruzamentos[box1.value][box02.value];
    } else {
        txtArea.innerHTML = "";
    }
}

I am suggesting this because, as I said, I did not understand the logic for generating the results very well. If you have a more "exact" rule, you could do something more "clever", but that eliminates this lot of if and leaves things more organized (if you need to add some more combination, just change the maps).

  • The Final would be another validation. Example let’s assume that in the first field "select male" chose albino and in the second "select female" chose blue .... ai within the textarea would have to give the result of crossing the genetics of the two. In this case I would have to create another object?

  • @Gabrielmariano So it would be this object cruzamentos that I said at the end

  • ah I got it, thank you very much! I’m going to take a test.

  • @Gabrielmariano Blz. Don’t forget that, if the answer solve your problem, you can accept it, see here how and why to do it. It is not mandatory, but it is a good practice of the site, to indicate to future visitors that it solved the problem. And when I get 15 points, you can also vote in all the answers you found useful.

  • Leave it ;] ! I’m running the tests.

  • I’m sorry for my ignorance @hkotsubo, but I couldn’t understand the Cross checkCross( ) ...being more specific, I couldn’t understand how it’s validating the " crossings[box1.value][box02.value] "

  • @Gabrielmariano It checks if there is value in the object cruzamentos. For example, if you choose "none", the value of the boxes will be 0 and to fetch cruzamentos[0] You won’t find anything (and then he falls in Else) - I edited now to change the check, because both the male and the female can be "none", so the if have to treat these 2 cases

  • @Gabrielmariano Complementando, this if works because null values are considered false, so you can test any object on an if, see more about it here: https://answall.com/q/271693/112052

  • It worked, thank you!

Show 4 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.