Find element in DOM


#1

Hi,

I want to get name and width in px (element) of differents elements when they are created. I use Ember.run and “afterRender” for this, but I would like to use something else of jQuery

This is my code :

//controllers/build.js
    Ember.run.schedule('afterRender', this, () => {
          let columnsModelAttribution = Ember.A([]);
          let modelAttributionDiv = Ember.$(".containers-parent .report-container");

          if(modelAttributionDiv.length > 0){
            modelAttributionDiv.each((index) => {
              let name = 'example';

              columnsModelAttribution.pushObject({name: name, 'width': Ember.$(modelAttributionDiv[index]).outerWidth()});
            });
          }
        });
      }).on('init'),

I have too access to the object who help me to create element. Do you have any ideas ?

Thanks a lot


#2

Not sure if I understand your issue correctly, If you want access to build controller just use “this”


#3

Sorry, this is not very understable for you…

In my controller (build.js), I have an observer on “elements.[]”. When a new item is add in elements, my observer works. This observer add item in the template. I add Ember.run, because, I can’t have access of the item add in the template at the end of this observer. But in my Ember.run, I want two things :

  • The width of the item who be add on the template (in jQuery i think)
  • The ID of this item (in object accessible in the observer)

Do you know a method for make a each on all items add on the template (width an object) and find the item with my object in the DOM.

I hope i am clear


#4

Controllers don’t have direct access to the DOM, that is what Components are for. So I would suggest moving some of your logic down into components. A component could render your list of things:

{{#each elements as |child|}}
  <div class="child" data-id={{child.id}}>{{child.whatever}}</div>
{{/each}}

And then read out their widths and ids together like:

let widths = [...this.element.querySelector('.child')].map(element => ({ 
  width: element.getBoundingClientRect().width,
  id: element.dataset['id']
});

Also:

This sounds like you’re manually trying to do what would happen automatically if you use an each in your template. No observers should be needed for this kind of thing, and they’re hard to use without introducing bugs.

You have two choices for automatically rerendering a list. You can use a native array and replace the whole array each time you want different items in the list, like

this.set('elements', this.elements.concat([newItem]))

Or you can use an Ember Array and use its pushObject method, which will automatically be observable by templates:

import { A } from '@ember/array';

// when creating the array
let elements = A();

// when updating the array
elements.pushObject(newItem);

#5

One other idea: the liquid-measured component in liquid-fire is an example of a component that exists to measure its own size. You could use it, or you could just look at how it works to get ideas: