I have an iframe that’s rendering some content. I want to programmatically change the iframe’s src attribute. However I don’t want this change to affect the browser’s history.
My initial attempt is this, but this is causing the browser (Firefox) to add history entries when changing the src:
get previewUrl(): SafeString {
return htmlSafe(`...`);
}
I’ve never tried this personally but it sounds like the best way is just to replace the iframe element entirely. Also sounds like if the iframe is same-domain you can use iframe.contentWindow.location.replace(...)as in the SO question you posted…
It’s mildly annoying, but given the specific thing you’re trying to do, I believe this would work:
{{#let this.previewUrl as |url|}}
<iframe src={{url}} />
{{/let}}
I believe that’ll give you a brand new iframe every time, rather than just updating the src for the current iframe. Assuming it works, I’d also add a comment to that effect to say “this is why we’re doing these weird shenanigans.”
Interesting hack, however it doesn’t work for me on Ember 3.16.1. The same element remains in the dom and a navigation history entry is added after changing the src-attribute (which is initiated by a <button> triggering an @action).
I’d be interested to hear your opinions on this solution, or should I call it a workaround? And if you have any suggestions for improvements, I’d be interested in hearing them.
use {{#with ...}} instead of {{#let ...}} as IIRC with doesn’t render block if the value is falsey so that may mean it would definitely re-render the block if the value changes, just a guess.
make a component for the iframe and see what you have to do to re-render the component, i’m pretty sure it would re-render with something like this, though this is pretty gross:
{{#with (component "iframe-component" src=this.previewUrl) as |IFrame|}}
<IFrameComponent/>
{{/with}}
As I was thinking about it later I realized that given how the template layer works, it shouldn’t actually rerender there, and I would expect the semantics of with to be the same here. Glimmer will preserve anything it can detect will be stable. Here, it’s clear that the element should be stable regardless of these shenanigans, so Glimmer is doing the right thing.
Cc. @pzuraq and @rwjblue because I can’t actually think of something clean here.
Use two invocations, toggle them with something like toggleProperty. It will force the current one to be torn down and the new one to be rendered fresh.
I am back with an updated recommendation, because I just hit this in refactoring the LinkedIn ad banner to Octane (!) and thus had cause to think more on how to handle it. You can use a modifier which replaces the iframe location with the location.replace API. That would look like this:
That gives you the desired properties and nicely isolates the complexity! The modifier becomes fairly straightforward to test, too, especially compared to trying to test a component class which does this: you just need to mock the url you’re passing in, and then confirm that the iframe renders the corresponding HTML you hand back.
I used the following method: in the body I put
<div id=‘IF’>
<iframe src=‘https://www.wolframalpha.com/input?i=Memphis%20TN%20Temperature’ style=“width:5in; height:6in” // src is just a sample title=‘Temperature’></iframe> </div>
I also had a script like
function UPdate() { // reload Iframe
T1=document.getElementById(‘IF’)
T2=T1.innerHTML
T1.innerHTML=T2
document.getElementById(‘W’).innerHTML=d}
}