If statement stopping a for loop - javascript

I'm making a table that calls the following method when the value is changed, but the update method dies part through if the variable stuntSet is set to "all"
When I call updateStunts, if stuntSet is set to "all" it never gets out of the for loop. When it's set to anything else it seems to work fine and moves on to call countStuntRefresh(). The strange part is that it completes all the code inside the if statement that checks if stuntSet ==="all" but it never reaches the call for countStuntRefresh();
I've been going through this for an hour and I can't find my mistake. I apologize if it's a simple mistake and I appreciate whatever help you can give.
http://jsbin.com/nicoruvamula/1/
is the link to the full code
var selected = false;
var updateStunts = function() {
for (var i = 0; i < character.stunts.length; i++) {
if (stuntSet === "all") {
selected = document.getElementById("select" + character.stunts[i].name).checked;
character.stunts[i].chosen = selected;
} else if( stuntSet === character.stunts[i].category) {
selected = document.getElementById("select" + character.stunts[i].name).checked;
character.stunts[i].chosen = selected;
}
}
countStuntRefresh();
};
var countStuntRefresh = function() {
character.spentRefresh = 0;
for(var i = 0; i <character.stunts.length; i++){
if (character.stunts[i].chosen) {
character.spentRefresh += character.stunts[i].cost;
}
document.getElementById("stunttest").innerHTML = "Spent Refresh:" + character.spentRefresh;
}
};

When I run the jsbin code, there are several exceptions because document.getElementById("select" + character.stunts[i].name) returns null.
Looking through the code, I noticed that you don't wait for the DOM-ready event. As you already including jQuery, have you tried wrapping your code in a
$(function() { /* your code*/ });
(or will jsbin automagically call your code in onload or DOMReady? not familiar with jsbin...)

Related

angularjs - ng-repeat being called before scope variable is defined

I have a md-tabs setup, I have it binded to $scope.selectedIndex so that I can change it by code when I need to.
I use a button, call my function that updates data, I then change $scope.selectedIndex to the tab number needed (In this case 3) that will then change the selected tab.
All of that is fine, except it's calling $scope.selectedIndex before .forEach() call is finished, which results in a ng-repeat not working as it exits silently with no errors since its not defined.
Button Calls:
ng-click="initTVShow(show)"
Function:
$scope.initTVShow = function(show) {
var rng = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for( var i=0; i < 10; i++ )
rng += possible.charAt(Math.floor(Math.random() * possible.length));
$scope.show = show;
$scope.show_name = show.title.split(' ').join('') + "-" + rng;
$scope.poster = show.images.poster;
$scope.backdrop = show.images.poster;
$scope.seasons = [{},{}];
getShow(show.imdb_id, function (err, show) {
for (let i = 0; i < 10; i++) {
$scope.seasons[i] = show.episodes.filter((episode) => episode.season === i);
}
});
$scope.selectedIndex=3;
};
As you can see, $scope.selectedIndex=3; basically changes to Tab #4 (0-based).
Then the following ng-repeat does not seem to work and most likely because .forEach hasn't finished yet. I tested with $scope.seasons with 2 empty index's to test and that works.
<span ng-repeat="season in seasons">{{season.number}}</span>
I think that this is because the function getShow retrieves data asynchronously. Show it to us.
Try this:
getShow(show.imdb_id, function (err, show) {
show.episodes.forEach(function(array){
$scope.seasons[array.season] = array;
});
$scope.selectedIndex=3;
});
It's because the data not ready and the DOM is.
you can solve it easily by adding ng-if on the element and check if the data ready.
Like:<span ng-if="season.number" ng-repeat="season in seasons">{{season.number}}</span>
I found the solution, it was actually just caused by the for() loop (Which pre-edit, was a .forEach), I simple added a callback to it, which changed the tab and it just WORKED!
Changed:
for (let i = 0; i < 11; i++) { }
To:
for (let i = 0; i < 11 || function(){ $scope.selectedIndex=3; }(); i++) { }

Javascript constructor copies array as empty when it should contain items

My code:
function BayesNet(vars) {
this.variables = {};
this.numVars = Object.keys(this.variables).length;
for (v in vars) {
this.variables[v] = new BayesNode(vars[v]);
this.variables[v].CPTorder = this.generateDomainRows(this.variables[v].parents);
this.variables[v].fullCPT = {}
for (var i = 0; i < this.variables[v].CPTorder.length; i++) {
this.variables[v].fullCPT[this.variables[v].CPTorder[i]] = this.variables[v].CPT[i];
}
this.variables[v].blocks = false;
}
}
function BayesNode(obj) {
this.parents = obj.parents;
this.children = obj.children;
if (typeof obj.domain == 'undefined')
this.domain = ['T','F'];
else
this.domain = obj.domain;
this.observation = obj.observation;
this.CPT = obj.CPT;
this.sampleDistribution = [];
for (var i = 0; i < this.CPT.length; i++) {
var s = [];
if(this.CPT[i].length == this.domain.length - 1)
this.CPT[i].push(1 - sumArray(this.CPT[i]));
s.push(this.CPT[i][0]);
for (var j = 1; j < this.domain.length - 1; j++) {
s.push(this.CPT[i][j]+s[j-1]);
}
s.push(1.0);
this.sampleDistribution.push(s);
}
//TODO: Check if CPT is valid
}
My problem is that BayesNode.parent is copied incorrectly.
BayesNode.parent should be an array containing items, and when I run the debugger through the constructor, this.parents is the correct value . However, once I go back to the BayesNet constructor, parents is an empty array. What could be causing this? All other variables in the object behave as expected.
Javascript executes function calls asynchronously. This is the root cause of your issue. You should use callbacks to execute code that is dependent on results of function calls.
Let me explain this using your code:
this.variables[v] = new BayesNode(vars[v]);
this.variables[v].CPTorder = this.generateDomainRows(this.variables[v].parents);
When you call the constructor, JS does NOT wait for the function to finish executing before moving onto the next line of code. When JS comes across "this.variables[v].parents", it is empty, because, the function call in the previous line is still executing asynchronously.
Javascript code design requires a different approach as compared to most other languages.
I don't see any issues in your code, its strange why its becoming empty. but to solve the problem there is a way. change the code as follow.
after this line
this.variables[v] = new BayesNode(vars[v]);
Add the follow
this.variables[v].parents = vars[v].parents;
I see you are not modifying the parents in the constructor, it will work for time being before you find out whats happening. you might have done this already :)

How do I loop a check for string in a document in Javascript?

I'm trying to make a code that will search for a specific text, and if it is found it will click a button. It needs to check for the string continuously, however I am struggling to find a way for that to happen. I'm a complete newb to coding, so any help is appreciated! :)
var findMe = [
//Test
'Hello!',
];
function findText() {
var text = document.querySelector('div[id=BtnText]');
for (var i = 0; i < findMe.length; i++) {
if (BtnText.match(findMe[i])) {
var btnDo = document.querySelector('input[type="submit"][value="Click!"]');
if (btnDo) {
btnDo.click();
}
}
}
}
Just editing your code a little bit.
I am assuming you have HTML like this?
<div id="BtnText">Hello!</div><input type="submit" value="Click!">
You will to change your code to this
var findMe = [
//Test
'Hello!',
];
function findText() {
var div = document.querySelector('div[id=BtnText]');
for (var i = 0; i < findMe.length; i++) {
if (div.innerText.indexOf(findMe[i]) !== -1) {
var btnDo = document.querySelector('input[type="submit"][value="Click!"]');
if (btnDo) {
if (typeof btnDo.onclick == "function") {
btnDo.onclick.apply(elem);
}
}
return true;
}
}
return false;
}
If you want to check continuously. I recommend using setInterval.
var interval = setInterval(function() {
var textFound = findText();
if(textFound) {
clearInterval(interval);
}
},50);
Regular expression:
(new RegExp('word')).test(str)
(new RegExp(/word/)).test(str)
indexOf:
str.indexOf('word') !== -1
search()
searches a string for a specified value, or regular expression, and returns the position of the match.
var n=str.search("word");
or
var n-str.search(/word/);
if(n>0)
{}
with window.find()
if (window.find("word", true)){}
//code
while(window.find("word",true){
//code
}
Why do you need to perform the check continously?
You should get another approach... Or your script will be blocked by Chrome, for example, if it makes the page non responsible. You can go for a timeout, as Taylor Hakes suggested... Or just call your findText function attached to the onChange event on the div.

Speed test: while() cycle vs. jQuery's each() function

I have an array of objects called targets and I want to execute a function on each of those objects. The first method:
targets.each(function() {
if (needScrollbars($(this))) {
wrap($(this), id);
id = id + 1;
}
});
This method gives execution speed of ~125ms. The second method is:
var i=0;
while (targets[i] != undefined) {
if (needScrollbars($(this))) {
wrap($(this), id);
id = id + 1;
}
i = i+1;
}
This second method takes whopping 1385ms to execute and I get my head around that. Does anyone have any idea why a bare bones cycle runs slower than a function which I'm only guessing that's doing (just guessing) a whole lot more than a simple cycle?
Thank you.
They are totally different. The this in the first example is the current target, in the second example this is the "external" this. You should change the second example as:
var i=0;
while (targets[i] != undefined) {
var cur = $(targets[i]);
if (needScrollbars(cur)) {
wrap(cur, id);
id = id + 1;
}
i = i+1;
}
The relevant quote
More importantly, the callback is fired in the context of the current DOM element, so the keyword this refers to the element.
But I don't know why you haven't written as:
for (var i = 0; i < targets.length; i++)
{
var cur = $(targets[i]);
if (needScrollbars(cur)) {
wrap(cur, id);
id = id + 1;
}
}
And in the end the each "method" is easier to comprehend (for me).
Your second method is not functionally equivalent to the first one.
Why? Because it uses this, making it a closure on the global scope. Of course the second method is slower: it continuously shells out jQuery objects made out of global scope. Try that benchmark again with:
var i=0;
while (targets[i] !== undefined) {
var o = $(targets[i]);
if (needScrollbars(o)) {
wrap(o, id);
id++;
}
i++;
}

Handling onclick events

I have a list which contains links . I am using this code to access them:
function initAll() {
var allLinks = document.getElementById("nav").getElementsByTagName("a");
for (var i=0; i< allLinks.length; i++) {
allLinks[i].onmouseover = showPreview;
allLinks[i].onmouseout = function() {
document.getElementById("previewWin").style.visibility = "hidden";
allLinks[i].onclick=mainProcess;
}
}
}
function mainProcess(evt){
alert(this.value);
false;
}
This is not the exact code, what I am trying to do is that I need to identify link is clicked and perform some function on the basis of link clicked. I don't know where code needs to be modified... Page is giving error on the allLinks[i].onclick=mainProcess(this); line.
Now the problem is that I don't know how I should handle all the three events?
1) You're setting the onclick property of each of the links to be the value returned by mainProcess() - which always returns false. So, in effect, you're writing allLinks[i].onclick = false;
2) When you define an event handler directly, the argument that gets passed to it when the event fires, is the event object - not the element it was fired on.
To figure out the element, you can either look in the event object, or (since the handler has been added to the element itself) simply use this, as that will refer to the link element
for (var i = 0; i < allLinks.length; i++) {
allLinks[i].onclick = mainProcess;
}
function mainProcess(event) {
{
alert(this.value);
return false;
}
You do need to pass this to mainProcess(link). As stated in http://www.quirksmode.org/js/events_tradmod.html "No parentheses!" and "this" chapters. Check it out, there's an example there too. Should be everything you need.
Try changing to this:
for (var i = 0; i < allLinks.length; i++) {
allLinks[i].onclick = mainProcess;
}
function mainProcess(event) {
{
alert(this.value);
return false;
}

Categories