0

I am trying to use retina.js with Ember and I'm running into a problem. Retina.js will swap out img elements with a @2x version if it exists and only does so once when the page is refreshed. Apparently I can loop through img elements and create a new RetinaImage instance for AJAX responses, which seems to work for rendering of Ember views as well but the problem is that it does it twice when the page is initially loaded. I've looked into didInsertElement but it fires when the view is inserted AND rerendered. Is there a way to only limit the new RetinaImage(this) to view rerenders?

Relevant code:

Ember.View.reopen({
  didInsertElement: function() {
    this._super();
    $('img').each(function() {
      new RetinaImage(this);
    });
  }
});
Patrick Ng
  • 30
  • 5

1 Answers1

0

The problem with doing it this way, is every single view that's injected into the page will run this code, against every image, you might run the retina image 100 times on one image. You really should centralize it to each instance where you are inserting images.

Imagining that the Foo view has some images, you would do something like this:

App.ImageView = Ember.View.extend({
  setupRetina: function() {
    this.$('img').each(function() {
      new RetinaImage(this);
    });
  }.on('didInsertElement')
});

Or even better would be to create a component out of it:

App.RetinaImageComponent = Ember.Component.extend({
  setupRetina: function() {
    this.$('img').each(function() {
      new RetinaImage(this);
    });
  }.on('didInsertElement')
});

You can read up more on component's here: http://emberjs.com/api/classes/Ember.Component.html

Kingpin2k
  • 47,277
  • 10
  • 78
  • 96
  • Thanks for the reminder about views and components. Still, relying on didInsertElement causes the code to run twice if someone refreshes the page with the view/component on it. Is there a way to only run this code when the view is rerendered or the route is transitioned to? Basically I don't want to execute this code when the view is being inserted into the DOM, only rerender. – Patrick Ng Jun 15 '14 at 05:39
  • I'm not sure that's a true statement. Can you show an example of that? Here's an example to the contrary: http://emberjs.jsbin.com/cubeninu/1/edit , And what do you mean by only do it on rerender? – Kingpin2k Jun 15 '14 at 05:57
  • My guess is that this is an issue with how Retina.js is written. Retina.js is wrapped in an IIFE so there are no extra calls necessary for it to run. As such, when a user loads up the page, Retina.js will immediately swap out the images with a 2x version and set the width and height accordingly. Because of this, I'm experiencing the swap from the initial page load, then doing new RetinaImage(this) will again swap out the 2x version with the 2x version again and thereby use the actual width and height of the 2x image instead of the non-retina image. Continued in next comment.. – Patrick Ng Jun 15 '14 at 06:39
  • See this http://emberjs.jsbin.com/cubeninu/2/edit If you save this locally, you can see the console try to make the call to the 2x2x image again. – Patrick Ng Jun 15 '14 at 06:40
  • I saved it locally and it ran 3 times, one for each picture :/ http://pastebin.com/rpmTEtnQ – Kingpin2k Jun 15 '14 at 15:22
  • There seems to also be a difference between my development machines. On a non-retina computer, it doesn't present this problem but on my Retina Macbook Pro, I see the errors. I'm not sure what the problem is anymore.. – Patrick Ng Jun 15 '14 at 16:09
  • So possibly Safari? Or a plugin on Safari? Or are you in chrome on your laptop? – Kingpin2k Jun 15 '14 at 17:46
  • This is happening in Chrome, Safari, and Firefox on the Retina macbook. Make sure you save the images locally as well to remove that as a variable. – Patrick Ng Jun 17 '14 at 04:18