I have a piece of code shown below that is supposed to select the first object in a list of image object. When it runs, about half of the time I am getting an error:
TypeError: Cannot read property of mylist
I realize that this is happening because it is trying to reference an object that has not yet been given a reference to an object. Basically, the page will load, and I want to call this function in JavaScript, however if this code runs before the list is referenced, it errors out. Here is my code snippet:
window.onload = function () {
try {
var tnl = $find('mylist');
tnl.selectFirstItem();
}
catch (exception) {
alert(exception);
}
}
The
tnl.selectFirstItem()
line is the one throwing the error to the catch block.
So, my question is, is there a way to force it to wait until this object "tnl" has been referenced?
Thanks!
var tnl = $find('mylist');
should be
var tnl = $('#mylist');
assuming mylist is an ID.
You're using find wrong.
First you get your element, then you use it to find a child element.
So you could do this:
var container = $('.containerElement');
container.find('#mylist');
Here is the "loop" you are asking for. But this is still wrong. If tnl is not assigned after $find('mylist'); returns, it is not going to become assigned later. You likely have error thrown by $find call.
window.onload = function () {
try {
var tnl = $find('mylist');
var timer = setInterval(function() {
if (tnl) {
clearInterval(timer);
tnl.selectFirstItem();
}
}, 1000);
} catch (exception) {
alert(exception);
}
}
Related
I am experimenting a strange issue: at the beginning of my code, I defined a function like so:
function rootEmbed()
{
var embed = new Discord.RichEmbed()
.setColor(config.embedColor);
return embed;
//returns an object
}
Later in the same file, I define another function which calls the one above, like so:
function commandList()
{
var embed = rootEmbed();
//....
}
Calling that function causes no problem, however calling the following function returns an error that says
(node:4988) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): TypeError: rootEmbed is not a function
Here is the told function:
function voidTrader(trader)
{
var rootEmbed = rootEmbed();
//...
}
I can't figure out why does the voidTrader() method causes an error while commandList() turns out perfectly fine. What am I doing wrong?
If you want the full code, you can find it here.
Thanks in advance!
This is a combination of variable hoisting and variable shadowing. When you initialize a variable var x = 5, what happens is that var x is hoisted to the top of the code file. However, function declarations are hoisted even higher. Meaning that when your file is run, this is what is happening:
function rootEmbed (){//...code here}
var rootEmbed = undefined;
To fix this problem, change this:
function voidTrader(trader)
{
var rootEmbed = rootEmbed();
//...
}
To something like this:
function voidTrader(trader)
{
var rootEmbedResult = rootEmbed();
//...
}
There is another problem at lines 25-26:
var year = "" + stamp.getYear();
var year = twoDigits("20" + year.substr(-2));
year is declared with var twice.
I have written a function TakeScreenshot in a JS file say base.js file which save screenshot and return me the screenshot path The implementation as below.
this.TakeScreenshot = function(screenShotName) {
//some stuff.....
browser.takeScreenshot().then(function (png) {
var stream = fs.createWriteStream(screenshotPath);
stream.write(new Buffer(png, 'base64'));
stream.end();
});
return screenshotPath;
};
I am calling the above function in another function called "isTruelyPresent". This function will take a screenshot if element is present/not present on UI. The implementation is as below:
this.isTrulyPresent = function(elementToCheckVisibilityOf, element2) {
return elementToCheckVisibilityOf.isDisplayed().then(function (isDisplayedd) {
var myObj;
myObj = this.TakeScreenshot(element2);
// some stuff
console.log('isDisplayed'+isDisplayedd);
return isDisplayedd;
}).then(null, function (error) {
var myObj;
myObj = this.TakeScreenshot("ErrorSS");
console.log('A NoSuchElement exception was throw because the element is NOT displayed so we return false');
return false;
});
};
Protractor script is throwing an error "this.TakeScreenshot is not a function". Could any one please help me to resolve the issue.
First of all be aware that there is a difference between isPresent (checks if an element is present in the DOM) and isDisplayed (checks if an element is present in the DOM AND visible). If an element is not present in the DOM, the method isDisplayed() will fail hard. You are now catching this error, is this also what you want?
Secondly each function can have it's own this scope. That means that your this.TakeScreenshot("ErrorSS") can have a reference to the this-scope of the function(error){} instead of the this you want to refer to.
This ;-) doc may help in fixing this. What I normally use are the arrow-functions, see the link.
I'm getting an error which I'm not quite sure what to make of. Anyway, before I go on to that, I found out about Unobtrusive JavaScript, at first I was just going to add an "OnClick" to my HTML but then found out that isn't a very good thing to do.
Anyway, so I did that and turned up with this code which isn't quite finished yet, but I wanted to try it out anyway before I went in and made any other changes.
window.onload = function findSubmitButton(){
var button = document.getElementsByClass("send_info").addEventListener("click", retrieveInputText());
}
function retrieveInputText(){
var inputArray = document.querySelectorAll("#container_id input[type=text]");
var finalArray;
for (var i in inputArray){
if(inputArray[i].type == "text"){
finalArray.push(i);
}
alert("done");
}
}
The error chrome's console gives me is this: Uncaught TypeError: undefined is not a functionfindInputs.js:5 findSubmitButton
There was also something I wanted to know, I want to be able to use this script with any other sort of input form, so instead of directly identifying the button for this page, I used a class identifier, this way, it works with any page. The only way there would be any issues would be if I had two buttons of the sort, as it is right now, any page with that sort of information only has one button for such procedures. I would appreciate if someone helped me out with this, I'm new to JavaScript.
getElementsByClassName(), returns an array, not an element so it does not have the addEventListener method, also you need to pass a function reference
window.onload = function findSubmitButton() {
var button = document.getElementsByClassName("send_info")[0].addEventListener("click", retrieveInputText);
}
Also you need to initialize the array var finalArray = [];
window.onload = function findSubmitButton() {
var button = document.querySelector(".send_info").addEventListener("click", retrieveInputText);
}
function retrieveInputText() {
var inputArray = document.querySelectorAll("#container_id input[type=text]");
var finalArray = [];
for (var i in inputArray) {
if (inputArray[i].type == "text") {
finalArray.push(i);
}
}
alert("done:" + finalArray);
}
Demo: Fiddle
I make a simple quiz game. Here is some relevan methods that i have inside one object.
But doesn't work. I always get an error within 'rightAnswerGot' function. Console drops
"uncaught typeerror undefined is not a function for object methods" for this.addVariantsHtml(this.updateCharacter());
BasicGame.Game.prototype = {
actionOnClick: function (button) {
var log;
if(button.value==this.char_bubble.text) {
setTimeout(this.rightAnswerGot,1000);
} else {
// wrong
swoshsound.play();
}
console.log(log);
},
rightAnswerGot: function (){
this.addVariantsHtml(this.updateCharacter());
},
addVariantsHtml: function(id) {
this.answer = this.getAnswersVariants(id);
for (var i = 0; i < 6; i++) {
this.button[i].value = this.answer[i]['trans'];
this.button[i].char_id = this.answer[i]['id'];
this.ans_text[i].setText(this.answer[i]['trans']);
}
},
updateCharacter: function() {
var i = this.getRandomCharacter();
console.log("updateCharacter: "+i + " " +this.chars[i]);
this.char_bubble.setText(this.chars[i].getPath());
return i;
}
}
The aim is to froze the game for a second, when user choose the right answer, and than go to next question. Any ideas why does it happens?
Thanks
Looks like a classic JavaScript scope issue to me. However as you've tagged this question as using Phaser, I would suggest you use a Phaser Timer event to avoid scope problems. Specifically:
setTimeout(this.rightAnswerGot,1000);
replace it with:
this.game.time.events.add(Phaser.Timer.SECOND, this.rightAnswerGot, this);
Which will create a single 1 second timer that fires only once, calling your function at the end of it. You can use 1000 instead of Phaser.Timer.SECOND of course.
I would image that whats happening is that its trying to call the this.addVariantsHtml method, before its calling this.updateCharacter and getting the ID.
So your probably expecting that when it runs, for it to be something like:
this.addVariantsHtml(1);
But its actually trying to run
this.addVariantsHtml(this.updateCharacter());
So just do this:
var id = this.updateCharacter();
this.addVariantsHtml(id);
Either that or you need to look into method chaining/piping, which is just complicated and doesnt need to be used for this situation, but is interesting :)
Ok I found something that made it work!!
Here is a solution:
actionOnClick: function (button) {
var log;
if(button.value==this.char_bubble.text) {
var context=this;
setTimeout(function() {
context.addVariantsHtml(context.updateCharacter());
},1000);
} else {
// wrong
swoshsound.play();
}
console.log(log);
},
I'm discovering the concept of "objects" in JavaScript. I'm making an RSS Parser, and I have an error (commented).
function MyParser (feed_url) { // Construct
"use strict";
this.feedUrl = feed_url;
this.pubArray = [];
if (typeof (this.init_ok) == 'undefined') {
MyParser.prototype.parse = function () {
"use strict";
var thisObj = this;
$.get(this.feedUrl, function (data, textStatus, jqXHR) {
if (textStatus == 'success') {
var xml = jqXHR.responseXML,
//lastBuildDate = new Date($(xml).find('lastBuildDate').text());
items = $(xml).find('item');
items.each(function () {
var pubSingle = thisObj.makeObj($(this).find('pubDate').text(),
$(this).find('link').text(),
$(this).find('title').text(),
$(this).find('description').text(),
$(this).find('encoded').text(),
$(this).find('commentRss').text(),
$(this).find('comments').last().text());
thisObj.pubArray.push(pubSingle);
});
console.log(thisObj.pubArray); // OK
}
}, 'xml');
console.log(this.pubArray); // Empty
return (this.pubArray);
};
MyParser.prototype.makeObj = function (pubDate, pubLink, pubTitle, pubDesc, pubContent, pubComCount, pubComLink) {
"use strict";
var pubSingle = {};
pubSingle.pubDate = new Date(pubDate);
pubSingle.pubLink = pubLink;
pubSingle.pubTitle = pubTitle;
pubSingle.pubDesc = pubDesc;
pubSingle.pubContent = pubContent;
pubSingle.pubComCount = pubComCount;
pubSingle.pubComLink = pubComLink;
return (pubSingle);
};
}
this.init_ok = true;
}
If you look at the console.log(), you'll see that the line // OK is outputting my array correctly.
But later, when returning from $.get, my array is empty.
Does anybody have an idea why, and how to correct that please?
This is not a problem with variable-scope. The problem here is that you're working with asynchronous flow and you're not thinking correctly the flow.
Let me explain:
When you do your .get, you fire a parallel asynchronous process that will request information from the browser, but your main program's flow keeps going, so when you get to your "return" statement, your array has not been filled yet with the response from your get method.
You should use your array from inside the get callback and not outside of it, since you can't guarantee that the array will have the information you need.
Does it make any sense?
Let me know!
Further explanation
According to your comments, you're still doing something like this:
var results = MyParser(feed_url);
//code that uses results.pubArray
And you cannot do that. Even though you're setting your "pubArray" inside your .get callback, you're trying to use pubArray right after you called MyParser and that's before the .get callback is called.
What you have to do, is call your next step on your program's logic from within the .get callback... that's the only way you can be sure that the pubArray is filled with proper data.
I hope that makes it clearer.
This is because your line
console.log(this.pubArray); // Empty
is being called directly after you issue your Ajax request; it hasn't had time to fetch the data yet. The line
console.log(thisObj.pubArray); // OK
is being called inside the Ajax callback, by which time the data has been fetched.
Thank you all, and particulary #Deleteman .
Here is what I did:
$.get(this.feedUrl, 'xml').success(function () {
thisObj.handleAjax(arguments[0], arguments[1], arguments[2]);
$(document).trigger('MyParserDone');
}).error(function () {
$(document).trigger('MyParserFailed');
});
Then, when i enter "HandleAjax", i'm back in my object context, so "this" refers to my object and the right properties. The only "problem" is that I have to set a listener (MyParserDone) to make sure the parsing is finished.