#The {{#each doesn't render

1 messages · Page 1 of 1 (latest)

gleaming summit
#

and I need a tip how to proceed to get it work. It's Ember 5.12 and a Glimmer component. The template contains a button, a list, and then, a dialog. The dialog renders fine, except the central 'each' enclosure, which doesn't appear (blank). The albums and albumsIndex are both @tracked arrays of equal length, containing proper values.

  ...
  this.toggleDialog('chooseAlbum');
}
getAlbum = (i) => {
  return this.albums[i];
}
<template>
  <button class='menu_img' type="button" title="{{t 'imageMenu'}}"
  {{on 'click' (fn this.z.toggleMenuImg 1)}}
  {{on 'keydown' this.detectClose}}></button>
  <ul class="menu_img_list" style="text-align:left;display:none">
    ...
  </ul>

  <dialog id="chooseAlbum" style="z-index:999" {{on 'keydown' this.detectEscClose}}>
    <header data-dialog-draggable>
      <div style="width:99%">
        <p style="color:blue">{{t 'selectTarget'}}<span></span></p>
      </div><div>
        <button class="close" type="button" {{on 'click' (fn this.z.closeDialog 'chooseAlbum')}}>×</button>
      </div>
    </header>
    <main style="padding:0.5rem">
      <b>{{t 'selectAlbum'}}</b>
      <span>(”.” = ”{{this.z.imdbRoot}}”):</span><br>
      <div class="albumList">

        {{#each this.albumsIndex as |i|}}
          <span class="pselect glue">
            <input id="album{{i}}" type="radio" name="albumList">
            <label for="album{{i}}" style="display:block;margin-left:1rem">
              ”.{{fn (this.getAlbum i)}}”
            </label>
          </span>
        {{/each}}

      </div>
        <button type="button" {{on 'click' (fn this.doMove)}}>{{t 'button.move'}}</button>
      &nbsp;<button type="button" {{on 'click' (fn this.z.closeDialog 'chooseAlbum')}}>{{t 'button.cancel'}}</button><br>
    </main>
    <footer data-dialog-draggable>
      <button type="button" {{on 'click' (fn this.z.closeDialog 'chooseAlbum')}}>{{t 'button.close'}}</button>&nbsp;
    </footer>
  </dialog>
</template>
...```
acoustic spoke
#

What does the JS console print if you put {{log this.albumsIndex}} and {{log this.albums}} right above the #each?

gleaming summit
#

Array(13) [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, … ]
and
Array(13) [ "/2021–2025", "/abc", "/abc/heml", "/abc/suba", "/abc/subb", "/abc/subb/subba", "/Album_för_annat_som_man_behöver", "/Album_för_dokumentation_av_tillståndet_i_socknen", "/def", "/def/subalbum", … ]
which is expected.

acoustic spoke
#

Yeah, that looks okay. Are there not even empty elements where you would expect them to be?

#

You can also try to add an else block to the loop to see if it considers the list empty. In that case, at least something should render

gleaming summit
#

Inserting if-else like this renders empty like before:

...
<div class="albumList">
  {{#each this.albumsIndex as |i|}}
    {{#if i}}
      index gt zero
    {{else}}
      index equals zero
    {{/if}}
    <span class="pselect glue">
      <input id="album{{i}}" type="radio" name="albumList">
      <label for="album{{i}}" style="display:block;margin-left:1rem">
        ”.{{fn (this.getAlbum i)}}”
      </label>
    </span>
  {{/each}}
</div>
...
```No 'index texts'.
#

A side effect appeared actually at the first {{log...}} test: In the console log, somewhere in between normal logs, 22 lines, each with Array [] did appear, and eventually the Array(13)s. No idea from where they originated, never seen before. Just in case; you asked for empty elements? Async hell?

acoustic spoke
#

Oh sorry, I meant adding an else to the each block. That will render if the each has no elements to render. I'm not too sure about async issues, but that would be how I'd tackle the debugging

#

How are the arrays populated? You might need to reassign them if they are initialized as empty or wrap them in a TrackedArray of tacked-buildins

gleaming summit
#

Yes indeed, this text appears:

<div class="albumList">
  {{#each this.albumsIndex as |i|}}
    <span class="pselect glue">
      <input id="album{{i}}" type="radio" name="albumList">
      <label for="album{{i}}" style="display:block;margin-left:1rem">
        ”.{{fn (this.getAlbum i)}}”
      </label>
    </span>
  {{else}}
    text to see something, appears!
  {{/each}}
</div>```The arrays are populated by pushing, e.g.:
```js
this.albumsIndex = [];
for (let i=0; i<this.albums.length; i++) this.albumsIndex.push(i);```The `this.albums` is first correspondingly pushed from a temp variable, which is looped through with some selection. The `temp` was created from a service storage like `let temp = [...this.z.imdbDirs];`.
gleaming summit
ebon hazel
#

use TrackedArray from tracked-built-ins to see re-renders after an [].push(...

#

otherwise .slice()

gleaming summit
acoustic spoke
#

Yeah, @tracked only causes a rerender when the variable itself is reassigned. If you populate the array layer, you might not see the updated state appear on the template as it is still the same array, just with different contents. For this you will need to wrap your array in TrackedArray after construction. This will notify the change tracking system on every change to the array content

#

As a side note. Do you need the index array for anything else? You can get the index of the items in an #each loop by adding another parameter e.g. {{#each this.albums as |album index|}}

gleaming summit
# acoustic spoke Yeah, @tracked only causes a rerender when the variable itself is reassigned. If...

I have read https://github.com/tracked-tools/tracked-built-ins and https://www.npmjs.com/package/tracked-built-ins/v/0.1.0 and successfully installed TrackedArray. Then I tried to 'declare' my variables according to the Usage notes, but without success. Assuming the same template as before, and with the following JS excerpt, please guide me further. moveFunc, which opens the dialog, is called from the ul.menu_img_list, see my initial post,

import Component from '@glimmer/component';
import { inject as service } from '@ember/service';
import { tracked } from '@glimmer/tracking';
import { TrackedArray } from 'tracked-built-ins';
albums = new TrackedArray([]);
albumsIndex = new TrackedArray([]);
...
moveFunc = () => {
  let tmp = [...this.z.imdbDirs];
  this.albums = [];
  for (let alb of tmp) {
    if (alb !== this.z.imdbDir && alb.slice(1) !== this.z.picFound) this.albums.push(alb);
  }
  this.albumsIndex = [];
  for (let i=0; i<this.albums.length; i++) this.albumsIndex.push(i);
  this.toggleDialog('chooseAlbum');
}
getAlbum = (i) => {
  return this.albums[i];
}```No build or runtime error, just nothing detected in #each. 

With `albums = new TrackedArray([]);` etc., and after later adding `{{log...`s like earlier, *now nothing* was printed in the browser log, except that a side effect like
#1334978294046789693 message appeared, and very early in the log, perhaps about when all components are compleatly loaded, containing 22 lines of 
`Proxy { <target>: [], <handler>: {…} }`
Next, with```js
@tracked albums = [];
albumsIndex = new TrackedArray([]);```instead, the browser log produces 11 pairs of```Array []
Proxy { <target>: [], <handler>: {…} }```Hope this will lead somewhere. Btw, I can't track the meaning of the number 11. I have also verified that```{{log this.albums}}
{{log this.albumsIndex}}```prnts nthng with TrackedArray and as expctd with @tracked bt alws triggrs the 2×11 side effct.
Thanks.
ebon hazel
#

first off there is no need to track albumsIndex
seconds for albums you want

albums = new TrackedArray([]);
...
moveFunc = () => { ....
gleaming summit
#

Yes I understand that albumsIndex is superfluous, just trying to primarily cope with the lack of rendering/tracking without changing more in the code than just to have that work. Thus, I've tried js albums = new TrackedArray([]); albumsIndex = new TrackedArray([]);resultless.

Added later: I have now changed the 'excerpt' to contain these lines, and added some experience of that. Please reread! thankyou

acoustic spoke
#
albums = new TrackedArray([]);
albumsIndex = new TrackedArray([]);
...
moveFunc = () => {
  let tmp = [...this.z.imdbDirs];
  this.albums = [];

You reassign the array in the move function it seems, this will remove the TrackedArray wrapper.
Still, I would not expect the issue to occur in this way.

can you share the entire component and template?

gleaming summit
ebon hazel
#

same for albmuns Index

#

6 lines below

gleaming summit
#

Have to leave for a few hours

tepid surge
#

@gleaming summit can you confirm that you restarted your ember server after installing tracked-built-ins? if you didn't, that can cause all sorts of weird issues

gleaming summit
# tepid surge <@489693456239689729> can you confirm that you restarted your ember server after...

I'm running a Node server (node-express), see the scripts https://github.com/toreric/mish-dev/blob/master/server.js and https://github.com/toreric/mish-dev/blob/master/node-express.
When testing the ember server with ember serve in the relevant catalog, the browser log catches two of thouse 11 'extra-triggered' line pairs, then a server call breaks, producing 404.
You may ask why Node? Since my idea is to have a portabel system that fits a server or a desktop or whatever wirh equal functionality.

gleaming summit
gleaming summit
#

I have found an indication pointing to the 11 ! It is document.querySelectorAll('.img_mini').length, which I can verify by changing into different 'albums' (imdbDir). Because of that I moved the topmost function selMinImgs at https://github.com/toreric/mish-dev/blob/master/mish-project/app/components/menu-image.gjs#L30 down within the MenuImage component (then being referenced this.selMinImgs), without visible change, exactly the same behaviour. I believe that such a function could fairly well be defined outside?

Summary so far is (for me as I have learned) that

  1. Reset with = [] or length = 0 both removes reactivity (isn't reset with @tracked, retracking possible?);
  2. Reset with length = 0 also makes the variable unprintable (empty?);
  3. The number of extra-triggered lines, connected to the mentioned number of dom elements, is
    some side effect, perhaps generated in some utility function that loops through them all?
  4. ”Outside” functions may be used in the way shown. (inner global?)
    OK? thankyou
tepid surge
#

@gleaming summit re: 1), if you end up doing a this.albums = [] you are indeed zapping your tracked array and your template won't update

#

if you instead do a this.albums = new TrackedArray([]); you should be set