Pular para o conteúdo principal

Como acessar um iframe e seus elementos via jQuery?

Recentemente tive um problema no projeto pois sentiu a necessidade de acessar um valor de um input que estava dentro de um iframe. Esse tipo de situação não é tão comum, uma vez que geralmente acessamos os valores do iframe para fora.


Para acessar, de dentro de um iframe, um valor externo, utilizamos o seguinte código:
$('#idDoElementoExterno', parent.document).val();
Entretanto, nunca tínhamos passado pela situação contrária. Pesquisando um pouco descobrimos uma alternativa, porém em JavaScript. Para ficar melhor o entendimento, vamos simular uma situação aqui. Temos uma página html "A.html" e dentro da mesma existe um iframe que aponta (src) para uma página "B.html":

<!-- A.html -->
<html>
 <head>
  <title>Testando iframe - jQuery</title>
   <script language="JavaScript">
    function exibeValor() {
     // alert aqui!
    }
   </script>   
  </head>
  <body>
  <input type="button" value="Exibir valor de campo do iframe" onclick="exibeValor()"/>
  <br/>
  <iframe name="iframeTeste" id="iframeTeste" src="B.html" />
  </body>
</html>
<!-- B.html -->
<html>
 <head>
  <title>Testando iframe - jQuery</title>    
  </head>
  <body>
   Campo de teste: <input type="text" id="campoTeste" />
  </body>
</html>
Suponhamos que queremos buscar o valor digitado no campo de texto ('campoTeste') do iframe e exibir em um alert javascript o mesmo ao clicar no botão que está fora do iframe.
Para isso, precisamos implementar o seguinte código javascript na função "exibeValor()":
var valor = window.parent.iframeTeste.document.getElementById('campoTeste').value;

 alert(valor);
Entretanto, essa abordagem ainda não compreendia o que queríamos, uma vez que estávamos utilizando jQuery. Logo, encontramos a solução abaixo para o mesmo método:
var valor = $('#campoTeste', window.parent.iframeTeste.document).val();
 alert(valor);
Ainda assim, essa implementação ainda faz uso de chamada de atributos javascript bruta. Queríamos algo totalmente jQuery, e então chegamos a código:
var valor = $('#iframeTeste').contents().find('#campoTeste').val();
 alert(valor); 

Tudo ficou mais simples por causa da função contents() do jquery. Normalmente, a função retorna todos os nós filhos a partir dos elementos combinados, mas no caso de um iframe todo o documento é carregado no iframe. Agora você pode usar o find() para localizar os elementos que você precisa para trabalhar e é isso.

Update 15/01/2016

Se você estiver usando o Google Chrome como browser para efetuar os testes deste exemplo, provavelmente receberá um erro do tipo: 
Uncaught SecurityError: Failed to read the 'contentDocument' property from 'HTMLIFrameElement': 
Blocked a frame with origin "null" from accessing a frame with origin "null". 
Protocols, domains, and ports must match.
Isso acontece porque o Chrome tem uma política de restrição de segurança que não permite acesso a outros arquivos direto do disco rígido da sua máquina, mesmo que pertençam ao mesmo diretório/app de origem.

Existem algumas opções simples de resolver isso, vejamos:
  1. Você pode executar seus códigos via Firefox ou outro browser, uma vez que eles não impõem tais restrições;
  2. É possível ainda configurar a flag "--allow-file-access-from-files" no seu arquivo de inicialização do Chrome para habilitar tal recurso;
  3. Ou você pode hospedar suas páginas HTML em algum servidor (Apache, Tomcat, etc.) e executá-las via http://localhost/. A forma mais simples de fazer isso, se você não tiver conhecimentos avançados de servidor, é usando o módulo http-server do Node.js.

-->

Comentários

  1. perfeito..
    vai melhorar e muito meu framework que precisso fazer..

    ResponderExcluir
  2. eu gostaria que fosse ao contrario.
    que o botão Exibir valor de campo do iframe, adicionasse um nome no campo de texto.

    tem como mim ajudar?
    envia pra mim com o link do site.
    davidssombra@live.com

    ResponderExcluir
    Respostas
    1. Oi, desculpa a demora...

      Pra acessar qualquer componente pai de dentro de um iframe é só usar a seguinte chamada:
      $(parent, '#idDoElemento')...

      Blz?

      Excluir
  3. Muito obrigada!! me ajudou muito!!

    Claudia

    ResponderExcluir
  4. bom dia amigo, podes me ajudar?
    eu tenho um site com frameset...

    ------------
    INDEX.html
    ------------
    [title]TITULO DO SITE[/title]
    [frameset rows="30,*" frameborder="NO" border="0" framespacing="0"]
    [frame id="topFrame" name="topFrame" scrolling="no" noresize src="ARQUIVO1.php"][/frame]
    [frame name="mainFrame" src="ARQUIVO2.php"][/frame]
    [/frameset][noframes][/noframes]

    ------------
    ARQUIVO2.php
    ------------
    [script]
    parent.document.title = "NOVO TITULO DO INDEX";
    [/script]

    ------------
    o que quero e não consegui e nem achei nada sobre isso, é pegar o titulo dinamicamente no ARQUIVO2 e passar ao arquivo INDEX.html, porém não funciona, pode me ajudar?

    troquei < por [ e > por ]

    agradeço deste já,
    Sandro.

    ResponderExcluir
    Respostas
    1. Olá Sandro, o seu cenário é bem semelhante ao que mostrei... já tentou acessar o elemento head através das funções que mostrei?

      Excluir
  5. Diogo, tudo bem? O código não funciona no Chrome, dá um erro: "Uncaught SecurityError: Blocked a frame with origin "null" from accessing a frame with origin "null". Protocols, domains, and ports must match.". Faz ideia do q pode ser?

    ResponderExcluir
    Respostas
    1. Olá Rosiene, tudo bem?

      Dá uma olhada no link: http://stackoverflow.com/questions/17950598/using-iframe-with-local-files-in-chrome

      Excluir
  6. Ola muito bom esse tutorial, só que eu tenho uma duvida eu apenas queria ir buscar ao iframe um valor que tenho no CodeBehind. Isto porque o que estou a tentar fazer é ir buscar o numero de notificações que estão dentro da iframe e mostrar no menu da pagina principal quantas notificações o usuário tem, como acontece nos mails, então o que faço é contar o numero de notificações que estão dentro da tabela e guardo numa variável é possível ir buscar essa variável e mostrar na pagina principal?

    Muito Obrigado

    ResponderExcluir
    Respostas
    1. Olá Marco,

      A sua dúvida estaria mais relacionada ao fator "buscar um valor em uma variável javascript no frame interno", é isso?

      Excluir
  7. Ola, entretanto consegui resolver o meu problema.

    Obrigado pela atenção

    ResponderExcluir

  8. Olá Diogo parabéns por este pots. Espero que me ajude. no meu arquivo. b.html em tenho um formulário com vários campos e tem uma função javascript para fazer a validação.

    Ai no arquivo. A.HTML eu tenho um botão chamado gerar O.S como eu faço para que quando eu clicar no botão gerar O.S. ele verifica os campos do arquivo b.html se estão preenchidos ou não. Ou seja eu quero que ele faça a verificação dos campos usando a função que eu utilizei.

    Aguardo um retorno.

    Att.,

    ResponderExcluir
    Respostas
    1. Opa Rodrigo, cara se entendi bem tua questão, você quer acessar os valores e validar se estão preenchidos ou não...

      Se for só isso, pode usar a função:
      var valor = $('#iframeTeste').contents().find('#campoTeste').val();
      if (valor == null || valor == '') {
      alert("Campo obrigatório");
      }

      Entendeu?

      Excluir
  9. Boa noite Diogo.

    Veja se pode me ajudar...

    Tenho um arquivo chamado restaurante.html, dentro deste existe o seguinte trecho de codigo:

    div id="TabbedPanels1" class="TabbedPanels"
    ul class="TabbedPanelsTabGroup"
    li class="TabbedPanelsTab" tabindex="0" Dados do Restaurante /li
    li class="TabbedPanelsTab" tabindex="0" Mapa /li
    /ul
    div class="TabbedPanelsContentGroup"
    div class="TabbedPanelsContent"

    /div
    div class="TabbedPanelsContent"
    iframe scrolling="no" src="Mapa.html id="frame" /iframe
    /div
    /div
    /div

    Note que dentro do iframe é chamado o arquivo Mapa.html.

    Dentro do arquivo Mapa.html eu tenho a chamada de um arquivo contendo codigo java script:

    script type="text/javascript" src="mapa.js" /script

    Dentro deste arquivo tenho codigo da API Google Maps V3 e abaixo usando jquery, quero que quando clicar nas abas do componente TabbedPanels1 (restaurante.html) acione uma função da API Google Maps:

    *****arquivo mapa.js*****
    var geocoder;
    var map;
    var marker;

    function initialize() {
    var latlng = new google.maps.LatLng(-26.257705,-48.629837);
    var options = {
    zoom: 10,
    center: latlng,
    mapTypeId: google.maps.MapTypeId.ROADMAP
    };

    map = new google.maps.Map(document.getElementById("map"), options);

    geocoder = new google.maps.Geocoder();

    marker = new google.maps.Marker({
    map: map,
    draggable: true,
    });

    marker.setPosition(latlng);
    }

    $(document).ready(function () {
    initialize();

    function carregarNoMapa(endereco) {
    geocoder.geocode({ 'address': endereco, 'region': 'BR' }, function (results, status) {
    if (status == google.maps.GeocoderStatus.OK) {
    if (results[0]) {
    var latitude = results[0].geometry.location.lat();
    var longitude = results[0].geometry.location.lng();

    var location = new google.maps.LatLng(latitude, longitude);
    marker.setPosition(location);
    map.setCenter(location);
    map.setZoom(16);
    }
    }
    })
    }

    O codigo acima está perfeito, preciso fazer funcionar o abaixo:

    tentei de 3 formas:
    1 - Não funcionou:

    $('.TabbedPanelsTab').live('click',function(){
    alert ('teste');
    if($("#txtEndereco").val() != ""){
    carregarNoMapa($("#txtEndereco").val());
    }
    })

    2 - Não funcionou

    $(parent, '.TabbedPanelsTab').click(function(){
    alert ('teste2');
    if($("#txtEndereco").val() != ""){
    carregarNoMapa($("#txtEndereco").val());
    }
    })

    3 - Funcionou se eu utilizar o arquivo mapa.js diretamente no arquivo restaurante, utilizando o iframe tambem não funcionou:

    $('.TabbedPanelsTab').click(function(){
    alert ('teste');
    if($("#txtEndereco").val() != ""){
    carregarNoMapa($("#txtEndereco").val());
    }
    })

    ResponderExcluir
  10. iframe id="pixlr" src="http://apps.pixlr.com/express/" height="800" width="1024" frameborder="0">fechariframe

    abrescript

    $(document).ready(function(){

    $("#pixlr").load(function(){
    $("#pixlr").contents().find("#ad-wrap").css("display","none");
    });

    });
    fecha_script

    obs: tive que tirar as tags de fechamento.

    ResponderExcluir
  11. consigo por meio de um form, efetuar login dentro do iframe e deste extrair informações de uma tabela?

    ResponderExcluir
  12. Opa,

    Sim. Desde que ambos pertençam à mesma aplicação. Basta usar a função mostrada usando os seletores de acesso.

    ResponderExcluir
  13. Aqui o codigo não funcionou (nao sei se atualizaram algo no chrome).

    ResponderExcluir

Postar um comentário

Postagens mais visitadas deste blog

Integrando Android e PayPal com Java e MySQL - Parte 1

Uma das funcionalidades mais importantes da maioria dos apps mobile de hoje em dia é a possibilidade de se integrar com plataformas de pagamento online, tais como PagSeguro, MercadoPago ou a mais famosa de todas (a nível internacional): PayPal . Na maioria dos apps de eCommerce, que se caracterizam principalmente por compras e vendas online, não basta somente ter uma boa interface e lógica de negócio implementadas, é também preciso gerenciar tudo isso de forma segura, e para isso precisamos fazer uso de Web Services, bancos de dados, aplicações e outros tipos de recursos e operações no lado do servidor. Com o objetivo de cobrir uma implementação pouco vista em português, esse artigo, dividido em duas partes, visa ensinar como construir uma aplicação básica em Android , usando a biblioteca SDK do PayPal , uma integração server side com um projeto em Java Web , que fará uso de requisições HTTP via Web Services Restful (implementação Jersey ) e salvará os dados em um schema MySQ

"Content is not allowed in prolog" - Entendendo exceção no Seam

Recentemente tive um problema de edição em um arquivo .xhtml utilizando JBoss Seam, Richfaces e afins. A princípio a mensagem de erro não dizia muito a respeito da causa do mesmo: com.sun.facelets.FaceletException: Error Parsing /consulta.xhtml: Error Traced[line: 1] Content is not allowed in prolog. "O conteúdo não é permitido no prólogo". Mas que conteúdo? Em qual prolog? Depois de dar uma pesquisada descobri que o erro acontece em vista de terem sido colocados alguns caraceteres inválidos antes da declaração de documento xml na página xhtml. Em outras palavras, a primeira coisa que deve constar em um documento xml (afins) deve ser: <?xml version="1.0" encoding="utf-8"?> Qualquer coisa antes disso, até mesmo um simples espaço em branco, pode gerar o erro em questão. Por fim, lembre-se de que a declaração de documento xml segue o padrão de encoding definido. Logo temos: <!-- Inc