Timing issues without didRender

Open
#38 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
25/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
javascript
Domain
frontend

Research direction

Start with Component.js and the component template shown in the issue, then reproduce the sequence of expanding the text and loading new content. Compare the did-update and did-insert timing around the content element; done when overflow is recalculated correctly after replacement without relying on a timeout.

Written by the indexing model from the issue text.

Description

In the process of rewriting components to Octane and using modifiers I ran into timing issues when didRender could no longer be used. The component in question renders text and based on if the text is scrollable or not adds an ‘expand text’ button, which when clicked shows the whole text without having to scroll.

See the following image for some explanation:
truncated-toggle

  1. Short text that is not scrollable
  2. Long text that scrolls, button is shown
  3. When the long text is expanded (There is also a button to collapse the content, but forgot to add it in the image)
  4. New text is loaded, should show button

The problem occurs when you expand the text and then load in new text. Every time new text gets loaded the text gets collapsed by default, then it checks if the text is scrollable. But because it takes some time to render the collapsing it does not see the text as scrollable and no button is shown.

Component.js :

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking'

export default class TruncatedToggle extends Component {
  @tracked
  hasOverflow = false;

  @tracked
  opened = false;

  @action
  init() {
    this.opened = false;
  }

  @action
  getOverflow(element) {
    this.hasOverflow =  element.scrollHeight-1 > element.clientHeight;
  }

  @action
  buttonClicked() {
    this.opened = !this.opened;
  }
}

Previously the getOverflow code was in didRender in which the element scrollHeight and clientHeight gave correct values. Tried to set opened in the init() function to have some time between getting the overflow and collapsing the content, but that was in vain.

Component hbs:

<div class="truncated-toggle"
  {{did-update this.init @content}}
>
  <div class="truncated-toggle__content"
    {{did-insert this.getOverflow}}
    {{did-update this.getOverflow @content}}
  >
    {{{@content}}}
  </div>

  {{#if this.hasOverflow}}
    <button {{action 'buttonClicked'}} class="btn btn--default">
      {{#if this.opened}}
        Collapse text
      {{else}}
        Expand text
      {{/if}}
    </button>
  {{/if}}
</div>

I am able to make this work by adding a timeout:

  @action
  getOverflow(element) {
    setTimeout(() => {
      this.hasOverflow =  element.scrollHeight-1 > element.clientHeight;
    })
  }

But this feels a bit hacky to me. Is this the way to go, or is there a solution that I do not know about?

Dominant language
TypeScript
Stars
86
Forks
34
PR merge metrics
No merged PRs in 30d

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from emberjs/ember-render-modifiers

All issues in emberjs/ember-render-modifiers

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.