3

I'm trying to execute jQuery/Angular calls via WWW::Mechanize::Firefox's eval_in_page. I'm guessing there is some sort of scope issue, because I'm getting errors.

If I try to execute this code:

angular.element(document.getElementsByClassName("input")[0]).triggerHandler(('change');

I get this response:

MozRepl::RemoteObject: ReferenceError: angular is not defined at ...

If I try to execute this code:

$(".input").val("Foo")

I get this response:

MozRepl::RemoteObject: ReferenceError: $ is not defined ...

It seems I don't have access to either framework. The page does appear to have both loaded, however. If I execute the code in the browser console it works fine.

ThisSuitIsBlackNot
  • 21,870
  • 8
  • 56
  • 101
Todd G.
  • 31
  • 2
  • 2
    I don't know enough about Firefox internals to be sure, but I think your issue is related to [this](https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Content_scripts) (and [this](https://bugs.jquery.com/ticket/4151)). `eval_in_page` runs in a sandbox that only has access to certain parts of the DOM (the relevant code is [here](https://metacpan.org/source/CORION/WWW-Mechanize-Firefox-0.79/lib/WWW/Mechanize/Firefox.pm#L532)). You may be able to load jQuery into the sandbox, but I'm not sure why you would...what exactly are you trying to do with jQuery and/or Angular? – ThisSuitIsBlackNot Dec 28 '16 at 22:27
  • I'm attempting to write some code to interface with a web page that relies heavily on Angular to drive it. Specifically, I'm attempting to fill an input field which has no id or name element on it. When that field detects a change event it appears to be triggering an angular defined function that performs some housekeeping. When it detects a blur event it converts the textual input into a pretty "tag" inside a span. Because of this housekeeping, I believe I need to fill in the value and then trip that function. – Todd G. Dec 28 '16 at 23:22

2 Answers2

1

You could click inside the field with $mech->click(), it accepts x, y coordinates, insert the text and remove the focus again. I used PhantomJS for similar work before. It should work for WWW::Mechanize::Firefox too.

use WWW::Mechanize::PhantomJS;
use strict;
use warnings;

my $mech = WWW::Mechanize::PhantomJS->new(log => 1);
$mech->get('http://example.com');

if($mech->success) { 
   # accepts x, y coordinates
   $mech->click(.. field[2]);

   # set a text for example in input-field number 2
   $mech->eval('document.getElementsByTagName("input")[2].value = "Your value";');   

   # Click somewhere else to trigger blur event
   $mech->click(.. outside the field[2]);

  # Read the converted textual input from span
}
user3606329
  • 2,074
  • 11
  • 23
  • This is a good approach, but it would be helpful to include how to find the coordinates. – simbabque Dec 29 '16 at 01:43
  • This helped move me forward. The problem is I still need to trigger a change event to get the behind the scenes house keeping to work. So far I've been unable to do that on an angular element. I'm still looking into how to properly handle this. I'll report back if I find it before someone else posts a solution. Thanks! – Todd G. Dec 29 '16 at 16:07
  • As an aside, I was able to use getBoundingClientRect() to find the elements bounding coordinates. – Todd G. Dec 29 '16 at 16:09
0

Thanks for the ideas all. I wasn't able to solve the original question, but I was able to come up with this alternate solution. Using this javascript I was able to fill in the field and trigger the appropriate change and blur events. Doing this allowed angular to do the processing it needed to do.

$js = qq(
  var myElement = document.getElementsByClassName("input")[0];
  myElement.value = "$value";

  function fireEvent(element, event) {
    var evt = document.createEvent("HTMLEvents");
    evt.initEvent(event, true, true); // event type,bubbling,cancelable
    return !element.dispatchEvent(evt);
  }

  fireEvent(myElement, 'change');
  fireEvent(myElement, 'blur');
);
$mech->eval_in_page($js);

Note the function I used was a trimmed down solution found here. I trimmed it down to just the Firefox code. If you're using a different browser, you'd want to use their more robust code. If anyone comes up with a solution to the original question I'd be happy to accept it.

Todd G.
  • 31
  • 2