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 ;)
Related
I have the following buttons:
<button id="abcd" onclick="something()">click</button>
and the following functions are attached to this button apart from the one in its html definition.
$('#abcd').on('click',function(){alert("abcd");});
$('#abcd').on('click',function(){
someAjaxCallWithCallback;
});
Now I want a new function with another ajax call to execute on this button's click, before the above mentioned functions. This new function determines whether the remaining functions would be called or not based on what data is recieved by the ajax call. That is, this pre function should complete its execution before giving control over to the rest of the functions and also determine whether they would run or not.
As an example, without changing the existing validation logics and button code, I have to add a new pre-validation function and similarly and post validation function.
I have a bindFirst method using which I can at least bring my new function to the beginning of the call stack but I have not been able to contain its execution and control further delegation because of callbacks.
If I understand correctly, you are looking for the way to do this, without modifying html and already existing js, only by adding new js-code.
First of all, if onclick handler is set and you want to control it, you should disable it on page load (maybe, saving it to some variable):
$(document).ready(function() {
var onclick = $("#abcd").attr("onclick").split("(")[0];
//to run it in future: window[onclick]();
$("#abcd").attr("onclick", "");
});
Edit: I changed my answer a little, previous approach didn't work.
Now you need to remove all already existing handlers. If number of handlers you want to control is limited, constant and known to you, you can simply call them in if-else after pre-validation inside your pre-function. If you want something more flexible, you are able to get all the handlers before removing, save them and then call them in a loop.
For that "flexible" solution in the end of $(document).ready(); you save all already existing handlers to an array and disable them. Then you write your pre-function and leave it as the only handler.
var handlers = ($._data($("#abcd")[0], "events")["click"]).slice();
$("#abcd").off("click");
$("#abcd").click(function() {
//this is your pre-func
//some code
handlers[1].handler.call();
});
Try console.log($._data($("#abcd")[0], "events")) to see, what it is.
Finally just run your post-function and do whatever you need, using conditions.
So, the general algorithm is as follows:
Disable onclick
Save all handlers
Disable all handlers
Run pre-func first
Run handlers you want to be executed
Run post-func
In fact, you just make your pre-func the only handler, which can run all other handlers you may need.
Although Alex was spot on, I just wanted to add more details to cover certain cases that were left open.
class preClass{
constructor(name,id){
if($(id) && $(id)[0] && $(id)[0]['on'+name])
{
var existing = $(id)[0]['on'+name]
$(id).bindFirst(name,existing);
$(id).removeAttr('on'+name)
alert("here");
}
if($._data($(id)[0],"events")){
this.handlers = $._data($(id)[0],"events")[name].slice();
}
else
{
this.handlers = null;
}
this.id = id;
this.name = name;
}
generatePreMethod(fn,data)
{
$(this.id).off(this.name);
$(this.id).bindFirst(this.name,function(){
$.when(fn()).then(execAll(data));
});
}
}
function exec(item,index){
item.handler.call()
}
function execAll(handlers){
return function(){ handlers.forEach(exec);}
}
This more or less takes care of all the cases.
Please let me know if there is something I missed!
I need to update single item of object in localstorage without reloading page.
jsFiddle: https://jsfiddle.net/7xsg8679/
Here is my code:
if (obj.isCompletedTask === false) {
newDone.innerHTML = "Not done";
newDone.dataset.done = false;
newButton.addEventListener('click', function (e) {
newDone.innerHTML = "Done";
newDone.dataset.done = true;
newUl.style.backgroundColor = "red";
e.preventDefault();
})
}
If I use if(obj.isCompletedTask === true) in the if-statement - it does nothing. Why?
When you use obj.isCompletedTask === true the button does nothing isCompletedTask is false, so the code between curly brackets { ... } is not run at all, so the eventListener does not get attached to your button click event.
You may want to move your if statement to inside of event listener, if i understood your intentions correctly.
When you want to update an element in localstorage, you do it like that:
localStorage.setItem('list', JSON.stringify(tasks));
...but when your tasks object changes, you need to keep a track of that yourself, and manually update localStorage. This relation is called data-binding. Moreover, you cannot just update subelement of your tasks directly, you have to replace list in localStorage with fresh version of tasks every time something in tasks changes.`
General remark: from what i see in your fiddle, i do really think you should have a look at some framework (like vue, react or angular). Keeping track of the changes here and there will really be tiresome after a while and besides, why should yo reinvent the wheel?
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.
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.
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.