# Change iframe src without adding history entry

**URL:** <https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645>\
**Category:** Questions\
**Created:** [February 22, 2021, 4:48pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645 "2021-02-22T16:48:02Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![bouke](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/bouke/32/16341_2.png) [@bouke](https://discuss.emberjs.com/u/bouke)\
**Post date:** [February 22, 2021, 4:48pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/1 "2021-02-22T16:48:02Z")

</div>

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:

```nohighlight
    get previewUrl(): SafeString {
        return htmlSafe(`...`);
    }

```

```nohighlight
    <iframe src={{this.previewUrl}} />

```

See also something this question from 2 decades ago: [javascript - Reload an IFRAME without adding to the history - Stack Overflow](https://stackoverflow.com/questions/821359/reload-an-iframe-without-adding-to-the-history)

---

<div class="post-metadata">

**Author:** ![dknutsen](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/dknutsen/32/16471_2.png) [@dknutsen](https://discuss.emberjs.com/u/dknutsen)\
**Post date:** [February 22, 2021, 5:15pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/2 "2021-02-22T17:15:57Z")

</div>

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…

---

<div class="post-metadata">

**Author:** ![bouke](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/bouke/32/16341_2.png) [@bouke](https://discuss.emberjs.com/u/bouke)\
**Post date:** [February 22, 2021, 6:35pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/3 "2021-02-22T18:35:50Z")

</div>

Now my code is rather simple: I change the component’s property, ember changes the DOM node. What is the “ember” way to replace the iframe element?

---

<div class="post-metadata">

**Author:** ![chriskrycho](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/chriskrycho/32/17763_2.png) [@chriskrycho](https://discuss.emberjs.com/u/chriskrycho)\
**Post date:** [February 22, 2021, 7:21pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/4 "2021-02-22T19:21:17Z")

</div>

It’s mildly annoying, but given the specific thing you’re trying to do, I believe this would work:

```nohighlight
{{#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.” 😂

---

<div class="post-metadata">

**Author:** ![bouke](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/bouke/32/16341_2.png) [@bouke](https://discuss.emberjs.com/u/bouke)\
**Post date:** [February 22, 2021, 8:08pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/5 "2021-02-22T20:08:33Z")

</div>

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`).

---

<div class="post-metadata">

**Author:** ![bouke](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/bouke/32/16341_2.png) [@bouke](https://discuss.emberjs.com/u/bouke)\
**Post date:** [February 22, 2021, 8:24pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/6 "2021-02-22T20:24:13Z")

</div>

I’m now forcing ember to remove the node and recreate the node on the next loop of the runloop using `next('afterRender')` like this:

```nohighlight
@action doSomething(): void {
    this.previewUrl = undefined;
    next('afterRender', () => {
        this.previewUrl = htmlSafe("new-url.html");
    });
}

```

```nohighlight
{{#if this.previewUrl }}
    <iframe src={{this.previewUrl}} />
{{/if}}

```

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.

---

<div class="post-metadata">

**Author:** ![dknutsen](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/dknutsen/32/16471_2.png) [@dknutsen](https://discuss.emberjs.com/u/dknutsen)\
**Post date:** [February 22, 2021, 10:24pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/7 "2021-02-22T22:24:10Z")

</div>

two ideas completely off the top of my head…

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:

```auto
{{#with (component "iframe-component" src=this.previewUrl) as |IFrame|}}
  <IFrameComponent/>
{{/with}}

```

---

<div class="post-metadata">

**Author:** ![chriskrycho](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/chriskrycho/32/17763_2.png) [@chriskrycho](https://discuss.emberjs.com/u/chriskrycho)\
**Post date:** [February 22, 2021, 11:47pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/8 "2021-02-22T23:47:28Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![rwjblue](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/rwjblue/32/9411_2.png) [@rwjblue](https://discuss.emberjs.com/u/rwjblue)\
**Post date:** [February 24, 2021, 12:29pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/9 "2021-02-24T12:29:11Z")

</div>

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.

```nohighlight
{{#if this.renderPrimary}}
  <iframe src="{{@iframeURL}}” /> 
{{else}}
  <iframe src="{{@iframeURL}}” />
{{/if}}

```

Then you make sure your getter for `renderPrimary` bounces from true to false every time you get a new url to use.

Not super pretty, but should work.

---

<div class="post-metadata">

**Author:** ![Nelly](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/nelly/32/17393_2.png) [@Nelly](https://discuss.emberjs.com/u/Nelly)\
**Post date:** [March 18, 2021, 5:58pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/10 "2021-03-18T17:58:21Z")

</div>

Great and useful information, thanks!

---

<div class="post-metadata">

**Author:** ![chriskrycho](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.emberjs.com/chriskrycho/32/17763_2.png) [@chriskrycho](https://discuss.emberjs.com/u/chriskrycho)\
**Post date:** [April 17, 2021, 4:19pm UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/11 "2021-04-17T16:19:12Z")

</div>

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:

```nohighlight
import { modifier } from 'ember-modifier';

export default modifier((iframe, _, { with: targetUrl }) => {
  iframe.contentWindow.location.replace(targetUrl);
});

```

(You may also want some try/catch handling for cross-origin access attempts.)

Invoking that would look like this:

```nohighlight
<iframe
  src="about:blank"
  {{replace-iframe-location with=this.previewUrl}}
></iframe>

```

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.

---

<div class="post-metadata">

**Author:** ![Col\_Boogie](https://avatars.discourse-cdn.com/v4/letter/c/c37758/32.png) [@Col\_Boogie](https://discuss.emberjs.com/u/Col_Boogie)\
**Post date:** [December 23, 2022, 4:41am UTC](https://discuss.emberjs.com/t/change-iframe-src-without-adding-history-entry/18645/12 "2022-12-23T04:41:56Z")

</div>

I used the following method: in the body I put  
\<div id=‘IF’\>  
\<iframe src=‘[https://www.wolframalpha.com/input?i=Memphis%20TN%20Temperature](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}  
}
