1

I have a form with 4 input (can be even many more) where the user can put a number or nothing. The only rule is that if you put a number in a input you cannot submit if the same number is in another input (no duplicates). You can submit with as many empty input as you want.

To validate the input I compare the length of the array of all the inputs with the same array with only unique values. If they have the same length it's ok. I need to improve my code because now it works only if the user enters all the input fields. If some inputs are empty they are considered in the array with unique value as they all have "" as a value. So, if the user enters just one number I will get that array length is 4 and array unique is 2 but it should be 1 and 1 (skipping the blank items).

I was thinking about using splice() on arr, but is this the best way to do this validation? **EDIT: I applied splice BUT if the array is ('1','','') my code gives me ('1','') instead of just (1) as I'd expect... ** This is because splice remove the item and change array length so that the for loop point to the wrong index. Any idea? HTML:

<div class="sez-form">
    <fieldset>
        <legend>Messaggi inclusi</legend>
        <div class="percheckbox">
            <input class="checkseq" type="checkbox" value="1" name="messaggio[0]">
            Prova di messaggio che scorre<br>
            <label>Ordine: </label>
            <input class="seq" type="text" name="ordine[0]" maxlength="2" size="2">
        </div>

        <div class="percheckbox">
            <input class="checkseq" type="checkbox" value="3" name="messaggio[1]">
            Titoli di film<br>
            <label>Ordine: </label>
            <input class="seq" type="text" name="ordine[1]" maxlength="2" size="2">
        </div>

        <div class="percheckbox">
            <input class="checkseq" type="checkbox" value="6" name="messaggio[2]">
            Prova a testo fisso<br>
            <label>Ordine: </label>
            <input class="seq" type="text" name="ordine[2]" maxlength="2" size="2">
        </div>
        <br style="clear: both;">
    </fieldset>
</div>

JAVASCRIPT:

function uniqueArray(arr) {
    return $.grep(arr,function(v,k) {
        return $.inArray(v,arr) === k;
    });
}

$(document).ready(function() {
    $('#invia').click(function(e) {
        e.preventDefault();
        var arr = $(".seq").map(function(){ return $(this).val(); }).toArray();
        var empty = $(".seq").filter(function() {
            return this.value == "";
        })
    for (index = 0; index < arr.length; ++index) {
        if (arr[index]=='') {
            new_arr = arr.splice([index],1);
        }
        console.log(arr);
    }

        if(empty.length == $('.seq').length) {
            alert('Non hai scelto alcun messaggio per il workflow. Correggi per procedere.');
        }
        else if(uniqueArray(arr).length != $('.seq').length) {
            console.log(uniqueArray(arr));
            alert('Ci sono voci duplicate nella sequenza. Correggi per procedere.');
        }
        else if($('#dt_from').val()=='__/__/____ __:__') {
            alert('Scegli data e ora di inizio validit\u00E0 per il workflow');
        }
        else if($('#dt_to').val()=='__/__/____ __:__') {
            alert('Scegli data e ora di fine validit\u00E0 per il workflow');
        }
        else {
            ajaxSubmit();
        }
    });
});
Lelio Faieta
  • 6,457
  • 7
  • 40
  • 74

3 Answers3

1

Maybe I don't understand what you are trying to do, but why can't you do it very simply with something like:

$('#invia').click(function(e) {
    e.preventDefault();
    var unique = [], nonunique = [];
    $(".seq").each(function(index){
        var val = $(this).val();
        if (val !== "") {
            if ($.inArray(val, unique) !== -1) {
                nonunique.push(val);
            } else {
                unique.push(val);
            }
        }
    });
    // If unique and nonunique are empty, all inputs were blank
    // else if nonunique is empty, inputs are valid and in unique
});
  • Will try it. More or less it does what I am looking for. Or even it does two of my validations in one. Will try and let you know! – Lelio Faieta Feb 09 '15 at 16:25
  • Good too. I chosed the other answer only because it is close to my actual code. Thanks a lot to boths! – Lelio Faieta Feb 09 '15 at 16:27
  • I noticed I typed too quickly and forgot to extract the value. I fixed the example. –  Feb 09 '15 at 16:27
1

Here is another possible way to handle it. Here is the working JSFiddle. And here is the code:

$(function() {
    $("#submit").click(function() {
        //build a profile of the inputs
        var inputs = [];
        var values = [];
        var dups = false; //track duplicates on pass 1

        $(".seq").each(function(i, el) {
            var empty = (el.value == ""); //check if empty
            var exists = (!empty && $.grep(inputs, function(item, index) {
                return (item.Value === el.value);
            }).length > 0); //check if exists
            dups = (dups || exists); //track dups

            //add the new input item
            var obj = {
                Element: el,
                Value: el.value,
                Empty: empty,
                Exists: exists
            };
            inputs.push(obj);

            //conditionally add the sorting value
            if (!empty && !exists)
                values.push(el.value);
        });

        //Validate the inputs. If there are duplicates, don't submit
        $(".seq").css("background-color", "white"); //clear errors
        if (dups) {
            $(inputs).each(function(i, el) {
                if (el.Exists) 
                    el.Element.style.backgroundColor = "red";
            });
        } else {
            values = values.sort();
            alert(values);
        }
    });
});

With this method, at the end you have an array - inputs - of all of the elements with their statuses so that you can provide error handling on specific fields. In my example, the error fields turn red.

At the alert, you have a sorted array of the valid values.

jwatts1980
  • 7,254
  • 2
  • 28
  • 44
0

Use a hash to track values as you iterate. This example simply returns true or false, but you could also scan the entire array and return the repeated values.

function uniquifyArray(ary) { 
    var seen = {};
    var isUnique = true;
    /* iterate backwards since the array length will change as elements are removed */
    for (var i=ary.length; i--;) {
        /* remove blank/undefined */
        if (typeof ary[i] === 'undefined' || ary[i] === '') {                
            ary.splice(i,1);
        } else {   
            /* check if this value has already been seen */
            if (ary[i] in seen) { 
                isUnique = false;
                ary.splice(i,1);
            } else { 
                seen[ary[i]]=true;   
            }
        }
    }
    ary = ary.sort();
    return isUnique;
}

var test = [ '1','2','','','3','4','1' ];
uniquifyArray(test); // returns false, test = [ '1','2','3','4' ]

test = [ '1','2','','' ]
uniquifyArray(test); //true, test = ['1','2']
Ben Grimm
  • 4,316
  • 2
  • 15
  • 24
  • If this isUniqueArray([ '1','2','','','3','4','1' ]); is user input it should give me isUniqueArray([ '1','2','','3','4' ]); that is false 'cause the input is 7 items and the output is 5 only (duplicates exist). I'd like to sort input, change it in isUniqueArray([ '1','2','3','4','1' ]); that is 5 items – Lelio Faieta Feb 09 '15 at 15:49
  • This is a validation function - doesn't modify the values at all. It seems you want a function that will sort, strip blanks _and_ fail if there are duplicates? – Ben Grimm Feb 09 '15 at 15:56
  • Yes, now I do it checking arr and arrUnique length... The blank items should be skipped because I can post an array even with one value and two empty but I cannot add this option to my code – Lelio Faieta Feb 09 '15 at 15:58
  • 1
    Updated the answer, I believe it does what you're looking for. – Ben Grimm Feb 09 '15 at 16:09
  • I'll give a check on the rest of my code. Anyway it is the right answer for me. – Lelio Faieta Feb 09 '15 at 16:26