Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem selecting element in an iframe booking form

I am trying to select the email field in this iframe booking form. I eventually want to do something else with the field but for now as a test I just want to select the element and change the placeholder.

Getting this error so I am not selecting it correctly: Uncaught TypeError: Cannot set property 'placeholder' of null at HTMLButtonElement.changeCopy

You can view a live version of my code here and see the error in console when you click the button at the top: https://finnpegler.github.io/cart_recover/

I have also included the code as a snippet below but it throws a different error to do with cross origin frames.

var iframe = document.getElementById("booking-widget-iframe");
var field = iframe.contentWindow.document.querySelector("booking[email]");

function changeCopy() {
field.placeholder = "hello";
}

document.getElementById("button").addEventListener("click", changeCopy)
<!DOCTYPE html>
<html lang="en">
<head>
<title>Test site for Cart Recover Tool</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" media="screen" href="stylesheet.css" />
<link href="https://fonts.googleapis.com/css?family=Bree+Serif|Open+Sans&display=swap" rel="stylesheet">
<link rel="icon" href="favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">  
</head>
<body>
Clicking this button should change the placeholder text in the email field below
<button id = "button">Click</button>
</body>

<script src="https://bettercleans.launch27.com/jsbundle"></script><iframe id="booking-widget-iframe" src="https://bettercleans.launch27.com/?w_cleaning" style="border:none;width:100%;min-height:2739px;overflow:hidden" scrolling="no"></iframe>
<script src="script.js"></script>
like image 518
FinnPegler Avatar asked Jan 16 '20 23:01

FinnPegler


People also ask

How do I select an element in an iframe?

Getting the element in Iframe const iframe = document. getElementById("myIframe"); Now, it has and contentWindow property which returns the document object by using that we can access the elements from an Iframe. const iWindow = iframe.

How do I control content of iframe?

getElementById('myIFrame'); // Let's say that you want to access a button with the ID `'myButton'`, // you can access via the following code: const buttonInIFrame = iFrame. contentWindow. document. getElementById('myButton'); // If you need to call a function in the iframe, you can call it as follows: iFrame.

What is #document in iframe?

Definition and Usage. The contentDocument property returns the Document object generated by a frame or iframe element. This property can be used in the host window to access the Document object that belongs to a frame or iframe element.


1 Answers

The reason why field is null is because when the variable was set, the value was blocked. Try opening your JavaScript console on the page and paste in

var iframe = document.getElementById("booking-widget-iframe");

Like in the source, which should work, but then see what happens when you enter in:

var field = iframe.contentWindow.document.querySelector("booking[email]");

You should get something like the following error:

Uncaught DOMException: Blocked a frame with origin "https://finnpegler.github.io" from accessing a cross-origin frame.
    at <anonymous>:1:34

So the problem isn't with field.placeholder = "hello"; being null, it's that field was never set because it was blocked from a cross-origin source.

The way to fix this: If you have access to https://bettercleans.launch27.com/?w_cleaning&iframe_id=j8szoz0b4, then somewhere on the source of that page, enter the following script:

<script>
addEventListener("message", function(e) {
    console.log(e.data);
    if(e.data["setIt"]) {
        document.querySelector("booking[email]").placeholder = e.data["setIt"];
         e.source.postMessage({
             hi:"I did it" 
         });
    }

});


</script>

Then on your https://finnpegler.github.io/cart_recover/ page source somewhere, enter the code:

<script>
var iframe;
addEventListener("load", function() {
    iframe = document.getElementById("booking-widget-iframe");
    iframe.contentWindow.postMessage({
        setIt: "hello"
    });

});
addEventListener("message", function(e) {
    console.log(e);
})
</script>

Warning: untested code, but here's the basic idea: with client side JavaScript, you can't directly edit the elements of an iframe, so the way to communicate with it is to send a message to the iframe using iframe.contentWindow.postMessage. On the iframe side, you can read that message that is coming in with the event listener "message" (or you can do window.onmessage). Then you can send JSON data or text as a message to the iframe, and read it with e.data. So in the above (untested) example, when the main github page wants to change the value of the placeholder to a specific amount, it simply sends a JSON object containing the placeholder data to the iframe, and then on the iframe source side, it reads that incoming message, checks the JSON if it has the set key for setting the placeholder, and if it has that key, then set the value of the placeholder to the value of that property.

Let me know if you have any more questions.

Here's some references:

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage https://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage https://javascript.info/cross-window-communication https://bl.ocks.org/pbojinov/8965299 https://www.ilearnjavascript.com/plainjs-postmessage-and-iframes/ https://medium.com/@Farzad_YZ/cross-domain-iframe-parent-communication-403912fff692

like image 85
B''H Bi'ezras -- Boruch Hashem Avatar answered Oct 12 '22 15:10

B''H Bi'ezras -- Boruch Hashem