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

Injecting Element do not work with @templateController #1011

Closed
euglv opened this issue Nov 22, 2024 · 3 comments
Closed

Injecting Element do not work with @templateController #1011

euglv opened this issue Nov 22, 2024 · 3 comments

Comments

@euglv
Copy link

euglv commented Nov 22, 2024

I'm submitting a bug report

  • Library Version:
    1.4.1

Please tell us about your environment:

  • Operating System:
    Windows 11

  • Node Version:
    18.17.0

  • NPM Version:
    10.9.0
  • Aurelia CLI OR JSPM OR Webpack AND Version
    CLI 3.0.3 | webpack 5.95.0
  • Browser:
    Chrome 131

  • Language:
    ESNext

Current behavior:

@templateController

and

@inject(Element)

do not work together for custom attribute.
<!--anchor--> Coment element is passed to constructor instead of actual DOM element:

@templateController
@inject(BoundViewFactory, ViewSlot, Element)
export class RedBoxCustomAttribute {
  constructor(factory, slot, element) {
    this.factory = factory;
    this.slot = slot;
    this.element = element;
    console.log(element) // <!--anchor--> is logged to console
  }

https://gist.run/?id=6a2ce66ed37b552dcfd2614d76cbe8fa&sha=531b9a54616b6b872e3e7d0eb498d6e8af00487a

  • What is the motivation / use case for changing the behavior?
    There should be the way to access DOM element and extend child context using custom attribute.
@euglv
Copy link
Author

euglv commented Nov 22, 2024

https://gist.run/?id=6a2ce66ed37b552dcfd2614d76cbe8fa&sha=531b9a54616b6b872e3e7d0eb498d6e8af00487a

I have figured out that BoundViewFactory is responsible for creating DOM elements. In my example I can store element in the end of bind method:

  bind(bindingContext, overrideContext) {
    let newContext = { };
    overrideContext = createOverrideContext(newContext, overrideContext);
    if (!this.view) {
      this.view = this.factory.create();
      this.view.bind(newContext, overrideContext);
      this.slot.add(this.view);
    } else {
      this.view.bind(newContext, overrideContext);
    }
    this.element = this.view.firstChild;
  }

@euglv euglv closed this as completed Nov 22, 2024
@euglv euglv changed the title Injecting Element do not work with customController Injecting Element do not work with @templateController Nov 24, 2024
@euglv
Copy link
Author

euglv commented Nov 24, 2024

this.element = this.view.firstChild;

This is not correct way to store DOM element reference in template controller custom attribute.
If custom attribute is used together with repeat.for it can refer several DOM nodes. To cover all cases template controller should store array of DOM elements:

bind(bindingContext, overrideContext) {
  let newContext = { };
  let overrideContext = createOverrideContext(newContext, overrideContext);
  if (!this.view) {
    this.view = this.factory.create();
    this.view.bind(newContext, overrideContext);
    this.slot.add(this.view);
  } else {
    this.view.bind(newContext, overrideContext);
  }
  // Retrieve DOM elements
  const elements = [];
  let element = view.firstChild;
  if (element instanceof Element) {
    elements.push(element);
  }
  while (element && element != view.lastChild) {
    element = element.nextSibling;
    if (element && (element instanceof Element)) {
      elements.push(element);
    }
  }
  this.elements = elements;
}

@euglv
Copy link
Author

euglv commented Nov 28, 2024

The above code is not correct too. It do not listen for changes in child view.
Here is the correct code to get children of containerless template controller: aurelia/templating#717

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