I'm learning how to actually use JavaScript. I've run into a situation where I'm getting an error. The error is: TypeError: 'undefined' is not an object (evaluating 'this.flagged'). I've narrowed down my code to where its happening. My code looks like this:
var flagged = false;
var intervals = [];
return {
flagged: flagged,
intervals: intervals,
createInterval : function (options) {
var defer = $q.defer();
if (this.throwsError) {
defer.reject('There was an error creating the interval.');
} else {
this.intervals.push(
$interval(function() {
console.log('here 1');
console.log(this.flagged);
},
1000
));
}
}
};
The error gets thrown at the: console.log(this.flagged); I'm guessing it has to do with the fact that "this" isn't visible. Yet, if "this" isn't visible, I'm not sure how to get the value for flagged. Can someone please explain to me what I need to do to get the value for flagged?
Thank you!
When you are using this inside $interval it won't be pointing to your original object, however, you can do this:
var flagged = false;
var intervals = [];
return {
flagged: flagged,
intervals: intervals,
createInterval : function (options) {
var defer = $q.defer(),
self = this;
if (this.throwsError) {
defer.reject('There was an error creating the interval.');
} else {
this.intervals.push(
$interval(function() {
console.log('here 1');
console.log(self.flagged);
},
1000
));
}
}
};
notice var self = this;
In JavaScript,
var flagged
will be a scoped variable, i think what you need here is a global scope variable for that, simply remove var from behind it.
flagged = false;
that should do the trick.
Related
I have a long running function that I don't really care about handling properly. Is it bad practice to just hand it off to the event loop along with an empty callback and move on. Something like this:
var takeSomeTime = function(callback) {
var count = 0,
max = 1000,
interval;
interval = setInterval(function() {
count++;
if (count === max) {
interval.clearInterval();
return callback();
}
}, 1000);
};
var go = function(callback) {
// do some stuff
takeSomeTime(function(err) {
if (err) {
console.error(err)
}
// take all the time you need
// I'm moving on to to do other things.
});
return callback();
};
go(function(){
// all done...
});
I don't know how your question is related to memory leaks, but one could certainly think of useful applications of passing empty function around in general. You basically could pass an empty function to third party code, that expects a function and doesn't check if it actually got one. Just like in your example, or this small logging library:
// Javascript enum pattern, snatched from TypeScript
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
LogLevel[LogLevel["WARN"] = 1] = "WARN";
LogLevel[LogLevel["ERROR"] = 2] = "ERROR";
LogLevel[LogLevel["FATAL"] = 3] = "FATAL";
})(LogLevel || (LogLevel = {}));
// end enum pattern
var noLog = function() {}; // The empty callback
function getLogger(level) {
var result = {
debug: noLog,
warn: noLog,
error: noLog
};
switch(level) {
case LogLevel.DEBUG:
result.debug = console.debug.bind(console);
case LogLevel.WARN:
result.warn = console.warn.bind(console);
case LogLevel.ERROR:
result.error = console.error.bind(console);
}
return result;
}
var log1 = LogFactory.getLogger(LogLevel.DEBUG);
var log2 = LogFactory.getLogger(LogLevel.ERROR);
log1.debug('debug test');// calls console.debug and actually displays the
// the correct place in the code from where it was called.
log2.debug('debug test');// calls noLog
log2.error('error test');// calls console.error
You basically return the empty function noLog back to the consumer of our library in order to disable logging for a particular log level, yet it can be called with any number of arguments without raising errors.
Can someone shed some light as to why this doesn't work the way I think it should (or what I'm overlooking).
function Pane(data) {
var state = {
show: function(data) {
var pane = document.querySelector('.pane[data-content='+data.target+']');
pane.classList.add('active');
},
hide: function(data) {
var pane = document.querySelector('.pane[data-content='+data.target+']');
var paneSibling = $(pane.parentNode.childNodes);
paneSibling.each(function(sibling) {
if(check.isElement(sibling)) {
var isActive = sibling.classList.contains('active');
if(sibling != pane && isActive) {
sibling.classList.remove('active');
};
};
});
}
}
return state;
}
So I can console log Pane(arg).show/hide and it'll log it as a function, so why is it when I call Pane(arg).show it doesn't do anything? The functions in the object work (outside of the constructor function in their own functions).
The function is returning the state object, so it will never return the constructed object, even when used with new. Since state contains those methods, you can just call the function and immediately invoke one of the methods on the returned object.
Now, if you're expecting show and hide to automatically have access to data via closure, it's not working because you're shadowing the variable by declaring the method parameters. You can do this instead:
function Pane(data) {
var state = {
show: function() {
var data = data || arguments[0];
var pane = document.querySelector('.pane[data-content='+data.target+']');
pane.classList.add('active');
},
hide: function() {
var data = data || arguments[0];
var pane = document.querySelector('.pane[data-content='+data.target+']');
var paneSibling = $(pane.parentNode.childNodes);
paneSibling.each(function(sibling) {
if(check.isElement(sibling)) {
var isActive = sibling.classList.contains('active');
if(sibling != pane && isActive) {
sibling.classList.remove('active');
};
};
});
}
}
return state;
}
Then you can use it like this:
Pane({}).show();
Or like this:
var p = Pane();
p.show();
Or force a new argument when needed:
p.show({foo:'bar'});
You are overriding the original argument in each function.
So what you are doing is to find elements with the attribute data-content='undefined'
This obviously doesn't work.
So to fix this you should just remove the data argument in the show/hide function.
Here is a plnkr showing the problem and fix.
I'm trying to access the variable np defined from within a function block; however, I am running into some issues when I call this.items.push(plumbers). I get TypeError: Cannot call method push of undefined
myApp.factory('np', function($resource, nearbyPlumbers){
var np = function(){
this.items = [];
this.busy = false;
this.limit = 5;
this.offset = 0;
};
np.prototype.nextPage = function(){
if (this.busy) return;
this.busy = true;
var temp;
nearbyPlumbers.nearby({lat: -37.746129599999996, lng: 144.9119861}, function(data){
angular.forEach(data, function(plumber){
alert('yay');
//this.items.push(plumber);
console.log(plumber);
console.log(this.items); // <--- This wont work. How do I access this.items
});
});
};
return np;
});
np.prototype.nextPage = function () {
if (this.busy) return;
this.busy = true;
var temp;
var that = this; // add this line
nearbyPlumbers.nearby({
lat: -37.746129599999996,
lng: 144.9119861
}, function (data) {
angular.forEach(data, function (plumber) {
that.items.push(plumber); //access using "that"
console.log(plumber);
console.log(that.items);
});
});
};
I'm really curious why you're using this, since it's going to be a different this depending on what scope accessing the singleton from. That would explain the error that you're getting.
I would strongly suggest reading up on factories in Angular and then taking another look at the code. The services docs are a good place to start and this question is good as well.
I get an error passing back an object from function to calling function.
What am I doing wrong?
function stStartProcessing()
{
var returnValue = {};
returnValue = srGetNextRecord(); // returnValue is undefined
}
function srGetNextRecord()
{
var returnValue = {};
returnValue.addressToArray = "AAA";
returnValue.sequence = "111";
console.log(returnValue); // this works
return returnValue;
}
There must be a different problem in your code, since what you posted works fine.
The modified code below shows 111. See this DEMO
function stStartProcessing()
{
var returnValue = {};
returnValue = srGetNextRecord(); // returnValue is undefined -- no, it's not
console.log(returnValue.sequence); //shows 111
}
function srGetNextRecord()
{
var returnValue = {};
returnValue.addressToArray = "AAA";
returnValue.sequence = "111";
console.log(returnValue); // this works
return returnValue;
}
stStartProcessing();
On a separate note, when writing JavaScript, please get into the habit of putting your opening braces on the same line—always. For what you have above it won't make a difference, but if you ever do this:
function foo()
{
return
{
x: 1,
y: 2
};
}
horrible things will happen—a semicolon will be inserted after the word return, thereby killing your return value, and causing a script error.
I am using setTimeout to create animation in Javascript, but it does not seem to work. Only the 1st move of the animation is executed, no subsequent moves.
I tried on two different laptops using Firefox, one doesn't throw any error, but the one says self.animateCallback is not a function. I also see other errors like saying my timeout function is useless or "compile-and-go" when I tried diff ways. Doesn't seem to get it working. I tried "function(self){self.animateCallback()}" and "self.animateCallback" (with and without quotes).
The code is below, it is part of a prototype method.
increment : function(incr, target, tick) {
var self = this;
self.animateCallback = function()
{
var done = Math.abs(self.currValue - target) < Math.abs(incr);
if(!self.animateCallback || done) {
if(done) {
self.updateAngle(self.currValue/self.maxValue);
self.stopAnimation(); //just setting animateCallback to null
}
}
else
{
self.updateAngle((self.currValue+incr)/self.maxValue);
setTimeout(self.animateCallback, tick);
}
}
self.animateCallback.call();
},
I've got a feeling the problem has something to do with the line setTimeout(self.animateCallback..., which is accessing the function through a closure and a property. It should be neater, at least, to do it like this:
increment : function(incr, target, tick) {
var self = this;
var animateCallback = function()
{
var done = Math.abs(self.currValue - target) < Math.abs(incr);
if(done) {
self.updateAngle(self.currValue/self.maxValue);
self.animateTimeout = null;
}
else
{
self.updateAngle((self.currValue+incr)/self.maxValue);
self.animateTimeout = setTimeout(animateCallback, tick);
}
}
animateCallback();
},
stopAnimation: function() {
if (this.animateTimeout) {
clearTimeout(this.animateTimeout);
this.animateTimeout = null;
}
},
I think the error is that some other code is changing the value of self.animateCallback to something else. The first time through, setTimeout has the correct value for self.animateCallback, but after the first time, the value of self.animateCallback has changed to something else, which isn't a function, but is still a non-falsy value so that !self.animateCallback returns false.
You can try changing the if statement to this:
if((typeof self.animateCallback !== "function") || done) {
if(done) {
self.updateAngle(self.currValue/self.maxValue);
self.stopAnimation(); //just setting animateCallback to null
}
}
try to pass an anonymous function to setTimeout, like
setTimeout(function(){ self.animateCallback(); }, tick);
hope it'll help.