When using tagless components (tagName = ""), the element property is (understandably) null. However I’d like to access some child node, which is usually done through this.element.querySelector(...). Is there a similar API available for tagless components?
import Component from '@ember/component';
import { action } from "@ember/object";
export default class extends Component {
tagName = "";
@action actionName() {
this.element.querySelector(".class")
// this.element is null, how to get child node here?
}
}
The first is to set an id explicitly on the root element of your component, using guidFor:
import Component from '@ember/component';
import { guidFor } from '@ember/object';
import { action } from '@ember/object/internals';
export default class MyComponent extends Component {
id = guidFor(this);
@action actionName() {
const el = document.querySelector(`#${this.id} .class`);
}
}
<div ...attributes id={{this.id}}>
{{! the rest of the template... }}
</div>
Depending on what you’re doing, though, the second option may be better: write a custom modifier using ember-modifier or possibly@ember/render-modifiers—though it’s easy to reach too quickly for the render modifiers because they feel familiar and a custom modifier is often a better solution.
My rule of thumb is that if I’m doing something which requires access to the element in Octane, I should use a modifier; if what I’m doing does not require access to the element, I should not use a modifier. It’s also often possible to refactor to just using one-way data flow and a series of getters to derive the state required to set something on the DOM, rather than doing it directly via the Element APIs, so the fact that you were doing it via DOM APIs doesn’t mean that’s how you should do it going forward.
With more details on what you’re actually doing with the element, I might be able to suggest how I would solve the specific use case.
The input field needs to be resized based on the content. The technique I’m using here is a hidden label that mirrors the input’s value and the hidden label’s width is set on the input:
onInput on the input updates the hidden label’s text
determine the hidden label’s width
set the width of the input field
In step 2 I need access to the hidden label’s element. I’m currently doing this:
This is a perfect use case for a modifier. (In fact, a colleague and I were implementing something very much like this over the past week, as a custom modifier!)