user3511871
user3511871

Reputation: 45

.hasClass() on dynamically added class doesn't work

I'm currently writing a simple script using jQuery which check if all the files (sent via AJAX) are properly uploaded before submitting the complete form. So the deal is: when the user drop an image into the browser (drag'n'drop), it's sent to the server using AJAX and when the upload is finished, it simply add a class "done" to some div tag.

So whenever the user drops an image, it adds this kind of div:

<div class="preview">/* blablabla other div and span classes */</div>

And when the upload is complete, it simply looks like this:

<div class="preview done">/* blablabla other div and span classes */</div>

Everything works like a charm, so here's the interesting part from the form:

<form action="target.php" method="post" enctype="multipart/form-data" 
onsubmit="return checkUploadFiles();">

It calls this JS function in order to prevent submitting if one files is not fully uploaded yet:

function checkUploadFiles(){
    $(".preview").each(function(i, val) {
        if(!val.hasClass('done')){
            alert("Something is not fully uploaded yet, please wait");
            return false;
        };
    });
    return true;
};

But... The form is sent anyway, even if there's 15 images uploading right now and 15 div tags having the .preview class but not the .done class.

I'm sure Iv'e done some stupid mistakes or that's just something I don't know about .each() or .hasClass(), can someone help please?

Thanks in advance!

EDIT: Here's the corrected script, considering the two mistakes I've made:

function checkUploadFiles(){
    var ret = true;
    $(".preview").each(function() {
        var $this = $(this);
        if(!$this.hasClass('done')){
            alert("Something is not fully uploaded yet, please wait");
            ret = false;
        };
    });
    return ret;
};

Upvotes: 2

Views: 2097

Answers (3)

user1618236
user1618236

Reputation:

To expand on my comment to provide an alternative to Ethan's method you can just 'jQuerify' the dom element that you are getting in the each loop, so your code would look like this:

function checkUploadFiles(){
    var isDone = true;
    $(".preview").each(function(i, val) {
        if(!$(val).hasClass('done')){
            alert("Something is not fully uploaded yet, please wait");
            isDone = false;
        };
    });
    return isDone;
};

This method is helpful if you still need the index value as well and avoids any what is this confusion.

Edited to also resolve the problem of returning false in the each loop using a boolean variable instead of hard coded boolean values.

Upvotes: 1

Ethan Brown
Ethan Brown

Reputation: 27282

In .each, val (and this) are the DOM object, not the jQuery-wrapped object. So what you want is this instead:

function checkUploadFiles(){
    $(".preview").each(function() {
        var $this = $(this);
        if(!$this.hasClass('done')){
            alert("Something is not fully uploaded yet, please wait");
            return false;
        };
    });
    return true;
};

It's a good idea to create a $this variable in case you do anything in callbacks (because you can't trust the value of this inside inner functions).

Upvotes: 1

Arun P Johny
Arun P Johny

Reputation: 388316

You are returning false from the each loop, not from the validate method so irrespective of the validation it will always return true.

Also val is a dom element reference, not a jQuery object so it doesn't have the hasClass() method.

function checkUploadFiles() {
    if (!$(".preview").not('.done').length) {
        alert("Something is not fully uploaded yet, please wait");
        return false;
    };
    return true;
};

Upvotes: 3

Related Questions