Problema al seleccionar un elemento en un formulario de reserva de iframe

8

Estoy intentando seleccionar el campo de correo electrónico en este formulario de reserva de iframe. Eventualmente quiero hacer algo más con el campo, pero por ahora como prueba, solo quiero seleccionar el elemento y cambiar el marcador de posición.

Obteniendo este error, así que no lo estoy seleccionando correctamente: Error de tipo no capturado: no se puede establecer la propiedad 'marcador de posición' de nulo en HTMLButtonElement.changeCopy

Puede ver una versión en vivo de mi código aquí y ver el error en la consola cuando hace clic en el botón en la parte superior: https://finnpegler.github.io/cart_recover/

También he incluido el código como un fragmento a continuación, pero arroja un error diferente relacionado con los marcos de origen cruzado.

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>

FinnPegler
fuente
1
Los navegadores bloquearán los intentos de un marco principal para manipular el contenido o la estructura de un marco secundario, si no son del mismo origen, es decir, no son del mismo dominio. En su caso, el origen del marco primario es finnpegler.github.io pero el origen del marco secundario es bettercleans.launch27.com. Si tiene acceso al código fuente js de bettercleans.launch27.com, puede intentar solucionarlo publicando un mensaje en el marco secundario. Vea si esta publicación SO le ayuda a stackoverflow.com/questions/25098021/…
Nivi M

Respuestas:

6

La razón por la cual el campo es nulo es porque cuando se estableció la variable, el valor se bloqueó. Intenta abrir tu consola de JavaScript en la página y pégala

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

Al igual que en la fuente, que debería funcionar, pero luego vea qué sucede cuando ingresa:

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

Debería obtener algo como el siguiente error:

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

Entonces, el problema no es field.placeholder = "hello";ser nulo, es que el campo nunca se configuró porque estaba bloqueado desde una fuente de origen cruzado.

La forma de solucionar esto: si tiene acceso a https://bettercleans.launch27.com/?w_cleaning&iframe_id=j8szoz0b4 , en algún lugar de la fuente de esa página, ingrese el siguiente 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>

Luego, en su https://finnpegler.github.io/cart_recover/ página fuente en alguna parte, ingrese el código:

<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>

Advertencia: código no probado, pero esta es la idea básica: con JavaScript del lado del cliente, no puede editar directamente los elementos de un iframe, por lo que la forma de comunicarse con él es enviar un mensaje al iframe usando iframe.contentWindow.postMessage. En el lado del iframe, puede leer el mensaje que viene con el "mensaje" del detector de eventos (o puede hacer window.onmessage). Luego puede enviar datos o texto JSON como mensaje al iframe y leerlo con e.data. Entonces, en el ejemplo anterior (no probado), cuando la página principal de github quiere cambiar el valor del marcador de posición a una cantidad específica, simplemente envía un objeto JSON que contiene los datos del marcador de posición al iframe, y luego en el lado de origen del iframe, lee ese mensaje entrante, comprueba el JSON si tiene la clave establecida para configurar el marcador de posición y si tiene esa clave,

Avísame si tienes más preguntas.

Aquí hay algunas referencias:

https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage https://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage https://javascript.info/ comunicación entre ventanas 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

bluejayke
fuente
0

Primero traigamos algo de claridad sobre lo que realmente está sucediendo. Para ayudar al análisis, he modificado su script sin introducir ningún efecto secundario de la siguiente manera:

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

console.log( `iframe: ${ iframe }` );
console.log( `iframe.contentWindow: ${ iframe.contentWindow }` );
console.log( `iframe.contentWindow.document: ${ iframe.contentWindow.document }` );
console.log( `iframe.contentWindow.document.querySelector("booking[email]"): ${ iframe.contentWindow.document.querySelector( "booking[email]" ) }` );

function changeCopy() {
    console.log( "-------------------------------------------------------------------------------" );
    console.log( "changeCopy: started" );
    console.log( "-------------------------------------------------------------------------------" );

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

    console.log( `iframe: ${ iframe }` );
    console.log( `iframe.contentWindow: ${ iframe.contentWindow }` );
    console.log( `iframe.contentWindow.document: ${ iframe.contentWindow.document }` );
    console.log( `iframe.contentWindow.document.querySelector("booking[email]"): ${ iframe.contentWindow.document.querySelector( "booking[email]" ) }` );

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

    console.log( "-------------------------------------------------------------------------------" );
    console.log( "changeCopy: finished" );
    console.log( "-------------------------------------------------------------------------------" );
}

document.getElementById( "button" ).addEventListener( "click", changeCopy )

Cargar el documento con el script anterior demostró el siguiente resultado: Ejecutar salida de script

¿Qué hemos aprendido de la salida?

  1. Antes de hacer clic en el botón, se iframe.contentWindow.document.querySelector( "booking[email]" )evalúa como null. Por lo tanto, la variable fieldera esencialmente null.

  2. ¿Por qué iframe.contentWindow.document.querySelector( "booking[email]" )evalué null antes del clic del botón ?

    • Como el iframedocumento no se había cargado, el navegador (Safari) consideró que no era óptimo ejecutar políticas de seguridad entre los marcos primarios y secundarios.
  3. En el momento en que presioné el botón Hacer clic, el documentde #booking-widget-iframe(marco secundario) se había cargado por completo y se habilitó la aplicación de políticas de seguridad entre los marcos primario y secundario. En consecuencia, el intento de accederiframe.contentWindow se bloqueó rápidamente debido al incumplimiento de la política de marcos de origen cruzado.

Posibles resoluciones:

  • Para que los scripts en el marco primario tengan acceso a los objetos en el marco secundario, los marcos primarios y secundarios deben cargarse desde el mismo domain(es decir, https://bettercleans.launch27.com ) yport (irrelevante para el caso en consideración )
  • Alternativamente, utilice la publicación de mensajes para la interacción entre ambos marcos como se documenta en Window.postMessage () .

Suponiendo que pueda aplicar la resolución, hay otro problema que debería aparecer 🙂. iframe.contentWindow.document.querySelector("booking[email]")aún lo sería null. La causa raíz del problema posterior se debe a que no bookingse puede encontrar ningún elemento nombrado en el documento de destino. En otras palabras, el selector "booking[email]"es erróneo.

Igwe Kalu
fuente