Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

getting return values from load events or waiting till finished

Status
Not open for further replies.

1DMF

Programmer
Jan 18, 2005
8,795
0
0
GB
Hi,

Hope this makes sense!

Basically I have a file control on a form and when a file is selected I want to check a few details and decide if the file is 'valid'

The initial function call needs a Boolean return value to decide if all was OK, but I can't get my head round how I do this when the code for a fileReader object and image object uses onload events.

Here is some code to hopefully explain better...

I call my function 'fileSelected' via a JQuery change event...


Code:
// upload file selected 
$('body').on('change','#file',function() {
    // validate selected file
    [b]if(fileSelected( $(this), fileObj ))[/b]
    {
        // show selected file.
        $(this).removeClass('invalid').addClass('valid');
        displayBanner();
    }
    else
    {
        $(this).removeClass('valid').addClass('invalid');
    }
    
});

fileSelected does a few things such as check file type and file size, I then do the following validation

Code:
// set up a fileReader object and image object
var reader = new FileReader();
fObj.file = new Image();

// load event to capture the file information.
reader.onload = (function(file) {

    // load event to check image dimensions
    fObj.file.onload = function(){
        
        if(this.width != fObj.imgWidth || this.height != fObj.imgHeight)
        {
            showDialog({content:'Image dimensions invalid. Must be (Width: ' + fObj.imgWidth + 'px, Height:' + fObj.imgHeight + 'px)'});
            clearFile(ele);
            return false;
        }
    };
    fObj.file.src = file.target.result;
});

// read selected file
reader.readAsDataURL(myFile);

// DO SOMETHING HERE TO CHECK AND RETURN TRUE OR FALSE

here is where I'm stuck for a start I know the 'return false' in the file.onload event is not returning to the fileSelected method, I doubt it's returning false to the fileReader reader.onload event either, how would you capture the return value of a bound function to an event handler?.

What I need after the 'read selected file' is to know was any of this OK, if so return true to the caller of fileSelected, otherwise false.

But I don't understand how I can do this?

I've googled and there is not a JS sleep/wait and apparently it's bad practice to try. I know there is some kind of when / deferred / promise in JQuery, but I could do with a hand getting my head round this if this is what I need to do.

How can you call a procedural function that needs to return a Boolean value when the function is creating event based actions and the procedural function ends before these events have finished but I don't want it to?

Advice appreciated.
1DMF

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
isn't the boolean returning to the fObj.onload object? the question is whether that event supports cancellation. perhaps better to unload the object programmatically.
 
I'm not sure but I don't want it to, I'm trying to return to the initial fileSelected function call but I think it's impossible because of the way event handlers are asynchronous.

I have a call if(fileSelected)...

So fileSelected needs to return true or false.

but in fileSelected it's creating an onload event for fileReader, which inside that has an onload event for the Image() object.

I see no way of getting the return code to fileSelected from inside the second onload event handler..

I've given up with this, it's flawed thinking as I'm trying to do something you simply can't do with events in this way.



"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
i can't see the fileSelected function

consider a closure instead for the callback

Code:
var reader = new FileReader();

reader.onload = (function(file){
    return function(e){        
        if(this.width != fObj.imgWidth || this.height != fObj.imgHeight){
            showDialog({content:'Image dimensions invalid. Must be (Width: ' + fObj.imgWidth + 'px, Height:' + fObj.imgHeight + 'px)'});
            clearFile(ele);
            return false;
        };
     };
})(file);

p.s. not sure i have that syntax quite right. may have some semicolons wrong.
 
consider a closure instead
what does that mean?

How have you tacked an argument on the end of the function like it's part of the signature?

here is the full fileSelected function
Code:
/ File selected helper
function fileSelected(ele,fObj)
{    

    // get selected file
    var myFile = ele.prop('files')[0];      
    fObj.fileSize = 0;
    
    if(myFile)    
    {       
        // add file details
        fObj.fileName = myFile.name;
        fObj.fileMIME = myFile.type;
                
        // validate file type
        if(! checkFile(fObj.fileName,fObj.fileType))
        {
            showDialog({content:'Invalid file selected! '+(fObj.fileInvalid||'')});
            clearFile(ele);
            return false;
        }                       
        
        // validate file size
        if(myFile.size > 1024 * 1024)
        {
            fObj.fileSize = (Math.round(myFile.size * 100 / (1024 * 1024)) / 100);
            
            // check file size
            if(fObj.fileSize > fObj.maxSize)
            {
                showDialog({content:'File size is too large. Max ' + fObj.maxSize + 'MB.'});
                clearFile(ele);
                return false;                
            }                
            else
            {
                fObj.sizeUnit = 'MB';
            }                       
        } 
        else
        {
            fObj.fileSize = (Math.round(myFile.size * 100 / 1024) / 100);
            fObj.sizeUnit = 'KB';            
        }
        
        // if image file check dimensions if provided
        if(fObj.fileType == 'img' && (fObj.imgHeight || fObj.imgWidth))
        {
            // set up a fileReader object and image object
            var reader = new FileReader();
            fObj.file = new Image();
            
            // load event to capture the file information.
            reader.onload = function(aFile) {
                
                // load event to check image dimensions                
                fObj.file.onload = function(){                   
                    if(this.width != fObj.imgWidth || this.height != fObj.imgHeight)
                    {
                        showDialog({content:'Image dimensions invalid. Must be (Width: ' + fObj.imgWidth + 'px, Height:' + fObj.imgHeight + 'px)'});
                        fObj.file = undefined; 
                        ele.trigger('imageFailed',fObj);
                        clearFile(ele);                        
                    } 
                    else
                    {
                        ele.trigger('imageLoaded',fObj);
                    }                    
                };
                
                fObj.file.src = aFile.target.result;
                                
            };
            
            // read selected file
            reader.readAsDataURL(myFile);            
                      
        }
        else
        {
            // clear previous file
            fObj.file = undefined;
            
            // show file details
            showFileDetails(fObj);                    
            
        }                    
        
        return true;
    
    }     
    else
    {
        clearFile(ele);
        return false;
    }
    
}

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Re the tack on: That's what a closure is!

I'm only on a mobile at the moment so difficult to take a wider look at that function.
 
you've melted my tiny brain!


So you are instantly running a function passing in file (via the closure), to a function that returns another function using file?

How does this help, what does this achieve?

How does the Image object src ever get populated from the fileReader source?



"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
Well I've tried to use closures, but I'm not getting anywhere...
Code:
// load event to capture the file information.
reader.onload = (function(aFile) {
    
    // load event                 
    fObj.file.onload = (function(aFile){     
                
        // check dimensions if provided      
        if( (fObj.imgHeight || fObj.imgWidth) && this.width != fObj.imgWidth || this.height != fObj.imgHeight) 
        {
            showDialog({content:'Image dimensions invalid. Must be (Width: ' + fObj.imgWidth + 'px, Height:' + fObj.imgHeight + 'px)'});
            fObj.file = undefined; 
            ele.trigger('imageFailed',fObj);
            clearFile(ele);                        
        } 
        else
        {
            ele.trigger('imageLoaded',fObj);
        }                    
    })(aFile);                
    
    fObj.file.src = aFile.target.result;
                    
})(myFile);

it errors with
TypeError: aFile.target is undefined

I'm not sure what it is I'm doing or why I'm doing it and would appreciate some guidance.

Regards,
1DMF

"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
I'm not familiar with the filereader html5 thing other than from answering (or trying to) previous questions from you.

i will give it all a proper try this evening or on the train.

 
No worries, I just need to understand the scope of the closure and its usefulness, before I can apply it.

I've have a working app currently now that I have refactored to use custom events, so this is no longer an pressing issue the needs solving, but more for enlightenment and progressive improvement of my JS coding.

As always your input is very much appreciated.

I've read a few articles, but its all still a little murky!

I got the previous link posted above from


where an example given is
Code:
function foo(x) {
  var tmp = 3;
  function bar(y) {
    alert(x + y + (++tmp)); // will alert 16
  }
  bar(10);
}
foo(2);

Which I kind of get, though ++ in front of a variable has me stumped. I would use var++ to increment a number, but when I tried that I get 15 as a result?

It's never easy learning a new concept especially when the coding style shown to explain it, uses syntax you don't understand. In this example you just want bar to see x from foo, ok I get it, but what is it giving if I apply the same to my code.

Having played a little it seems if you use closure, then the inner function can no longer see the initial function scoped arguments of 'fileSelected' so my ele & fObj vars are no longer available to the inner function?

I read closures as a way of giving access to vars normally outside the local lexical scope, but so far all I seem to have done is block access to vars accessible when not using closures?

Apparently the SO thread is meant to explain it to a 6 year old, I must have the brain of a 3 year old then! [baby]



"In complete darkness we are all the same, it is only our knowledge and wisdom that separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!"
Free Electronic Dance Music
 
on the ++ operator

the difference is when the increment is done, before or after the other operations.

so
Code:
var x = 10;
y = x;

//y = 10, x=10

y = x++;
//y = 10, x = 11

y = ++x;
//y = 11, x = 11

on the closures, I tend to use them most when i'm using anonymous functions inside event handlers, where another value cannot be known until the event is fired.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top