Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
VFP Web automation and form filling
#1
I want to fill out a form on a website using VFP. 
I can fill in the textboxes in the form with this code:

Code:
thisform.oAntviewDocument = CREATEOBJECT('AntViewAx.AntViewDocument')
thisform.oAvdCtrl = NEWOBJECT('avdctrl','avdctrl.prg')
EVENTHANDLER(this.oAntviewDocument,this.oAvdCtrl)
thisform.oAntviewDocument.CurrentBrowser = thisform.oAntView.object
thisform.oAntView.object.navigate(ALLTRIM(thisform.text1.Value))

ThisForm.OAntViewDocument.ElementValueByName("txtSifre") = SIFRE  && Filling text

I have two questions:
 
1. How can I click on a link in the form with which code? (Picture1)
   
2. How can I check a checkbox in the web form? (Picture2)  
   

Thank you.
Reply
#2
Hello Ozcan,

Here's some example code in VFP to do what you asked.
This is based on the demo code that is pre-installed.

First some code to automatically open the website in the init procedure of the form.

Code:
thisform.oAntviewDocument = CREATEOBJECT('AntViewAx.AntViewDocument') && create the AntViewDocument and assign it to a form property
thisform.oAvdCtrl = NEWOBJECT('avdctrl','avdctrl.prg') && CREATEOBJECT("Ctrl") && We need an object for our events
EVENTHANDLER(this.oAntviewDocument,this.oAvdCtrl)

thisform.oAntView.Init()
thisform.oAntView.UnlockControl("ExampleCompany","WI5PO2-2KSU3Q-HWFXFU-IUMU2V-QF8P2F")
lnStatus = thisform.oAntView.UnlockStatus

thisform.oAntviewDocument.CurrentBrowser = thisform.oAntView.object && this property shows as "Write-only" in the object browser

thisform.text1.Value = [https://eokulyd.meb.gov.tr/]
thisform.oAntView.object.navigate(ALLTRIM(thisform.text1.Value))

To automatically click on the link "button" I've written the following bit in the click method of the LoadString button:
Code:
LOCAL lcjScript
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let info, row, column, link
       info = document.getElementById('information');
       row = info.firstElementChild;
       column = row.firstElementChild;
       link = column.firstElementChild;
       if (link) {
         link.click();
       }
     }
ENDTEXT

thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)

Normally you should check that each of those get element object methods actually returns an object.
So the error handling is missing I expect that you can write that yourself.

It clicked the left hand "button" during my tests.

For "checking" a checkbox in a form I added the following to the "go" button click method:


Code:
LOCAL lcjScript
LOCAL lbIsSuccess
LOCAL leStatus
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let obj
       obj = document.getElementById('auto');
       if (obj) {
         obj.setAttribute("checked","");
       }
     }
ENDTEXT

thisform.oAntView.navigateSync("https://antwise.com/demo/SimpleCheckboxExample.html",lbIsSuccess,leStatus)

thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)


This first navigates to the page https://antwise.com/demo/SimpleCheckboxExample.html which has 3 checkboxes with all of them unchecked. Then it checks the "I have a car" checkbox immediately after loading the page.

This last example makes it clear that it would be really great to have a method for setting a element attribute in the document interface without having to resort to javascript in your code.
Which will be looked into.

Hope this helps,
--
Wil
Reply
#3
The examples you provided are very valuable, thank you very much for your support.
In the code mentioned below, what should I do to click on the 2nd or 3rd button instead of the first button?
{
      let info, row, column, link
      info = document.getElementById('information');
      row = info.firstElementChild;
      column = row.firstElementChild;
      link = column.firstElementChild;
      if (link) {
        link.click();
      }
    }
If you have a link to more demos prepared for VFP, I would be happy if you could share it. Thanks again.
Reply
#4
Hi,

There are multiple ways to do that.
First look at the html again.
   

As you can see in the image above, the second button is the 2nd link element within the div column element.

You could for example use the javascript nextElementSibling to get the object for the 2nd element.

Code:
LOCAL lcjScript
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let info, row, column, link
       info = document.getElementById('information');
       row = info.firstElementChild;
       column = row.firstElementChild;
       link = column.firstElementChild;
       if (link) {
         link = link.nextElementSibling;
         link.click();
       }
     }
ENDTEXT

thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)

Getting the 3rd or 4th etc.. element would be a matter of "next next" until you reached the element of interest.
Do-able for the 3rd element I guess, but beyond that you'll get code that is hard to read/understand.

In that case it might be better to enumerate all the child objects and access them by index, by using the javascript children method.
The code then could look like this:
Code:
LOCAL lcjScript
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let info, row, column, links
       info = document.getElementById('information');
       row = info.firstElementChild;
       column = row.firstElementChild;
       links = column.children;
       if (links.length>0) {
         links[1].click();
       }
     }
ENDTEXT

thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)

More VFP example code would be great and it is on our wish list, but it will probably take some more time as we are working on the control itself. But don't hesitate to ask here if you need assistance and we'll be happy to provide code snippets.

--
Wil
Reply
#5
(2023-11-08, 15:05:52)wila Wrote: Hi,

There are multiple ways to do that.
First look at the html again.


As you can see in the image above, the second button is the 2nd link element within the div column element.

You could for example use the javascript nextElementSibling to get the object for the 2nd element.

Code:
LOCAL lcjScript
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let info, row, column, link
       info = document.getElementById('information');
       row = info.firstElementChild;
       column = row.firstElementChild;
       link = column.firstElementChild;
       if (link) {
         link = link.nextElementSibling;
         link.click();
       }
     }
ENDTEXT

thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)

Getting the 3rd or 4th etc.. element would be a matter of "next next" until you reached the element of interest.
Do-able for the 3rd element I guess, but beyond that you'll get code that is hard to read/understand.

In that case it might be better to enumerate all the child objects and access them by index, by using the javascript children method.
The code then could look like this:
Code:
LOCAL lcjScript
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let info, row, column, links
       info = document.getElementById('information');
       row = info.firstElementChild;
       column = row.firstElementChild;
       links = column.children;
       if (links.length>0) {
         links[1].click();
       }
     }
ENDTEXT

thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)

More VFP example code would be great and it is on our wish list, but it will probably take some more time as we are working on the control itself. But don't hesitate to ask here if you need assistance and we'll be happy to provide code snippets.

--
Wil

Thank you very much.  
Shy
Reply
#6
(2023-11-08, 17:07:34)ozcan Wrote:
(2023-11-08, 15:05:52)wila Wrote: Hi,
There are multiple ways to do that.
First look at the html again.
As you can see in the image above, the second button is the 2nd link element within the div column element.
You could for example use the javascript nextElementSibling to get the object for the 2nd element.
Code:
LOCAL lcjScript
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let info, row, column, link
       info = document.getElementById('information');
       row = info.firstElementChild;
       column = row.firstElementChild;
       link = column.firstElementChild;
       if (link) {
         link = link.nextElementSibling;
         link.click();
       }
     }
ENDTEXT
thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)

Getting the 3rd or 4th etc.. element would be a matter of "next next" until you reached the element of interest.
Do-able for the 3rd element I guess, but beyond that you'll get code that is hard to read/understand.
In that case it might be better to enumerate all the child objects and access them by index, by using the javascript children method.
The code then could look like this:
Code:
LOCAL lcjScript
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let info, row, column, links
       info = document.getElementById('information');
       row = info.firstElementChild;
       column = row.firstElementChild;
       links = column.children;
       if (links.length>0) {
         links[1].click();
       }
     }
ENDTEXT
thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)

More VFP example code would be great and it is on our wish list, but it will probably take some more time as we are working on the control itself. But don't hesitate to ask here if you need assistance and we'll be happy to provide code snippets.
--
Wil

Thank you very much.  
Shy



The code I wrote to click the button with the "Listele" Id on the web form and submit it is not working. I wonder where I might be making a mistake?

  thisform.oAntViewDocument.RequestFormSubmitById("btnListele")

   
Reply
#7
Hi Ozcan,

Your code looks fine to me.
Is the input control part of a html form?

Do you have a link to the page above that I can try and see what is happening?
--
Wil
Reply
#8
(2023-11-10, 22:04:34)wila Wrote: Hi Ozcan,

Your code looks fine to me.
Is the input control part of a html form?

Do you have a link to the page above that I can try and see what is happening?
--
Wil


Thank you very much Wil.

This website is accessed through two-factor authentication system. 
I am sending the entire HTML content (and screenshot of inspect element) in the attachment. 
I want to click "Listele" button and submit the form.
Thank you.


Attached Files Thumbnail(s)
   

.txt   html.txt (Size: 44.37 KB / Downloads: 2)
Reply
#9
Ozcan,

Thanks for the html.

For some reason the default requestSubmit function isn't working. Will try to figure out why that is.

The following however might be able to work around the issue.

Code:
LOCAL lcjScript
LOCAL lbIsSuccess
LOCAL leStatus As Long
LOCAL leError As Integer
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let listele
       listele = document.getElementById('btnListele');
       if (listele) {
         listele.click();
       }
     }
ENDTEXT
thisform.oAntView.navigateSync("https://antwise.com/demo/20231113-formSubmitButton.html",lbIsSuccess,leStatus)
thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)

Your button has a onclick event, so instead of triggering submit, we're triggering the onclick event by programmatically sending a click.

Hope this helps,
Wil
Reply
#10
Ozcan,

Got some more time to look into this (busy day).

The reason it doesn't work, is because the form is using method type "post".
This shouldn't be a problem and is considered a bug. 
Let me know if the workaround I supplied works for you and we'll add some functionality to handle this automatically.
--
Wil
Reply
#11
(2023-11-07, 18:26:06)wila Wrote: Hello Ozcan,

Here's some example code in VFP to do what you asked.
This is based on the demo code that is pre-installed.

First some code to automatically open the website in the init procedure of the form.

Code:
thisform.oAntviewDocument = CREATEOBJECT('AntViewAx.AntViewDocument') && create the AntViewDocument and assign it to a form property
thisform.oAvdCtrl = NEWOBJECT('avdctrl','avdctrl.prg') && CREATEOBJECT("Ctrl") && We need an object for our events
EVENTHANDLER(this.oAntviewDocument,this.oAvdCtrl)

thisform.oAntView.Init()
thisform.oAntView.UnlockControl("ExampleCompany","WI5PO2-2KSU3Q-HWFXFU-IUMU2V-QF8P2F")
lnStatus = thisform.oAntView.UnlockStatus

thisform.oAntviewDocument.CurrentBrowser = thisform.oAntView.object && this property shows as "Write-only" in the object browser

thisform.text1.Value = [https://eokulyd.meb.gov.tr/]
thisform.oAntView.object.navigate(ALLTRIM(thisform.text1.Value))

To automatically click on the link "button" I've written the following bit in the click method of the LoadString button:
Code:
LOCAL lcjScript
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let info, row, column, link
       info = document.getElementById('information');
       row = info.firstElementChild;
       column = row.firstElementChild;
       link = column.firstElementChild;
       if (link) {
         link.click();
       }
     }
ENDTEXT

thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)

Normally you should check that each of those get element object methods actually returns an object.
So the error handling is missing I expect that you can write that yourself.

It clicked the left hand "button" during my tests.

For "checking" a checkbox in a form I added the following to the "go" button click method:


Code:
LOCAL lcjScript
LOCAL lbIsSuccess
LOCAL leStatus
lcjScript = ''
TEXT TO lcjScript NOSHOW PRETEXT 7
() => {
       let obj
       obj = document.getElementById('auto');
       if (obj) {
         obj.setAttribute("checked","");
       }
     }
ENDTEXT

thisform.oAntView.navigateSync("https://antwise.com/demo/SimpleCheckboxExample.html",lbIsSuccess,leStatus)

thisform.oAntViewDocument.RunAnonymousFunction( 1, "", lcjScript)


This first navigates to the page https://antwise.com/demo/SimpleCheckboxExample.html which has 3 checkboxes with all of them unchecked. Then it checks the "I have a car" checkbox immediately after loading the page.

This last example makes it clear that it would be really great to have a method for setting a element attribute in the document interface without having to resort to javascript in your code.
Which will be looked into.

Hope this helps,
--
Wil

Hi.
Sorry. Why this text '() =>' before brackets?
It's beeing part of the  lcjScript variable.
I don't understand that.

CYZ
Reply
#12
(2023-11-24, 18:39:33)carlos@agpsoftware.com Wrote: Hi.
Sorry. Why this text '() =>' before brackets?
It's beeing part of the  lcjScript variable.
I don't understand that.

Hello Carlos,

Don't be confused, it's a short hand notation detail from javascript. 
It's called an arrow function.

The runAnonymousFunction depends on something that is called anonymous functions in javascript.
So basically a function without a name.
You can still pass variables though, that's why the () is there, so you can pass variables in there. (Click on the runAnonymousFunction link to see an example)

More info about that can be read here:
https://www.w3schools.com/js/js_function_definition.asp
and here:
https://developer.mozilla.org/en-US/docs.../Functions
direct link in MDN:
https://developer.mozilla.org/en-US/docs..._functions

--
Wil
Reply
#13
(2023-11-24, 19:07:01)wila Wrote:
(2023-11-24, 18:39:33)carlos@agpsoftware.com Wrote: Hi.
Sorry. Why this text '() =>' before brackets?
It's beeing part of the  lcjScript variable.
I don't understand that.

Hello Carlos,

Don't be confused, it's a short hand notation detail from javascript. 
It's called an arrow function.

The runAnonymousFunction depends on something that is called anonymous functions in javascript.
So basically a function without a name.
You can still pass variables though, that's why the () is there, so you can pass variables in there. (Click on the runAnonymousFunction link to see an example)

More info about that can be read here:
https://www.w3schools.com/js/js_function_definition.asp
and here:
https://developer.mozilla.org/en-US/docs.../Functions
direct link in MDN:
https://developer.mozilla.org/en-US/docs..._functions

--
Wil

I see. Thanks
Reply
#14
Thank you for asking as it made it clear that the documentation could use a little bit extra info about arrow functions.
This has been added and will be in the next update.
--
Wil
Reply


Forum Jump:


Users browsing this thread: 3 Guest(s)