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

Custom attribute "attached" event too early? #860

Open
DamageLimiter opened this issue Feb 8, 2018 · 4 comments
Open

Custom attribute "attached" event too early? #860

DamageLimiter opened this issue Feb 8, 2018 · 4 comments

Comments

@DamageLimiter
Copy link

DamageLimiter commented Feb 8, 2018

I'm submitting a bug report

  • Library Version:
    "aurelia-framework": "1.1.5"

Please tell us about your environment:

  • Operating System:
    Windows 10

  • Node Version:
    8.9.4

  • NPM Version:
    5.6.0

  • Aurelia CLI OR JSPM OR Webpack AND Version
    CLI 0.32.0 | webpack 3.5.5

  • Browser:
    all

  • Language:
    TypeScript 2.6.2

Current behavior:
(corresponding stackoverflow questions: https://stackoverflow.com/questions/48596232/custom-attribute-attached-event-too-early)
The custom component

I've created a custom component for the navigation of my app. It consists of an ul element and all its li elements are dynamically created based on the items in the router's navigation list. This is happening in the attached event of the component. Nothing special is going on here.

The custom attribute

But because I want to have a good looking fancy menu I also created a custom attribute and implemented it into the root ul element of the custom component. In the attached event of the custom attribute I'd like to do some dom manipulations so that my menu looks like a menu created by those cool kids.

The problem

Although the attached event of the custom attribute is fired AFTER the attached event of the custom component, the dynamically created li items are not part of the dom in the attached event of the custom attribute yet.

The question

My assumption was that on attached event the view of the actual component is attached to dom and that all components before are also attached to the dom. And when I am done with the attached event the html that has been dynamically created here is also attached. Am I mistaken?

On a side note

I am aware of using TaskQueue could solve my problem. However, I would like to know if there's a different approach/solution first because I believe that moving things in time could cause a chain of paradoxes leaving you in a maintenance nightmare.

Repro:
Custom-Component HTML

<ul id="mainMenu" smart-menu>
    <li class="${category.hasActiveItem ? 'active open' : ''}" repeat.for="category of navigationItems">
        <a if.bind="category.navModels.length == 1" href.bind="category.navModels[0].href">
            <i class="${category.icon}"></i>
            <span class="menu-item-parent">${category.navModels[0].title}</span>
        </a>
        <a if.bind="category.navModels.length > 1" href="#" title.bind="category.categoryName">
            <i class="${category.icon}"></i>
            <span class="menu-item-parent">${category.categoryName}</span>
        </a>
        <ul if.bind="category.navModels.length > 1" repeat.for="nav of category.navModels">
            <li class="${nav.isActive ? 'active' : ''}">
                <a href.bind="nav.href" title.bind="nav.title">
                    <span class="menu-item-parent">${nav.title}</span>
                </a>
            </li>
        </ul>
    </li>
</ul>

SmartMenuCustomAttribute

public async attached() {
    //this does work
    //*******************************
    //this._task.queueMicroTask({
    //  call: () => {
    //    this.addCollapseIcons();
    //  }
    //});

    //this does not work
    this.addCollapseIcons();
  }

private addCollapseIcons(){
    this.$("#mainMenu).find('li:has(> ul)').each((i, li) => {
      let $menuItem = $(li);
      let $a = $menuItem.find('>a');
      let sign = $('<b class="collapse-sign"><em class="fa fa-plus-square-o"/></b>');

      $a.on('click', (e) => {
        this.toggle($menuItem);
        e.stopPropagation();
        return false;
      }).append(sign);
      
    })
  }
  • What is the motivation / use case for changing the behavior?
    I kind of expected to be able to modify attached items without the need of defering the execution. Is this a bug or does it work as designed?
@bigopon
Copy link
Member

bigopon commented Feb 10, 2018

It works fine when I was trying to reproduce it:

export class App {
  navigationItems = [
    {
      categoryName: 'Category 1',
      navModels: [
        { icon: 'fa fa-edit', href: 'href0', title: 'Proj1' },
        { icon: 'fa fa-edit', href: 'href1', title: 'Proj2' }
      ]
    }
  ];
}

export class SmartMenuCustomAttribute {

  private $ = jQuery;

  public async attached() {
    // this does work
    // *******************************
    // this._task.queueMicroTask({
    //  call: () => {
    //    this.addCollapseIcons();
    //  }
    // });

    // this does not work
    this.addCollapseIcons();
  }

  private addCollapseIcons() {
    const lis = this.$('#mainMenu').find('li:has(> ul)');
    console.log({ lis });
    lis.each((i, li) => {
      const $menuItem = $(li);
      const $a = $menuItem.find('>a');
      const sign = $('<b class="collapse-sign"><em class="fa fa-plus-square-o"/></b>');

      $a.on('click', (e) => {
        this.toggle($menuItem);
        e.stopPropagation();
        return false;
      }).append(sign);
    });
  }

  public toggle(menuItem) {
    console.log(menuItem);
  }
}

What I see in the console:

image

@DamageLimiter
Copy link
Author

This is weird. Once I am back home I will also do some more repro steps.

@Alexander-Taran
Copy link
Contributor

@DamageLimiter have you had any success with repro?

@Alexander-Taran
Copy link
Contributor

@bigopon can be closed.. maybe..

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

3 participants