Forcing parts of code to wait on others? - javascript

I was wondering if I can stop a function from even defining itself (basically I'm not using it, but it still defines itself, at least that's what I assume the problem is).
if (document.getElementById("loginLogoutButton").title!="התנתק/י") {
document.getElementById("username").value="asdf";
document.getElementById("password").value="asdf";
var target = document.getElementById("loginLogoutButton");
var clickevent = document.createEvent("MouseEvents");
clickevent.initEvent("click", true, true);
target.dispatchEvent(clickevent);
}
function loaded() {
var targLpink = document.getElementById ("iconImage_3");
var clickEvent = document.createEvent ("MouseEvents");
clickEvent.initEvent('dblclick', false, true);
targLpink.dispatchEvent(clickEvent);
}
window.addEventListener("load", setTimeout(loaded,3000));
var msgodd;
var msgeven;
var messages;
//The first error happens here as far as I can tell
//"Uncaught TypeError: undefined is not a function"
function list() {
msgeven = document.getElementsByTagName("even unread");
msgodd= document.getElementsByTagName("odd unread");
var k = msgodd.length+msgeven.length;
confirm(k);
var i = 0;
while ((i+2)< k) {
if (i%2==0 && i+2<msgeven.length){
messages.push(msgeven[i/2].id);
}
if(i%2==1 && i+2<msgodd.length){
messages.push(msgodd[(i-1)/2].id);
}
i=i+1;
}
alert(messages.length);
}
setTimeout(list, 9000);
I then get an error on tagname:
Uncaught TypeError: Cannot read property 'length' of undefined
I might also throw out that I have to use the setTimeout since I'm waiting for the page to load (it's not a different address, it opens up stuff within itself, so I can't use onload on that - at least when i tried it failed).

You're treating msgeven/msgodd as an array. But it's a NodeList! You can convert them with this:
msgeven = Array.prototype.slice.call(document.getElementsByClassName("even unread"));
msgodd = Array.prototype.slice.call(document.getElementsByClassName("odd unread"));

Related

Javascript Typedef Error when using parameters

What am I doing wrong, and how can one pass variables to a different function within the same wrapping variable/function.
Example:
function customFunctionWrap(){
this.myVar1 = 0;
this.getCurrentPosition = function(){
if (navigation.geolocation) {
navigator.geolocation.getCurrentPosition(function(position){});
}
},
this.doSomething = function(){ // Works
//Do something, return
this.callWithParams(); //Works
},
//If I remove passing in 'value1',calling it elsewhere works
this.doSomethingWithParams = function(value1){
//Use value1
//Return
},
this.callWithParams = function(){
var value1 = 'xyz'; //Is a variable that changes based on some DOM element values and is a dynamic DOM element
this.doSomethingWithParams(value1); //THROWS TYPEDEF ERROR: this.doSomethingWithParams is not a function
this.getCurrentPosition();
}
};
var local = new customFunctionWrap();
local.doSomething(); //WORKS
I know there is another way to do it and then directly use customFunctionWrap.callWithParams(), but am trying to understand why the former approach is erroring out.
var customFunctionWrap = {
myVar1 : 0,
callWithParams : function(){
}
}
What JS sees:
var customFunctionWrap = (some function)()
returned function is fired, because the last (), so it has to yield/return something, otherwise, like in your code it is "returning" undefined.
So your given code does not work.
The very first fix is to delete last 2 characters from
var customFunctionWrap = (some function)()
to make it return constructor.

"Illegal invocation" error for call to member of newly-created Web components object

When I try to run the clear function in the following code snippet in Chrome, I get an Uncaught TypeError: Illegal invocation error.
I'm creating a web component with some functions for a text input. This is my first method but I keep getting that error and I have no clue what it could be.
var XEditProto = Object.create(HTMLInputElement.prototype);
XEditProto.clear = function() {
this.value = '';
return "Erased";
}
var Edit = document.registerElement('x-edit', {
prototype: XEditProto,
extends: 'input'
});
document.body.appendChild(new Edit());
var XEditProto = Object.create(HTMLInputElement.prototype);
XEditProto.clear = function() {
this.value = '';
return "Erased";
}
var Edit = document.registerElement('x-edit', {
prototype: XEditProto,
extends: 'input'
});
var x = document.body.appendChild(new Edit());
...
x.clear();
Works as expected

JSLint unexpected 'that' message

I've just started using JSLint to make sure that the JavaScript code I'm creating at least meets some standards and I've got a confusing message:
JSLint: Unexpected 'that'.
The code is part of a solution to implement a progress bar, part of which is this object that handles timers and callbacks and is as follows (this is an extract from the beginning of a larger file, I can add the whole file if required):
var ProgressHandler = function () {
"use strict";
// Build a new object
var that = {};
// Add basic properties
that.taskid = 0;
that.timerid = 0; // Timer ID used to push refreshes
that.progressUrl = ""; // URL to invoke to read progress
that.interval = 500; // The interval for progress refresh
that.taskProgressCallback = null; // The user-defined callback that refreshes the UI
that.taskCompletedCallback = null; // The user-defined callback that finalizes the call
// Set progress url
that.setProgressUrl = function (url) {
that.progressUrl = url;
return this;
}
// Set frequency of refresh
that.setInterval = function (interval) {
that.interval = interval;
return this;
};
The message appears on the line that begins that.setInterval. There are further uses of that I but JSLint also says that it stops processing at this point. I've tried searching for this message but it's not listed specifically here or on jslinterrors.com.
Why is this appearing and what can I do to fix it? Or should it just be ignored?
The issue seems to be that you do not have a ; after the definition of that.setProgressUrl. Changing to:
// Set progress url
that.setProgressUrl = function (url) {
that.progressUrl = url;
return this;
};
Resolves the reported issue. You then have an issue in that you are missing a closing brace and semi colon at the end of the file, not sure if that is just a copy and paste issue. The complete script should look like:
var ProgressHandler = function () {
"use strict";
// Build a new object
var that = {};
// Add basic properties
that.taskid = 0;
that.timerid = 0; // Timer ID used to push refreshes
that.progressUrl = ""; // URL to invoke to read progress
that.interval = 500; // The interval for progress refresh
that.taskProgressCallback = null; // The user-defined callback that refreshes the UI
that.taskCompletedCallback = null; // The user-defined callback that finalizes the call
// Set progress url
that.setProgressUrl = function (url) {
that.progressUrl = url;
return this;
};
// Set frequency of refresh
that.setInterval = function (interval) {
that.interval = interval;
return this;
};
};

Mootools "Cannot read property 'call" of undefined"

I've got a website that is using MooTools. I've been getting the following errror, but can't figure out what is causing it. I've had very little luck tracing it out. Does anyone know what this might be? I haven't been able to find anything on the web about it.
Uncaught TypeError: Cannot read property 'call' of undefined mootools-core.js:4497
condition mootools-core.js:4497
defn mootools-core.js:4511
Stackoverflow has this question, but it does not relate as far as I can tell. Ideas?
Update
Having looked at this a bit more, the cause of the error is still mysterious. The offending line in my code is an addEvent call:
window.addEvent('load', preloader(preload));
The variable preload is an array of image urls. And the callback preloader is a method that preloads the images specified in preload. Here's the preloader method:
/**
* Event callback that preloads images
*/
function preloader(images) {
var img;
if ( images ) {
for (var i=0; i<images.length; i++) {
img = new Image();
img.src = images[i];
}
}
}
The line of mootools code specified by the error is this:
addEvent: function(type, fn){
var events = this.retrieve('events', {});
if (!events[type]) events[type] = {keys: [], values: []};
if (events[type].keys.contains(fn)) return this;
events[type].keys.push(fn);
var realType = type,
custom = Element.Events[type],
condition = fn,
self = this;
if (custom){
if (custom.onAdd) custom.onAdd.call(this, fn, type);
if (custom.condition){
condition = function(event){
//error here--> if (custom.condition.call(this, event, type)) return fn.call(this, event);
return true;
};
}
if (custom.base) realType = Function.from(custom.base).call(this, type);
}
var defn = function(){
return fn.call(self);
};
var nativeEvent = Element.NativeEvents[realType];
if (nativeEvent){
if (nativeEvent == 2){
defn = function(event){
event = new DOMEvent(event, self.getWindow());
if (condition.call(self, event) === false) event.stop();
};
}
this.addListener(realType, defn, arguments[2]);
}
events[type].values.push(defn);
return this;
},
Er. you are not passing a function as callback.
this:
window.addEvent('load', preloader(preload));
/**
* Event callback that preloads images
*/
function preloader(images) {
var img;
if ( images ) {
for (var i=0; i<images.length; i++) {
img = new Image();
img.src = images[i];
}
}
}
it will essentially invoke the preloader function immediately, not onload - and it will try to bind the event to the result of the preloader function, which does not return anything at all.
when the interpreter sees preloader(preload), it just runs it straight away. you can return a function or better yet, rewrite to:
window.addEvent('load', function(){ preloader(preload); });
// or even
window.addEvent('load', preloader.bind(this, preload));
Running example:
var imagesArray = new Array(50).join(',').split(',');
imagesArray = imagesArray.map(function(el, i){
return 'http://dummyimage.com/600x400/000/' + (255 - i) + '?' + +new Date();
});
function preloader(images) {
var img;
if ( images ) {
for (var i=0; i<images.length; i++) {
img = new Image();
img.src = images[i];
console.log(img.src);
}
}
}
window.addEvent('load', function(){
preloader(imagesArray);
});
<script src="//cdnjs.cloudflare.com/ajax/libs/mootools/1.5.0/mootools-core-full-nocompat.js"></script>
You can also have a look at my preloader class which gives you greater flexibility over how your images are pre-loaded, as well as progress etc. https://github.com/DimitarChristoff/pre-loader - it will actually wait for the images to download, allow you to choose how they are loaded etc.
mootools-more also has Asset.images you can use.
finally, not sure you want to bind to load event, which will trigger when all assets, including images, have been loaded, you should be able to start at domready instead.
It means, I believe, that mooTools is getting an undefined/malformed parameter in one of your call.
Find out which function is defined at line 4497 of mootools-core.js (can be an object method) and look for each call in your script. Log all parameters/object you're working with, and you'll find your error ;)
Edit
Seeing your code, I think your problem come from the fact that type is not declared inside condition. Try :
if (custom.condition){
condition = function(event,type){
if (custom.condition.call(this, event, type)) return fn.call(this, event);
return true;
};

JavaScript error: "is not a function"

It looks like "$smth is not a function" is a very common problem with JavaScript, yet after looking through quite a few threads I still cannot understand what is causing it in my case.
I have a custom object, defined as:
function Scorm_API_12() {
var Initialized = false;
function LMSInitialize(param) {
errorCode = "0";
if (param == "") {
if (!Initialized) {
Initialized = true;
errorCode = "0";
return "true";
} else {
errorCode = "101";
}
} else {
errorCode = "201";
}
return "false";
}
// some more functions, omitted.
}
var API = new Scorm_API_12();
Then in a different script I am trying to use this API in the following way:
var API = null;
function ScormProcessInitialize(){
var result;
API = getAPI();
if (API == null){
alert("ERROR - Could not establish a connection with the API.");
return;
}
// and here the dreaded error pops up
result = API.LMSInitialize("");
// more code, omitted
initialized = true;
}
The getAPI() stuff, looks like this:
var findAPITries = 0;
function findAPI(win)
{
// Check to see if the window (win) contains the API
// if the window (win) does not contain the API and
// the window (win) has a parent window and the parent window
// is not the same as the window (win)
while ( (win.API == null) &&
(win.parent != null) &&
(win.parent != win) )
{
// increment the number of findAPITries
findAPITries++;
// Note: 7 is an arbitrary number, but should be more than sufficient
if (findAPITries > 7)
{
alert("Error finding API -- too deeply nested.");
return null;
}
// set the variable that represents the window being
// being searched to be the parent of the current window
// then search for the API again
win = win.parent;
}
return win.API;
}
function getAPI()
{
// start by looking for the API in the current window
var theAPI = findAPI(window);
// if the API is null (could not be found in the current window)
// and the current window has an opener window
if ( (theAPI == null) &&
(window.opener != null) &&
(typeof(window.opener) != "undefined") )
{
// try to find the API in the current window�s opener
theAPI = findAPI(window.opener);
}
// if the API has not been found
if (theAPI == null)
{
// Alert the user that the API Adapter could not be found
alert("Unable to find an API adapter");
}
return theAPI;
}
Now, the API is probably found, because I do not get the "Unable to find..." message, the code proceeds to try to initialize it. But firebug tells me API.LMSInitialize is not a function, and if I try to debug it with alert(Object.getOwnPropertyNames(API));, it gives me a blank alert.
What am I missing?
For more generic advice on debugging this kind of problem MDN have a good article TypeError: "x" is not a function:
It was attempted to call a value like a function, but the value is not
actually a function. Some code expects you to provide a function, but
that didn't happen.
Maybe there is a typo in the function name? Maybe the object you are
calling the method on does not have this function? For example,
JavaScript objects have no map function, but JavaScript Array object
do.
Basically the object (all functions in js are also objects) does not exist where you think it does. This could be for numerous reasons including(not an extensive list):
Missing script library
Typo
The function is within a scope that you currently do not have access to, e.g.:
var x = function(){
var y = function() {
alert('fired y');
}
};
//the global scope can't access y because it is closed over in x and not exposed
//y is not a function err triggered
x.y();
Your object/function does not have the function your calling:
var x = function(){
var y = function() {
alert('fired y');
}
};
//z is not a function error (as above) triggered
x.z();
Your LMSInitialize function is declared inside Scorm_API_12 function. So it can be seen only in Scorm_API_12 function's scope.
If you want to use this function like API.LMSInitialize(""), declare Scorm_API_12 function like this:
function Scorm_API_12() {
var Initialized = false;
this.LMSInitialize = function(param) {
errorCode = "0";
if (param == "") {
if (!Initialized) {
Initialized = true;
errorCode = "0";
return "true";
} else {
errorCode = "101";
}
} else {
errorCode = "201";
}
return "false";
}
// some more functions, omitted.
}
var API = new Scorm_API_12();
I also hit this error. In my case the root cause was async related (during a codebase refactor): An asynchronous function that builds the object to which the "not a function" function belongs was not awaited, and the subsequent attempt to invoke the function throws the error, example below:
const car = carFactory.getCar();
car.drive() //throws TypeError: drive is not a function
The fix was:
const car = await carFactory.getCar();
car.drive()
Posting this incase it helps anyone else facing this error.
In addition to the popular answers above, if you are using a services or helper functions file and doing an export on the functions that you will later import in your project.
Make sure that the function name you are importing matches the exact name of the function being exported from the services, helper, or utils file - and that the function actually exists in the right file! I got stuck on this error and was debugging for a few hours, getting nowhere until I found this out.
Had the same issue on Next.js. On _app.tsx I forgot to wrap the Component with the AuthProvider where I had all the Authentication functions.
In my case after a ton of stackoverflowing I saw what a function thing would go with here... it was merely a silly typo , I forgot to put $ in start of the next line's instruction:
function o_chir(id,nom) {
_id_ochirish = id
_nom= nom
//here it threw that "Uncaught TypeError: nom is not a function"
('#nom').val(s_)
$('#o_chir').modal('show')
}
and PHPStorm didnt give any warning
I received this error when I copied a class object incorrectly using JSON.parse and JSON.stringify() which removed the function like:
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Method
calcArea() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);
console.log('area of square: ', square.calcArea());
const squareCopy = JSON.parse(JSON.stringify(square));
// Will throw an exception since calcArea() is no longer function
console.log('area of square copy: ', squareCopy.calcArea());

Categories