AngularJS ng-include dentro do Google Maps InfoWindow?

Estou tentando include um arquivo de modelo views/infowindow.html como o conteúdo da minha InfoWindow do serviço que escrevi para iniciar a API do Google Maps:

 for ( var count = locations.length, i = 0; i < count; i++ ) { var latLng = locations[i], marker = new google.maps.Marker({ … }), infowindow = new google.maps.InfoWindow(); google.maps.event.addListener( marker, 'click', (function( marker , latLng ){ return function(){ var content = '
'; infowindow.setContent( content ); infowindow.open( Map , marker ); }//return fn() })( marker , latLng ) );//addListener }//for

No entanto, parece que o Angular não está processando content quando é inserido na InfoWindow (ao inspecionar o código via Dev Tools, o código que é inserido é

).

Eu esperava que o Angular pré-processasse meu include antes de ser inserido na InfoWindow, mas infelizmente não.

O que estou tentando fazer é possível?

Eu estou pensando que vou ter de alguma forma armazenar em cache o modelo antes de passá-lo para infowindow.setContent() , mas eu não sei como fazer isso (ou se é mesmo o que eu deveria estar fazendo). Eu preferiria carregar o modelo no evento em vez de fazer o cache e injetá-lo para cada marcador.

EDIT Olhando para $ templateCache e uma questão SO relacionada .

EDIT 2 Aqui está um plunk que tenta usar $compile (o conteúdo do InfoWindow ainda é

)


SOLUÇÃO

A base para isso veio da resposta de Mark abaixo . Em sua solução, o conteúdo do InfoWindow é compilado no primeiro clique (de qualquer marcador), mas a InfoWindow não abre de fato até que outro clique em qualquer marcador, provavelmente porque o GoogleMaps é impaciente.

Mover a $compile fora e depois passar o modelo compilado para .addListener resolve o problema:

 for ( … ) { … infowindow = new google.maps.InfoWindow(); scope.markers … var content = '
'; var compiled = $compile(content)(scope); google.maps.event.addListener( marker, 'click', (function( marker , scope, compiled , localLatLng ){ return function(){ scope.latLng = localLatLng;//to make data available to template scope.$apply();//must be inside write new values for each marker infowindow.setContent( compiled[0].innerHTML ); infowindow.open( Map , marker ); };//return fn() })( marker , scope, compiled , scope.markers[i].locations ) );//addListener }//for

Plunker atualizado .

Depois de adicionar o content ao DOM, você precisará encontrá-lo (talvez com um seletor de jQquery?), Então $compile () e aplicá-lo ao escopo apropriado. Isso fará com que o Angular analise seu conteúdo e atue em qualquer diretiva que ele encontrar (como ng-include).

Por exemplo, $compile(foundElement)(scope)

Sem mais código, é difícil dar uma resposta mais precisa. No entanto, aqui está uma pergunta e resposta semelhante à que você pode ver.

Atualização: ok, finalmente consegui que isso funcionasse e aprendi algumas coisas.

 google.maps.event.addListener( marker, 'click', (function( marker , scope, localLatLng ){ return function(){ var content = '
'; scope.latLng = localLatLng; var compiled = $compile(content)(scope); scope.$apply(); infowindow.setContent( compiled[0].innerHTML ); infowindow.open( Map , marker ); };//return fn() })( marker , scope, scope.markers[i].locations )

Eu estava com a impressão de que apenas elementos DOM poderiam ser $ compilados – isto é, primeiro eu tinha que adicionar o conteúdo ao DOM, e depois compilá-lo. Acontece que isso não é verdade. Acima, primeiro compilo o content com o scope e, em seguida, adiciono-o ao DOM. (Eu não sei se isso pode quebrar a binding de dados – isto é, os $ watch () que foram configurados por $ compile.) Eu tive que setar scope.latLng porque o template ng-incluído precisa interpolar {{latLng[0]}} e {{latLng[1]}} . Eu usei innerHTML vez de outerHTML para que apenas o conteúdo de infowindow.html seja inserido.

Plunker

Update2: o clique não funciona na primeira vez. Parece que ‘infowindow.html’ não é carregado até um segundo clique (tentei chamar o escopo. $ Apply () uma segunda vez … não ajudou). Quando eu tive o plunker trabalhando, eu tinha inlined o conteúdo de infowindow.html em index.html:

  

Eu estava usando isso em addListener ():

 var content = '
';

Eu mudei o plunker para usar o modelo embutido.

As respostas acima são sólidas, mas você perde sua binding:

 infowindow.setContent( compiled[0].innerHTML ); 

Faça isso em vez disso:

 infowindow.setContent( compiled[0] ); 

Caso contrário, se você tiver algo como

{{myVar}}

, ele não será atualizado se myVar for atualizado no seu aplicativo.

Você já tentou a function de compilation? http://docs.angularjs.org/api/ng.$compile

Eu não olhei muito em angular ainda, mas acho que isso poderia funcionar.

Como alternativa, você pode tentar fazer o bootstrap do material. mas eu não acredito que seja a maneira correta … http://docs.angularjs.org/guide/bootstrap