Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Timing issues without didRender #38

Open
damatri opened this issue Aug 3, 2021 · 1 comment
Open

Timing issues without didRender #38

damatri opened this issue Aug 3, 2021 · 1 comment

Comments

@damatri
Copy link

damatri commented Aug 3, 2021

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?

@damatri
Copy link
Author

damatri commented Aug 10, 2021

Another example would be how to rewrite the sticky chatbox mentioned in this article: https://embermap.com/notes/63-building-a-sticky-chatbox

Which in the conclusion states:

  • The willRender and willUpdate hooks are a great place to take measurements or perform visual calculations on a component's DOM before Ember re-renders it.
  • The didRender hook is useful if you need to update a component's DOM in response to a re-render, for example after the component receives new attrs.

How will you take measurements/make calculations before you get new attributes and after new attributes have rendered?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant