Faiz Shukri
Faiz Shukri

Reputation: 95

Get variable inside load function

I know this might probably been answered many times but I do not know the words to search for to find the answer. So here is the question.

I'm using javascript and I have

function getDataUrl( file ){
    var url = URL.createObjectURL( file ),
    canvas = document.createElement('canvas'),
    ctx = canvas.getContext("2d"),
    img = new Image,
    dataURL = '';

    img.load = function(){
        canvas.height = this.height;
        canvas.width = this.width;
        ctx.drawImage(this, 0, 0);
        dataURL = canvas.toDataURL("image/jpeg");
    };

    img.src = url;
    return dataURL;
}

then on the input I have this,

$('#file-input').on('change', function(e){
    var dataUrl = getDataUrl( e.target.files[0] );
    console.log( dataUrl );
});

But it return empty string (the initial one). I want the base64 data that already generated inside load.

I've try something like this

function getDataUrl( file ){
//... codes

    img.load = function(){
        //... codes
        dataURL = canvas.toDataURL("image/jpeg");
        return dataUrl;
    };
}

but of course it can't since it return to the load function and not to it's parent function.

How do I get dataUrl value inside load function ?

Thanks

Upvotes: 2

Views: 1939

Answers (2)

jfriend00
jfriend00

Reputation: 707208

The load event is asynchronous. That means it occurs sometime in the future AFTER your getDataURL() function has completed. Thus, you cannot return the value you want from the getDataURL() function because the image has not loaded yet and the load event handler has not yet been called. So, instead, you need to think asynchronously and program in a way that deals with that. The typical way of doing this is to pass in a callback function that will get called when the data is available and you can pass that data to the callback function.

There are many different ways to code this, but here's one way:

function getDataUrl( file, callback ){
    var url = URL.createObjectURL( file ),
    canvas = document.createElement('canvas'),
    ctx = canvas.getContext("2d"),
    img = new Image,
    dataURL = '';

    img.load = function(){
        canvas.height = this.height;
        canvas.width = this.width;
        ctx.drawImage(this, 0, 0);
        dataURL = canvas.toDataURL("image/jpeg");
        // pass the dataURL to the callback function
        callback(dataURL);
    };

    img.src = url;
}

getDataUrl("myfile.jpg", function(dataURL) {
    // code here to use the dataURL        
});

Upvotes: 0

Martin Tournoij
Martin Tournoij

Reputation: 27822

Your code, abbreviated, looks like this:

function getDataUrl() {
    dataURL = '';  

    img.load = function() {
        dataURL = 'Hello!';
    };

    return dataURL;
}

What img.load = function does is nothing except assign a function to img.load, the execution will then just continue with the return statement, meaning that your dataURL variable retains the original value.
You should realize that functions in Javascript van be assigned to variables just like a string or number can. It's doesn't need to be executed.
It may be a bit confusing, it's certainly different from many other languages, but you'll get the hang of it. Be sure to continue reading & learning about javascript.

You probably want to use img.onload, this will execute the function whenever the image is finished loading. But this can be whenever, maybe 1 second, maybe 10, maybe never.

What you need to do, is something like:

$('#file-input').on('change', function(e) {
    getDataUrl(e.target.files[0], function(dataUrl) {
        console.log(dataUrl);
    });
});

function getDataUrl(callback) {
    dataURL = '';  

    img.onload = function() {
        callback(dataUrl);
    };

    return dataURL;
}

Here you pass a function as an argument, an execute that function once the image finished loading, passing dataUrl as a parameter. This is a fairly common pattern in Javascript.

Upvotes: 1

Related Questions