I have a vue app. I use this.data to access it's data variables and methods.
In a certain method I have to use img.onload to get the width of an image. But there are 2 "this" now and vue js methods and variables are not working now. I need an alternative solution so both will work.
vueMethod(url) {
var img = new Image();
img.onload = function() {
this.size = {this.width,this.height} //size is a vue variable
}
img.src = url;
}
You could assign this to a variable called vm before calling img.onload function as follows
vueMethod(url) {
var img = new Image();
let vm = this;
img.onload = function() {
vm.size = { this.width, this.height } //size is a vue variable
}
img.src = url;
}
You can use an arrow function (documentation) to keep the englobing scope:
vueMethod(url) {
var img = new Image();
img.onload = () => {
this.size = {img.width, img.height}
}
img.src = url;
}
In this example, this will have the same reference as if you used it next to var img
You should save Vue instance into a variable outside the img.onload scope
try with:
vueMethod(url) {
var img = new Image();
var vm = this;
img.onload = function() {
vm.size = {this.width,this.height} //size is a vue variable
}
img.src = url;
}
Put var that = this; inside your img funciton.
That will give you scope in your function, or bind your function when you call it e.g
vueMethod("url").bind(this)
So when you use a function with the keyword function it creates a new scope for this to refer to consider the below example
const obj = {
size: 10,
testFunc() {
console.log(this, 'now obj')
const func = function () {
// this now refers to function its currently in
}
const otherFunc = () => console.log(this, 'refers to obj still')
},
testFunc2: () => {
console.log(this, 'now window')
}
}
any questions let me know and i'll be happy to help
const obj = {
size: 10,
vueMethod(url) {
console.log(this.size, 'this now refers to obj')
const img = new Image();
const self = this;
img.onload = function() {
console.log(this, 'this now refers to img')
console.log(self.size, 'but you can reassign this to a var outside the scope');
self.size = {
width: this.width,
height: this.height
}
};
// mocking the onload dont include this
img.onload();
img.src = url;
}
}
obj.vueMethod()
Related
Following is a simple class definition. this.bounds is undefined in the console so i am wondering how can i access and alter bounds inside a callback. The goal is after the image is loaded, the bounds will be set to bounds.width = image.width etc. Thanks!
function Car() {
this.image = new Image();
this.bounds = new Rectangle(0, 0, 0, 0);
this.setImage = function(ii){
this.image.src = ii;
this.image.onload = function () {
console.log("image was loaded " + this.bounds);
}
};
}
Can you try doing :
this.image.onload = function () { console.log("image was loaded " + this.bounds); }.bind(this)
"bind" is used to bind the current scope of this to any function.
Whenever you call the function in future, the bound reference of this will be used.
Please refer this link : what is bind in javascript
Inside onload callback this no longer points to Car instance but to image because it's called by image object when image is loaded. To access Car methods inside this callback you can:
use bind method which returns new function inside which this is set the to value passed as argument to bind
this.image.onload = function () {
console.log("image was loaded " + this.bounds);
}.bind(this)
You can read more about bind here
in ES2015 you can use arrow function which also preserves this value:
function Car() {
this.image = new Image();
this.bounds = new Rectangle(0, 0, 0, 0);
this.setImage = function(ii){
this.image.src = ii;
this.image.onload = () => {
console.log("image was loaded " + this.bounds);
}
};
}
You can read more about arrow functions here
you can also define a variable that will hold a value of this
function Car() {
this.image = new Image();
this.bounds = new Rectangle(0, 0, 0, 0);
var self = this;
this.setImage = function(ii){
this.image.src = ii;
this.image.onload = function () {
console.log("image was loaded " + self.bounds);
}
};
}
"this" inside function image.onload() is actually scoped under function setImage(), which definitely don't have this.bounds defined, hence you got it undefined.
One solution could be to assign this to any variable just before the line: this.image.onload = function () {
so it will change to:
var that = this;
this.image.onload = function () {
console.log("image was loaded " + that.bounds);
}
I think you should see this:
var doc, bod, htm, Img, C, E; // for reuse on other loads
addEventListener('load', function(){
doc = document; bod = doc.body; htm = doc.documentElement;
C = function(tag){
return doc.createElement(tag);
}
E = function(id){
return doc.getElementById(id);
}
Img = function(src, complete, context){
this.image = C('img');
var img = this.image;
var cx = context || this;
img.addEventListener('load', function(eventObj){
complete.call(cx, eventObj);
});
img.src = src;
this.imgMethod = fuction(){
this.newProp = 'this in here refers to instance of Img';
}
}
Car = function(){
this.setImg = function(src, complete){
return new Img(src, complete);
}
}
var what = new Car; // no args it's okay to not use () with new
var someImg = what.setImg('yourImgSrc.png', function(){
this.imgMethod(); console.log(this.newProp);
});
someImg.image.addEventListener('click', function(ev){
var bc = this.getBoundingClientRect();
var xy = {x:ev.clientX-bc.left, y:ev.clientY-bc.top};
console.log(xy);
});
});
Note: this is only an example of this binding using call
UPDATED
I have an HTML code below:
<canvas id="canvas1"></canvas>
<canvas id="canvas2"></canvas>
I have a function below:
var Context;
function onSign(canvas){
var ctx = document.getElementById(canvas).getContext('2d');
SigWebSetDisplayTarget(ctx);
tmr = setInterval(SigWebRefresh, 50);
}
function SigWebSetDisplayTarget( obj ){
Context = obj;
}
I called the function OnSign twice with different canvas id parameters.
OnSign('canvas1');
OnSign('canvas2');
Below is the SigWebRefresh function that is repeatedly called for a reason.
function SigWebRefresh(){
xhr2 = new XMLHttpRequest();
requests.push(xhr2);
xhr2.open("GET", baseUri + "SigImage/0", true );
xhr2.responseType = "blob"
xhr2.onload = function (){
var img = new Image();
img.src = 'image.jpg';
img.onload = function (){
Ctx.drawImage(img, 0, 0);
revokeBlobURL( img.src );
img = null;
}
}
xhr2.send(null);
}
After that, I noticed that the two canvas was being updated and the image is loaded to the 2 canvas. Why is it? I have to load the image, only to the last canvas I supplied with the function OnSign. Where am I missing?
var Context; is declared in global scope
OnSign('canvas1');
OnSign('canvas2');
Doing so you are assigning value of canvas number two.
Update: http://jsfiddle.net/bmynvtLd/2/
This is what you desired to update both contexts? if yes this is how you pass the parameter to setInterval function: setInterval(function() {SigWebRefresh(ctx)}, 300);
running example:
var images = ['http://img09.deviantart.net/6d02/i/2015/284/0/b/beginning_autumn_by_weissglut-d9cssxw.jpg', 'http://orig06.deviantart.net/063c/f/2013/105/3/6/free_crystal_icons_by_aha_soft_icons-d61tfi1.png', 'http://img15.deviantart.net/b126/i/2015/118/c/1/this_small_tree_by_weissglut-d8re8q7.jpg', 'http://img00.deviantart.net/84f8/i/2015/284/d/f/nuclear_light_by_noro8-d9cs4u6.jpg'];
function OnSign(canvas){
var ctx = document.getElementById(canvas).getContext('2d');
tmr = setInterval(function() {SigWebRefresh(ctx)}, 300);
}
OnSign('canvas1');
OnSign('canvas2');
var index = 0;
function MyIndex()
{
// console.log(index);
index = images.length == index ? 0 : index+1;
return images[index];
}
function SigWebRefresh(Context){
var img = new Image();
img.src = MyIndex();
img.onload = function (){
Context.drawImage(img, 0, 0);
img = null;
}
}
I'm trying to get my head around why this doesn't work and wondered if someone could help me out. Basically I need multiple instances of this object with different images and I need each object to store the image height/width for its associated image for further operations, however the onload event never fires?
Sorry guys to be clear heres the complete code, if you see the TestTheVar function imgW is never set to anything.
<script type="text/javascript">
(function() {
var myTest = new TestObj();
mytest.TestTheVar();
})();
function TestObj() {
this.img = new Image();
this.img.onload = function(){
this.imgW = this.img.width;
this.imgH = this.img.height;
};
this.img.src = "reel_normal.PNG";
this.TestTheVar = function() {
alert(this.imgW);
}
}
</script>
You have two problems here
1) scope
2) timing
Scope, as mentioned in other answers refers to the fact that this inside the onload function is the Image object and not your TestObj so you would need to do the following:
<script type="text/javascript">
(function() {
var myTest = new TestObj();
mytest.TestTheVar();
})();
function TestObj() {
var self = this;
this.img = new Image();
this.img.onload = function(){
self.imgW = this.width;
self.imgH = this.height;
};
this.img.src = "reel_normal.PNG";
this.TestTheVar = function() {
alert(this.imgW);
}
}
</script>
Timing refers to the fact that you cannot assume the image has finished loading by the time you are trying to access height and width. This is what callbacks are good for:
<script type="text/javascript">
(function() {
var myTest = new TestObj(function() {
myTest.TestTheVar();
});
})();
function TestObj(cb) {
cb = cb || function() {};
var self = this;
this.img = new Image();
this.img.onload = function(){
self.imgW = this.width;
self.imgH = this.height;
cb();
};
this.img.src = "reel_normal.PNG";
this.TestTheVar = function() {
alert(this.imgW);
}
}
</script>
this is a keyword that belongs to each function.
In the load event listener it will be the image, not your TestObj instance.
Therefore, you can
Use this.img.imgW to get it:
function TestObj() {
var that = this;
this.img = new Image();
this.img.onload = function(){
this.imgW = this.width;
this.imgH = this.height;
that.testTheVar();
};
this.img.src = "reel_normal.PNG";
this.testTheVar = function() {
alert(this.img.imgW);
};
}
Store it in your TestObj instance:
function TestObj() {
var that = this;
this.img = new Image();
this.img.onload = function(){
that.imgW = this.width;
that.imgH = this.height;
that.testTheVar();
};
this.img.src = "reel_normal.PNG";
this.testTheVar = function() {
alert(this.imgW);
};
}
Customize this inside the event handler to be your TestObj instance:
function TestObj() {
this.img = new Image();
this.img.onload = (function(){
this.imgW = this.img.width;
this.imgH = this.img.height;
this.testTheVar();
}).bind(this);
this.img.src = "reel_normal.PNG";
this.testTheVar = function() {
alert(this.imgW);
};
}
Code:
var getImageFromUrl = function(url, callback) {
var img = new Image();
img.onError = function() {
alert('Cannot load image: "'+url+'"');
};
img.onload = function() {
callback(img);
};
img.src = url;
}
getImageFromUrl(somurl, Nextline);
LINE1-//should come here after callback(img)
I wanted that after img.onload function the compiler will run code in line1
Actually you can do this using JQuery Callback function.
var getImageFromUrl = function(url, callback) {
var img = new Image();
img.onError = function() {
alert('Cannot load image: "'+url+'"');
};
img.onload = function() {
callback(img);
};
img.src = url;
}
var callBack = $.Callbacks();
callBack.add(getImageFromUrl(somurl, Nextline));
callBack.add(function(){
// LINE 1 logic can be executed here.
});
callBack.fire();
For further reference, please refer to here
I'm new using JS. I want to keep all of the information about an object in one place.
So I've made this function:
function Obiekt(img) {
this.img = img;
this.ready = false;
this.image = new Image();
this.image.src = this.img;
this.image.onload = function() {
ready = true;
};
this.x = 0;
this.y = 0;
this.rotation = 0;
}
Then I've made my object, named hero.
var hero = new Obiekt("images/hero.png");
Problem is, hero.ready is always false and I can't draw this.
if (hero.ready) {
ctx.drawImage(hero.image, 0, 0);
}
Can you help me?
Two problems :
ready can't be found
If your image is cached (depending on the browser), the order you used can't work as the image isn't loaded after you set the callback.
Here's a solution :
var _this = this;
this.image.onload = function() {
_this.ready = true;
};
this.image.src = this.img;
(and I'd add that the naming isn't very good : I'd prefer imgsrc over img)