1

How can I click on a link by using the stringByEvaluatingJavaScriptFromString method in a UIWebView? The actual hyperlink itself is different every time but the wording ("Test") inside the Test code is always the same.

How would I go about doing this? I have had a suggestion to do the following (which doesn't work and doesn't do anything):

var fonts = document.getElementsByTagName('font');
for(i=0;i<fonts.length;i++) {
  if (fonts[i].innerHTML == 'Test') {
  fonts[i].parentNode.childNodes[0].click();
  break;
 }
} 
6
  • Do you want to click on the link or do you want to load the page at the link's URL ? Commented Dec 4, 2011 at 16:42
  • 1
    see this stackoverflow.com/questions/6157929/… Commented Dec 4, 2011 at 17:37
  • The trouble is, I don't have access to editing the page and it doesn't have any IDs or anything. I need to find the text in the webpage and then click on the link associated with that text... Commented Dec 4, 2011 at 17:38
  • The SO link shows you how to click a link. No need to edit the page - all the code goes into the string you pass to stringByEvaluatingJavaScriptFromString. If your problem is also finding the link.. that's kinda a different question on it's own. It will involve iterating all links on the page like you do in your question. Commented Dec 4, 2011 at 20:11
  • well it says 'getElementById' but my link doesn't have an ID... That's the problem. How can I search for text on the page e.g. "test" and then click on the hyperlink associated with it? Commented Dec 4, 2011 at 20:17

2 Answers 2

4
+100

Looks like you have an answer including the Objective-C code you need, but I would imagine that for the javascript you can simply fire the contents of the link's onclick or navigate to the appropriate url instead of going through the trouble of simulating a mouse click. Granted, I have not tested this in an iOS app but feel free to give it a shot:

var links = document.getElementsByTagName('a');
for(i=0;i<links.length;i++) {
  if (links[i].innerHTML.indexOf('Test') != -1) {
  clickLink(links[i]);
  break;
 }
} 

function clickLink(linkobj) {
 var onclickHandler = linkobj.getAttribute('onclick');
 if (onclickHandler == null) window.location = linkobj.getAttribute('href').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
 else eval(onclickHandler(linkobj));
}

By the way, there is an eval in this code that will run the contents of the onclick handler. This can be unsafe. If you only need to navigate to a location specified by the link then you may want to remove the portion dealing with onclick.

A much simpler version of this is printed below (since your sample code does not appear to need to deal with onclick) which may be easier to use. In this case I am calling it after a 1-second delay, but in reality, since it seems that this code runs in response to a trigger on the iOS side (button click?), you should not use a delay and instead simply wait enable the trigger until loading is complete - webViewDidFinishLoad.

function clickLink() {
    var links = document.getElementsByTagName('a');
    for (i = 0; i < links.length; i++) {
        if (links[i].innerHTML.indexOf('Prev') != -1) {
            window.location = links[i].getAttribute('href').replace(/^\s\s*/, '').replace(/\s\s*$/, '');
            break;
        }
    }
}

setTimeout(clickLink, 1000);

jsFiddle which demonstrates this using your sample code: http://jsfiddle.net/fzKL7/5/

Sign up to request clarification or add additional context in comments.

20 Comments

unfortunately your code doesn't work for me. It just stays on the same page?
@pixelbitlabs Can you post a little bit of the HTML source that includes one of the links you are trying to click? The code I posted should work but it's hard to know exactly what your situation is without seeing any code.
just to note (I know it sounds obvious) I am not trying to click them at the same time. I just tried it on 'Prev Day' to test that initially but it didn't work.
@pixelbitlabs Do you get an error? Anything at all? If you replace the js with alert('Hello World!'); does that work? How about alert(links.length);? alert(links[i]);? Unrelated, the last stringWithFormat in your code is unnecessary.
@pixelbitlabs I would love to help you further but I am at a loss - based on the sample data you have provided my Javascript works correctly. We also have verification from another user that it works in the context of an iOS app and by setting alerts you were able to see for yourself that the Javascript is executing in your app. Without sitting down in front of your code I am not sure what else I can do for you. What if you simply execute window.location = 'http://apple.com/'; and/or window.location = one of your URLs? Might help narrow things down.
|
1

I have created a sample app with the function from the other SO question mentioned by hooleyhoop in the comments.

This is what I end up with:

- (void)webViewDidFinishLoad:(UIWebView *)wv {
    // Called when the website has finished loading and triggers the JS code
    NSString *javascript = @"function simulate(element, eventName) \
    { \
        var options = extend(defaultOptions, arguments[2] || {}); \
        var oEvent, eventType = null; \
        for (var name in eventMatchers) \
        { \
            if (eventMatchers[name].test(eventName)) { \
                eventType = name; break; \
            } \
        } \
        if (!eventType) { \
            alert('Only HTMLEvents and MouseEvents interfaces are supported'); \
        } \
        if (document.createEvent) \
        { \
            oEvent = document.createEvent(eventType); \
            if (eventType == 'HTMLEvents') \
            { \
                oEvent.initEvent(eventName, options.bubbles, options.cancelable); \
            } \
            else \
            { \
            oEvent.initMouseEvent(eventName, options.bubbles, options.cancelable, document.defaultView, options.button, options.pointerX, options.pointerY, options.pointerX, options.pointerY, options.ctrlKey, options.altKey, options.shiftKey, options.metaKey, options.button, element); \
            } \
            element.dispatchEvent(oEvent); \
        } \
        else \
        { \
            options.clientX = options.pointerX; \
            options.clientY = options.pointerY; \
            var evt = document.createEventObject(); \
            oEvent = extend(evt, options); \
            element.fireEvent('on' + eventName, oEvent); \
        } \
        return element; \
    } \
    function extend(destination, source) { \
        for (var property in source) \
            destination[property] = source[property]; \
        \
        return destination; \
    } \
    var eventMatchers = { \
        'HTMLEvents': /^(?:load|unload|abort|error|select|change|submit|reset|focus|blur|resize|scroll)$/, \
        'MouseEvents': /^(?:click|dblclick|mouse(?:down|up|over|move|out))$/ \
    }; \
    var defaultOptions = { \
        pointerX: 0, \
        pointerY: 0, \
        button: 0, \
        ctrlKey: false, \
        altKey: false, \
        shiftKey: false, \
        metaKey: false, \
        bubbles: true, \
        cancelable: true \
    }; \
    window.setTimeout(function() { \
        var links = document.getElementsByTagName('a'); \
        for(var i in links) { \
            if(links[i].innerHTML == 'Test') { \
                simulate(links[i], 'click'); \
            } \
        } \
    },1);";
    // Execute JS
    [webView stringByEvaluatingJavaScriptFromString:javascript];
}

Test HTML

<html>
    <head>
        <title>Testpage</title>
    </head>
    <body>
        <a href="http://www.google.com">I'm linking to google.com</a><br />
        <a href="http://www.stackoverflow.com">Test</a>
    </body>
</html>

- (void)webViewDidFinishLoad:(UIWebView *)wv

This is the UIWebView's delegate function which get's called as soon as the web view has finished loading the website.

NSString *javascript = @"..."

That's the point where I construct the JS code, at the beginning, the function from the other SO question that triggers the click. At the end I placed a timeout that executes the part that looks for all "a" tags, loops through them, checks if it's innerHTML text is "Test" and if that's the case, it calls the simulate function with the a element as the first parameter and the eventtype as the second parameter. Boom, link clicked.

I used the timeout as it caused problems executing the JS directly, seems like the UIWebView needs some time until the function simulate becomes available.

Cheers, Björn

3 Comments

thanks for your answer! Will this work if the link text has no ID or anything, just plain text? :-)
Yes it will, I added the HTML-Code I used for testing to my answer.
You can also use David's JS code instead of mine, it's much smaller and does the same thing ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.