setTimout screws up variable javascript - javascript

I'm having trouble with a piece of script that removes an object X amount of time after it has gotten the class 'hidden'
selector = getselector($(this).parent().parent());
console.log("Clicked Cancel");
$(this).parent().parent().addClass('hidden');
setTimeout(function() {
$(selector).remove();
}, 400);
I edited some piece of script from here to make function getselector since $(this) doesn't work within a setTimeout.
now this piece of code works, as long as you don't run it too quickly again.
problem seems to be that variable selector gets messed up when a another node gets deleted within the timespan (currently 400ms)
and I can't think of an easy way around it. :(

The answer is simple: Don't make selector global, i.e. use var. Oh, and simply store the element instead of trying to build a selector:
var elem = $(this).parent().parent();
elem.addClass('hidden');
setTimeout(function() {
elem.remove();
}, 400);

You can also queue the removal in the following way, which makes your Code a little bit more spicy:
$(this).parent().parent().addClass('hidden').delay(400).queue(function() {
$(this).remove();
});

Set a variable with a value true at the start of the process. On action, check whether it is not false and then set it to false and then back to true once finished. If you click it too fast, it will check your variable, see it is true again and will do the action again.

Related

Does $.addClass not update the DOM immediately?

Consider the following snippet.
function foo(event) {
var $item = $(event.target);
$item.addClass("className");
bar(event);
};
function bar(event) {
var $item = $(event.target);
// The following return false
if ($item.hasClass("className")) {
// flow of control does not enter
}
};
I am not asking how to get around this. That would be plain obvious: to pass the reference to the $item to the bar function.
I am asking if jQuery:
Does or does not update the DOM immediately?
When does it update?
How can I make it update explicitly?
Finally, where can I read about this?
Does or does not update the DOM immediately?
Yes. Immediately.
When does it update?
The property/attribute of the DOM is updated immediately, you can read the changed value immediately. But the UI rendering may delay to the end of the JavaScript code (UI rendering doesn't matter).
How can I make it update explicitly?
You don't need to.
Finally, where can I read about this?
Well ... I think the DOM/ES standards may contain these contents.
And you can think about the "correct behavior" of a design: who can bear the strange behavior that can not read the changed value immediately? It must be crazy. So your browser always do the right things. :D
See your demo here, works without any problem (if it doesn't work, it is your browser's problem, maybe buggy version, or caused by some buggy plugins)
function foo(event) {
var $item = $(event.target);
$item.addClass("className");
bar(event);
};
function bar(event) {
var $item = $(event.target);
if ($item.hasClass("className")) {
$("#output").text("className changed!")
}
};
$(function(){
$("#test").on("click", foo);
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="test">click me</button>
<div id="output">hello</div>
your code should perform as expected, there's no apparent problem with it, but here's the thing that might be creating problems
when you do addClass, it triggers an even that updates the class='' attribute and removes your className, which is why the condition
($item.hasClass("className"))
returns false

Need help understanding javascript code/jquery

So apparently the following can be used to automate linkedin steps of unfollowing a contact. I tried to run this code in the Chrome Console, and I'm not sure if it works. So I need help from someone who knows Javascript and JQuery to understand what this does, and then I can modify it to make it work.
var buttons = $("button"),
interval = setInterval(function(){
var btn = $('.is-following');
console.log("Clicking:", btn);
btn.click();
if (buttons.length === 0) {
clearInterval(interval);
}
}, 1000);
PS: The linkedin page that lets to unfollow your contacts is below. Login, and then navigate to the below.
https://www.linkedin.com/mynetwork/invite-connect/connections/
First, it selects all the buttons and stores them on the variable buttons ($("TAG") will select elements with the tag TAG). Then, it creates an interval that will be stored in the variable interval (bad practice, btw, because it isn't using "var" to declare the variable, so, it's a global variable, that should be avoided... but it's necessary to declare it as global in order to use clearInterval) that will execute the function inside the setInterval function call every second (1000 ms). That function will get all the elements that have the class "is-following" and will store them on the variable btn. Then, it will log the... buttons? After that, it will execute the click event on all of those buttons. Finally it will check if the amount of buttons are 0. If true, it'll stop the interval.

Why does waitForKeyElements() only trigger once despite later changes?

For several years I've used the waitForKeyElements() function to track changes in webpages from a userscript. However, sometimes I've found it doesn't trigger as expected and have worked around out. I've run into another example of this problem, and so am now trying to figure out what the problem is. The following is the barest example I can create.
Given a simple HTML page that looks like this:
<span class="e1">blah</span>
And some Javascript:
// function defined here https://gist.github.com/BrockA/2625891
waitForKeyElements('.e1', handle_e1, false);
function handle_e1(node) {
console.log(node.text());
alert(node.text());
}
setInterval(function() {
$('.e1').text("updated: "+Math.random());
}, 5000);
I would expect this code to trigger an alert() and a console.log() every 5 seconds. However, it only triggers once. Any ideas?
Here's a codepen that demonstrates this.
By design and default, waitForKeyElements processes a node just once. To tell it to keep checking, return true from the callback function.
You'll also want to compare the string (or whatever) to see if it has changed.
So, in this case, handle_e1() would be something like:
function handle_e1 (jNode) {
var newTxt = jNode.text ();
if (typeof this.lastTxt === "undefined" || this.lastTxt !== newTxt) {
console.log (newTxt);
this.lastTxt = newTxt;
}
return true; // Allow repeat firings for this node.
}
With the constant string comparisons though, performance might be an issue if you have a lot of this on one page. In that scenario, switching to a MutationObserver approach might be best.

Automation script is not working?

This is the first time I get my hands on with automation instruments in xcode The script works well for all button taps but the one making server connection. I don't know the reason
Here is the script I tried so far
var target = UIATarget.localTarget();
target.pushTimeout(4);
target.popTimeout();
var window=target.frontMostApp().mainWindow()
var appScroll=window.scrollViews()[0];
appScroll.logElementTree();
UIATarget.localTarget().delay(2);
appScroll.buttons()[1].tap();
The above script works up to showing the UIActivityIndicator instead of moving to next controller after success
I know There must be a very simple point I am missing. So help me out
UIAutomation attempts to make things "easy" for the developer, but in doing so it can make things very confusing. It sounds like you're getting a reference to window, waiting for a button to appear, then executing .tap() on that button.
I see that you've already considered messing with target.pushTimeout(), which is related to your issue. The timeout system lets you do something that would be impossible in any sane system: get a reference to an element before it exists. I suspect that behind-the-scenes, UIAutomation repeatedly attempts to get the reference you want -- as long as the timeout will allow.
So, in the example you've posted, it's possible for this "feature" to actually hurt you.
var window=target.frontMostApp().mainWindow()
var appScroll=window.scrollViews()[0];
UIATarget.localTarget().delay(2);
appScroll.buttons()[1].tap();
What if the view changes during the 2-second delay? Your reference to target.frontMostApp().mainWindow.scrollViews()[0] may be invalid, or it may not point to the object you think you're pointing at.
We got around this in our Illuminator framework by forgetting about the timeout system altogether, and just manually re-evaluating a given reference until it actually returns something. We called it waitForChildExistence, but the functionality is basically as follows:
var myTimeout = 3; // how long we want to wait
// this function selects an element
// relative to a parent element (target) that we will pass in
var selectorFn = function (myTarget) {
var ret = myTarget.frontMostApp().mainWindow.scrollViews()[0];
// assert that ret exists, is visible, etc
return ret;
}
// re-evaluate our selector until we get something
var element = null;
var later = get_current_time() + myTimeout;
while (element === null && get_current_time() < later) {
try {
element = selectorFn(target);
} catch (e) {
// must not have worked
}
}
// check whether element is still null
// do something with element
For cases where there is a temporary progress dialog, this code will simply wait for it to disappear before successfully returning the element you want.

Run a method everytime value changes

I wonder if any of you guys can help me with what I think is observing problem.
I have an element (svg to be more specific) that I want to update every time a value somewhere is changed.
I have variable:
GetThreadTree().treeBoxObject.getFirstVisibleRow() that initially is 0. I want to run a function updateCanvas() every time value of GetThreadTree().treeBoxObject.getFirstVisibleRow() changes.
What I have is:
canvas.observe(GetThreadTree().treeBoxObject.getFirstVisibleRow(), "scroll", updateCanvas());
But it calls updateCanvas() only once, when it's called for the first time, and for some reason does not execute the code that is after it. I checked error console and nothing is there.
Any ideas?
You logic is all in the wrong place. When you update your value what ever it is that needs to be done in one place by a function, something like treeBoxObject.IncrementRow() or similar.
Then you can have that function fire an event, like onTreeBoxRowIncremented. That event is what you listen out for, when that changes then you can do your check and update whatever you like.
Excuse the weird function names just trying to use what you have.
One way of solving this problem is:
var registeredRow = 0;
function checkRow(){
var row = GetThreadTree().treeBoxObject.getFirstVisibleRow();
if (registeredRow != row) {
registeredRow = row;
updateCanvas();
}
window.setTimeout(checkRow, 1);
}
And before checkRow is called:
registeredRow = GetThreadTree().treeBoxObject.getFirstVisibleRow();
checkRow();
But it's not the most elegant solution but it works ;)

Categories