How to get a DOM elements click handler using capybara-webkit or native QtWebKit? - qt

I'm using capybara-webkit and would like to get the event handler(s) bound to the click event of an element in the DOM. An answer even using native QtWebKit calls would probably be enough for me to figure out how to do it using the webkit driver in Ruby. The challenge I am having is that the event handlers are being bound programmatically in JavaScript, not in HTML, and my searches so far on how to do this all seem to end with how to click or otherwise trigger events in a QWebView. I need to inspect the event handler (i.e. the actual function definition), in particular anonymous functions bound to the event, without generating the event itself. Any help is appreciated.

You can execute arbitrary Javascript and return the result using page.execute_script. If the event handlers in question are bound using jQuery, this will list them:
page.execute_script(<<-JAVASCRIPT)
var handlers = $('.some-selector').data("events").click;
jQuery.each(handlers, function(key, handler) {
console.log(handler);
});
JAVASCRIPT
There's a complete answer on introspecting on event handlers here: How to find event listeners on a DOM node when debugging or from the JavaScript code?

Related

Event to fire in DTM after async API

I am new to Adobe Analytics and DTM.
On my website, an asynchronous API is creating a div on the page dynamically. This DIV has a special CSS class, let's say "wantedClass".
I want to create 2 rules :
A rule that fires once the DIV appears on the page, which i did like using Page Load Rules as following :
On this trigger, an event1 is fired in Adobe Analytics.
I picked onLoad because I read that this is the last one among the other options, and I want to make sure that the API async finished creating the DIV so this event would be fired.
A rule that fires once the DIV is clicked, which I did using Event Based Rules as following :
On this trigger, an event2 is fired.
What's happening when I test is :
Page loads, no event1 is fired
DIV clicked, no event2 is fired, BUT event1 is fired.
What am I doing wrong?
Any help would be appreciated;
1. Page loads, no event1 is fired
Async calls by their nature can happen after DOM Ready or window load (onLoad), so onLoad is not guaranteed to trigger after some API (async) ajax call is made and returns something.
Ideally, you should trigger something in the API's ajax success callback function. You can create and trigger a Custom Event which DTM can listen for in an Event Based Rule. Note: If you go this route, make sure you create/trigger on document.body or a decendant; DTM will not listen for custom events on document itself. Also, since I see you using jQuery syntax in your screenshot, if you go this route, also note that jQuery custom event functionality is NOT the same as native javascript custom events. So for example if you do $( document.body ).trigger( "someEvent" ), this does NOT push to something listening to
document.body.addEventListener('someEvent', function (e) { /* ... */ }, false);
DTM uses the above to listen for custom events. So TL;DR - don't use jQuery syntax to create or broadcast custom events if you intend on using DTM's built-in custom event listener.
Alternatively, within the API's ajax callback function, you can just do _satellite.track('dc_rule_value_here'); and create a Direct Call rule with 'dc_rule_value_here' as the string condition.
If you cannot add something to the API ajax callback function, the next best thing is to create a Data Element of Custom Code type, with the code you have in your screenshot condition (returning true or false if .wantedClass is found). Then, create an Event Based Rule of Data Element Changed type, with a condition reflecting what you return from the data element. This isn't ideal because this rule type works by polling the data element every 1 second for the duration of the page view. This isn't that big a deal in the grand scheme of things but it is not as efficient as other methods (and if you 0make it a practice to do this for a lot of rules, then it might become a problem). Note that you should also bake into your Data Element to only return true once, so that it doesn't keep triggering the EBR every 1s after its found (DTM does not have a native "fire only once" type config).
2. DIV clicked, no event2 is fired, BUT event1 is fired.
Not sure about this one. At face value, it sounds like the DTM rule itself is working, but there is a problem with the AA s.events being set. Could be that you simply typo'd and put event1 into the rule, though I'm sure you checked that.. right?
Could be you have other code (e.g. code within s.doPlugins callback) that is overwriting it. Or maybe it's some other rule entirely that is triggering, not the one above.
May be able to help further if you provide more details on how/where you actually set the event (including other places you may be setting both events), but it but kinda sounds like something I'd have to see this in action on a page to really get to the bottom of it :/

Register JavaScript alert at extreme end using RegisterStartupScript

(Note: Just to clarify the problem is not specifically related to C1WebDateEdit. It could be with any custom control which require JavaScript to render actual control)
I have many C1WebDateEdit controls in my page. On a button click based on some condition I am displaying JavaScript alert message ScriptManager.RegisterStartupScript. These controls are inside UpdatePanel. The issue I am facing with it is, when these C1WebDateEdit has not value and page displays alert message, it displays "01/01/0001" behind the alert box and on closing alert it shows empty textboxes.
The reason is, C1WebDateEdit creates actual control using JavaScript. and page renders alert message JavaScript before C1WebDateEdit controls' JavaScript.
For example:
HTML markup
alert JavaScript
C1WebDateEdit JavaScript
Logical solution is get alert JavaScript after C1WebDateEdit JavaScript because it will allow C1WebDateEdit to load fully before alert box.
I found no inbuilt way in asp.net to change sequence, so I tries solution given here but It didn't work for me.
One possible solution I am thinking that I create Custom or WebUserControl and place at it last at the page in the UpdatePanel and PreRender event I call ScriptManager.RegisterStartupScript to register alert message. Logically I think it will work but trying to find that any one implemented any other solution for it?.
Other possible solution is use "pageLoaded" event of PageRequestManager. I created below function for temporary fix:
function delayedAlertBox(strMsg)
{
var fnc = function (a, b)
{
//remove reference so on next call it do not show previous alerts.
Sys.WebForms.PageRequestManager.getInstance().remove_pageLoaded(fnc);
alert(strMsg);
}
//add function reference to call on Ajax pageloaded event
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(fnc);
}
and calling in asp.net like simple function as given below:
ScriptManager.RegisterStartupScript(Page, Page.GetType(), "dd", "delayedAlertBox('Hi, how are you?')", True)
But still looking for any other good alternative. If I found other, I will post it.

Angular2 - stopping 'setInterval' http requests on route change

I'm writing a realtime updating graph using Angular2. My graph is being updated through data coming via an http observable, and a setInterval command.
A weird thing I've noticed is that, when I route through angular to a different view on my app, the setInterval command on the previous component does not stop, causing the server for unnecessary load.
What would be the correct method to stop setInterval http requests on route changes in Angular2?
Any help would appreciated.
Events are managed very differently by browsers, basically they are processed by Event loop.
The browser has inner loop, called Event Loop, which checks the queue
and processes events, executes functions etc.
So whenever you add any asynchronous event like setTimeout/setInterval, they gets added to Event Loop with their handlers.
Basically whenever you wanted to stop/de-register those asynchronous event, you need to de-register them manually. Like here you need to call clearInterval method with that setInterval object reference, then only it will remove that async event from Event Loop.
You could use ngOnDestroy life-cycle hook where you can have your stuff before destroying your component.
//hook gets called before Component get destroyed or you can say disposed.
ngOnDestroy(){
clearInterval(intervalReference)
}
Extra stuff(Comparing with Angular 1)
The same kind of problem you can see in any Javascript Framework. In Angular 1 there is way to handle such kind of situation(I'm adding this stuff so that anyone from Angular 1 background can easily get this concept by comparing A1 with A2). While destroying controller instance angular internally emit's $destroy event over element & $scope of that element. So by having listener over $destroy event, we used to do stuff to ensure those object value/object/events should not available.
$scope.$on('$destroy', function(event){
//do stuff here
})
element.bind('$destroy', function(event){
//do stuff here
})

Using Javascript to detect when a user has selected an item in an ASP.NET listbox

I am developing an ASP.NET web application that incorporates google maps. I have an ASP.NET listbox on my page which contains a list of items. When the user selects one of the items, I'd like to show this item on the map. The main complication lies in the fact that google maps uses javascript to control it and the listbox is a server control.
I can think of two ways to do this. The first would involve the listbox calling a javascript function when the user selects a new item. I can then write this function to perform the necessary map operations. Unfortunately, the OnSelectedIndexChanged property of the listbox doesn't seem to support javascript functions.
The second involves wrapping an UpdatePanel around the listbox and getting the listbox to perform a postback. In the SelectedIndexChanged event in VB/C#, I would the need to somehow make a call to a javascript function which would then update the map.
Which solution can I use?
Thanks
--Amr
In your codebehind (in your pageload) just add a javascript handler to the OnChange attribute that points to your javascript function. Eg:
lbYourListBox.Attributes.Add("onChange", "UpdateYourMap();");
You could also add this to your control using inline javascript as well but I prefer to do it in the codebehind so that the framework can handle matching up the names.
You could simply embed javascript into your page, avoidig relying on ASP with it. Put the code into your document body:
<script language="javascript">
body.onload=function(){
var lb=document.getElementById("yourlistboxid");
lb.onChange = function(){
// put your handling code here
}
}
</script>
to demo the other approach, here's a rough guide:
void listbox_SelectedIndexChanged( ... ) {
string js = string.Format("callToMapsFunction({0});", listbox.SelectedValue);
string scriptKey = "mapscript";
ScriptManager.RegisterStartupScript( listbox, typeof(ListBox), scriptKey
, js, true);
}
RegisterStartupScript runs whatever javascript you give it after the partial postback completes. you don't necessarily have to pass the listbox value- just whatever data you want to provide to the maps api. the first 3 items are for preventing the script from registering a bunch of times (as far as I know). the true at the end tells the scriptmanager to automagically add opening and closing tags around your js code.

How do you call a Javascript function from an ASPX control event?

How do you call a Javascript function from an ASPX control event?
Specifically, I want to call the function from the SelectedIndexChanged event of a DropDownList.
I get a little nervous whenever I see this kind of question, because nine times out of ten it means the asker doesn't really understand what's going on.
When your SelectedIndexChanged event fires on the server, it fires as part of a full postback. That means that for that code to run, the entire rest of your page's load code also had to run.
More than that, the code runs as the result of a new http request from the browser. As far as the browser is concerned, an entirely new page is coming back in the result. The old page, and the old DOM, are discarded. So at the time your SelectedIndexChanged event code is running, the javascript function you want to call doesn't even exist in the browser.
So what to do instead? You have a few options:
Change the page so the control doesn't post back to the server at all. Detect the change entirely in javascript at the client. This is my preferred option because it avoids odd onload scripts in the browser page and it saves work for your server. The down side is that it makes your page dependent on javascript, but that's not really a big deal because if javascript is disabled this was doomed from the beginning.
Set your desired javascript to run onload in the SelectedIndexChanged event using the ClientScript.SetStartupScript().
Apply the expected results of your javascript to the server-model of the page. This has the advantage of working even when javascript is turned off (accessibility), but at the cost of doing much more work on the server, spending more time reasoning about the logical state of your page, and possibly needing to duplicate client-side and server-side logic. Also, this event depends on javascript anyway: if javascript is disabled it won't fire.
Some combination of the first and third options are also possible, such that it uses javascript locally if available, but posts back to the server if not. Personally I'd like to see better, more intuitive, support for that built into ASP.Net. But again: I'm talking about the general case. This specific event requires javascript to work at all.
As Muerte said you have to just put the javascript, or a call to it on the page from the code behind. Personally I use this:
ClientScript.RegisterClientScriptBlock("customscript", "<script>simple script here</script>")
Of you can call the function if you already have a more complex one on the page instead of the stuff I have.
You can't do it directly from an event, because ASPX control event is server side.
What you can do is emit a Javascript in the ASPX event which will call the JavaScript function when the page reloads.
For example, if in your ASPX page you have a Javascript function called "DoSomething()", in you ASPX control event, add the following:
protected void btnSubmit_Click(object sender, EventArgs e)
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "myEvent", "DoSomething()", true);
}
The last boolean parameter defines that tags are added automatically.
In the code behind, attach some markup to the server side control via its attributes collection. This assumes that the function is already in a client script file that is already available to the page.
MyServerDDLControl.Attributes.Add("SelectedIndexChanged", "MyClientSideFunction();");

Resources