After much Googling throughout the day and night this weekend I found a way to create an alphabetic table grid and insert it into the DOM. I was thrilled to get it working with this Twiddle, but I’m running into trouble getting it to work in my app.
Does anyone know how to var array = [dynamic array] in an Ember Helper?
The path you’re headed down is going to be hard to get right. For example
there’s a bug that causes the previous render to not be removed when running again (when the window resizes, for example).
it’s leaking a global event listener
the helper throws an exception when its module is evaluated (it’s trying to return a non-existent function)
it works by accident of timing and wouldn’t work in a real app if you navigated away from it and came back
You will fight more bugs if you try to efficiently re-render when the array changes. Many of the problems you’re trying to solve are ones that Glimmer is already built to solve for you.
Outstanding and infinitely more elegant than my hacky solution for alphabetical table grids in Ember (I always try to SEO-up my comments here for the future guy like me trying to figure all this out ).
Interestingly I just discovered the resizing bug and was afraid what it was going to do to my week. Greatly appreciate you taking the time.
However, while I can see the terms in console, I can’t see them on the page. Feels like the last step is a change here, but I can’t find the right combination.
{{!-- alpha-grid/template.hbs }}
{{#each rows as |row|}}
<div style="display: flex">
{{#each row as |item|}}
<div style="min-width: 100px">{{item}}</div>
{{/each}}
</div>
{{/each}}
Hi @ef4 , thought I solved this problem with TailwindCSS, but turns out I wasn’t looking close enough and the terms were no longer alphabetized. So I rolled it back to flex/min-width and this is the result.
After wrestling with it through the long weekend, I concluded this comes from window.innerWidth (or $(window).width() in the Twiddle, along with the subsequent window.addEventListener and window.addEventListener.
Would you recommend using clientWidth instead, and, if so, how? Found another answer of yours on the subject, but don’t know if the same workflow applies here. Also found ember-in-viewport and it seems like it could provide a way to make this work.
Is there a good way to bind the table/grid to the width of an element instead of the window?
You can definitely measure the width of any element, but you can’t easily get an event telling you when a particular element changed size. That said, it’s probably enough to continue relying on window resize events (since the only thing likely to change the size of your element is a change in the size of the window).
So you can keep window.addEventListener('resize', ...) but replace window.innerWidth with this.element.getBoundingClientRect().width.
In my original example the columns were fixed at 100px wide, which is why there’s a divide-by-100 in that code. If you pick a different size for the columns, change it to match. There shouldn’t be a need for a fudge factor like the extra 1.5.
If things still aren’t fitting correctly, double-check that the element you’re measuring has the geometry you expect (by giving it a border or something visible).
Yes, the element was set wrong and being measured wrong. Fixed it, then stretched the min-width to 175px, set a max-width at 175px to force breaks in the long terms, and added 8px of padding.
Sorry to bother you so much today, @ef4. One more question on this.
I’ve got to break the terms up separately based on first letter. I tried using ember-composable-helpers, but unless I’m doing it wrong using group-by forces the terms into horizontal alphabetization, instead of the desired vertical result.
Went with ember-truth-helpers to do an “if equals” conditional comparison like so:
The first 3 terms do not eq item.letter "m" and aren’t shown. However, they are replaced by the last 3 rows moving left and pushing the true first “M” term down… which throws everything off.
Is there a way to prevent this behavior or group-by without breaking the flex?
Assuming you have an {{alpha-grid}} component that works the way you want, don’t mess with it. Instead, call it multiple times, with different batches of words for each letter. You can do the grouping by letter in Javascript in a new, outer component that calls alpha-grid.
If you actually want the empty letters to appear (as in your screenshot), you’ll need to iterate through the whole alphabet.
// this will return a list structured like:
//
// [
// {letter: "a", names: [] },
// { letter: "b", names: ["banana", "byte"] },
// ... and so on
// ]
letterGroups: computed(`names.[]`, function() {
let groups = [];
// "a" is ascii code 97. "z" is 122.
for (let letterIndex = 97; letterIndex < 123; letterIndex++) {
let letter = String.fromCharCode(letterIndex);
groups.push({
letter,
names: this.names.filter(name => name[0].toLowerCase() === letter))
});
}
return groups;
})
Then in your template:
{{#each letterGroups as |group|}}
<h2>{{group.letter}}</h2>
{{alpha-grid @names=group.names}}
{{/each}}