Aurelia attached triggers before repeat.for

戏子无情 提交于 2019-12-10 15:59:49

问题


I'm trying to setup certain logic in Aurelia that would affect DOM nodes looped by repeat.for. If I understand the documentation correctly, the attached() callback of the view is called after DOM rendering and is the place put this kind of logic in.

The problem is that the attached() callback seems to be fired before the repeat.for binding is complete, leaving me with only a partially rendered dom.

In order to illustrate the problem:

I have a custom element containing:

<template>
    <ul>
      <li repeat.for="thing of things"></li>
    </ul>
</template>

Once attached is called(), I would expect having a rendered DOM containing all the li elements, instead. A simple dump of the dom shows an empty

How can is implement a callback that gets access to those li nodes?


回答1:


attached is called when the component's DOM element is "attached" to the DOM. There may be child components such as repeated templates that are further down in the queue to be rendered, the easiest thing to do would be to put your logic at the bottom of the queue:

import {inject, TaskQueue} from 'aurelia-framework';

@inject(TaskQueue)
export class MyComponent {
  constructor(taskQueue) {
    this.taskQueue = taskQueue;
  }

  doSomethingAfterRepeatIsRendered() {
    // your logic...
  }

  attached() {
    this.taskQueue.queueMicroTask({
      call: () => this.doSomethingAfterRepeatIsRendered();
    });
  }
}

There are better approaches than this, but I would need to know more about what kind of work you need to do with the <li> elements to provide a better answer. It's uncommon to use the TaskQueue directly, often things can be refactored into custom elements or attributes that participate in the composition lifecycle more naturally. For example, if you need to do some jQuery stuff with your <li> elements, the "aurelia way" would be to separate this logic from your view-model using a custom attribute:

do-something.js

import {inject, customAttribute} from 'aurelia-framework';
import $ from 'jquery';

@customAttribute('do-something')
@inject(Element)
export class DoSomethingCustomAttribute {
  constructor(element) {
    // "element" will be the DOM element rendered from the
    // template this attribute appears on, in this example an <li> element
    this.element = element;
  }    

  // now we don't need the task queue because attached is called when the 
  // <li> element is attached.
  attached() {
    // this.value is whatever the custom attribute is bound to, in this case
    // its a "thing" from your "things" array.
    $(this.element).doSomething(this.value);
  }
}

Here's the usage:

app.html

<template>
  <require from="./do-something"></require>

  <ul>
    <li repeat.for="thing of things" do-something.bind="thing"></li>
  </ul>
</template>



回答2:


Would like to add here another option for catching DOM changes that is pretty simple, works not only for aurelia and could be really useful when you have some dynamic DOM changes triggered on user interaction, you can use MutationObserver https://developer.mozilla.org/en/docs/Web/API/MutationObserver

import {DOM} from 'aurelia-pal';
...
let mutationObserver = DOM.createMutationObserver(() => {
   // handle dom changes here
});

//start to observe, note you can set different options
mutationObserver.observe(someDomElement, {childList: true, subtree: true, characterData: true});

when you don't neet to observe anymore, you do mutationObserver.disconnect(); usually from detached()



来源:https://stackoverflow.com/questions/35037581/aurelia-attached-triggers-before-repeat-for

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!