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

@children Only Working in Chrome #655

Open
TonyLugg opened this issue Dec 20, 2018 · 27 comments
Open

@children Only Working in Chrome #655

TonyLugg opened this issue Dec 20, 2018 · 27 comments

Comments

@TonyLugg
Copy link

TonyLugg commented Dec 20, 2018

Using @children in a custom element is only working in Chrome. Adding @useShadowDOM to the custom element got it working in FireFox but it does not work in Edge. My elements have slots and two types of custom elements can be nested within each other forming a multi-level menu.

@fkleuver This is a carry over from our discussion in the vNext space.

@fkleuver
Copy link
Member

@TonyLugg Thanks. Can you please post your markup and the piece of your typescript code that declares and consumes the @children decorator?

@fkleuver
Copy link
Member

I did some digging and it seems the implementation differs based on whether you're having @useShadowDOM or not, but that implementation does not account for whether the browser actually supports shadowDOM or not (which Edge doesn't).

So for starters, you should probably either remove that @useShadowDOM decorator (apologies for the wrong advice there) or, if you do actually need to use shadow dom, polyfill it in Edge.

@fkleuver
Copy link
Member

@bigopon you probably want to know about this too. Previous discussion at aurelia/aurelia#331

@TonyLugg
Copy link
Author

TonyLugg commented Dec 20, 2018

<menu-list>
	<div>This is a menu</div>
	<menu-list-item>List item number 1</menu-list-item>
	<menu-list-item>List item number 2</menu-list-item>
	<menu-list-item>Sub menu 3
		<menu-list>
			<menu-list-item>Sub item number 1</menu-list-item>
			<menu-list-item>Sub item number 2</menu-list-item>
		</menu-list>
	</menu-list-item>
	<menu-list-item>List item number 4</menu-list-item>
</menu-list>
export class MenuListCustomElement {
	el: Element;
	@children('menu-list-item') items: any[];
	parentId: number;

	constructor(el: Element) {
		this.el = el;
		this.parentId = Math.floor((Math.random() * 1000000) + 1);
	}

	attached() {
		console.log('items', this.items);
		if (this.items) {
			for (let loItem of this.items) {
				console.log('loItem:', loItem);
				if (loItem.el && loItem.el.au && loItem.el.au.controller && loItem.el.au.controller.viewModel) {
					let vm = <MenuListItemCustomElement>loItem.el.au.controller.viewModel;
					console.log('loItem vm:', vm);
					console.log('uniqueId', vm.uniqueId);
					console.log('submenu', vm.subMenu);
				}
			}
		}
	}
}	

items is undefined when logged in Edge

@TonyLugg
Copy link
Author

In Chrome I actually don't need to reference el.au.controller.viewModel, as the vm's are right there in the array of children.

@StrahilKazlachev
Copy link
Contributor

  1. So the issue is with items that are initially present? Not ones added later on?
  2. Also the html markup is how you are using it?
    2.1 <menu-list> has a <slot>?

@TonyLugg
Copy link
Author

@StrahilKazlachev Correct. All items in View HMTL. Each custom element has a slot (menu-list and menu-list-item). menu-list can create multiple menu-list-item's, menu-list-item can contain visual content and a single menu-item (a sub menu).

@fkleuver
Copy link
Member

Yeah if you use slots then the view compiler enables ShadowDOM mode for the custom elements.
@StrahilKazlachev you are on point then about what you said on Discord.

@TonyLugg You could either try polyfilling ShadowDOM in Edge with shadydom, or you can use replaceable instead of slots to ensure ShadowDOM is not being used.

That said, this is still a valid issue as I believe we should be able to detect whether something is really shadowDOM or not, and if not, use the appropriate initialization logic.

@EisenbergEffect
Copy link
Contributor

For vCurrent, you can use slots without ShadowDOM. If you do, the framework attempts to emulate. If you specify @useShdadowDOM and your browser doesn't support it, it also tries to emulate it. But, perhaps specifying @useShdadowDOM when there's no native support causes the issue with @children. I'd either polyfill ShadowDOM or remove @useShadowDOM as quick fixes. Let me know if either of those solves the problem.

@TonyLugg
Copy link
Author

@EisenbergEffect I had originally not used @useShadowDOM and only Chrome was working for my use case. I added @useShadowDOM and FF worked but still Edge did not work.

@EisenbergEffect
Copy link
Contributor

Can you create a simple repro based on the Aurelia CLI and attach it here? I'd like to take a look myself. This seems pretty surprising to me so either there's something not quite right in your project or we've had a major regression at some point.

@TonyLugg
Copy link
Author

OK, I'm tied up for a few days but will get something for you soon.

@fkleuver
Copy link
Member

@EisenbergEffect See #655 (comment)
The fact that he's using slots causes the view compiler to turn on shadowDOM mode for the element.

This in turn causes the children observer to go into a different traversal mode which doesn't work. I'm fairly sure it has been like this for a long long time. I also recall issues with slots + @children in the past, that's in fact the reason why I stopped even trying to use them. I never laid this link before however.

@EisenbergEffect
Copy link
Contributor

Using slots in vCurrent should never force shadow dom to turn on. That's the whole reason for having slot emulation to begin with. If that is what is happening, then this is some sort of regression. It's definitely not always been that way.

@TonyLugg
Copy link
Author

TonyLugg commented Dec 21, 2018

I just created a little sample in Aurelia Typescript Sandbox and it works there in all browsers. My real test app is using CLI Webpack config. Also, the custom elements are global resources.

I'll create a new CLI project and see what happens.

@TonyLugg
Copy link
Author

I created a new CLI app with Webpack and TypeScript and used the same files as the sandbox linked above. Now I get the original results, i.e. it works in Chrome but not in FF or Edge.

@EisenbergEffect
Copy link
Contributor

Do you mind zipping that up and attaching it here?

@TonyLugg
Copy link
Author

menu-test4Rob.zip

Here is the test project, sans node modules.

@EisenbergEffect
Copy link
Contributor

Thanks! I'm on vacation and traveling a bit but I'll try to take a look over the next couple of days. I may have some more specific questions after I dig in more.

@EisenbergEffect EisenbergEffect self-assigned this Dec 21, 2018
@TonyLugg
Copy link
Author

OK, first, have your well deserved vacation, this can wait until you return. It is pretty simple. CLI new app, add the app.html. Add the two custom elements. Check the console in each browser. That's it for this crude sample.

@davismj
Copy link
Member

davismj commented Dec 22, 2018

@davismj
Copy link
Member

davismj commented Dec 22, 2018

Firefox

image

Chrome

image

Edge

image

@TonyLugg The outputs in the console look identical to me. Can you help me understand what is different in Edge or Firefox in your local build, please?

@TonyLugg
Copy link
Author

TonyLugg commented Dec 22, 2018

@davismj Correct. Per the sandbox sample I provided here it is working there too. However, it does not work with the CLI Webpack config that I attached for Rob above.

In FF and Edge, items is undefined in the log.

@TonyLugg
Copy link
Author

I finished the multi-level menu using querySelectorAll and referencing el.au.controller.viewModel instead of @children. I did not need to build a tree as each menu-list and menu-list-item referenced their children and parent.

@bigopon
Copy link
Member

bigopon commented Feb 4, 2019

@TonyLugg Did you get your issue resolved?

@TonyLugg
Copy link
Author

TonyLugg commented Feb 4, 2019

@bigopon The issue with @child and @children was not resolved to my knowledge. I worked around it as mentioned above based on comments provided by @davismj.

@bigopon
Copy link
Member

bigopon commented May 17, 2020

@TonyLugg I'm finally able to have a look at the cause of this. In short, this is a timing issue. It can be explained like this:

  • With native shadow on: every element is kept as is, what you see is what you get initially. And with this, the child observer is able to initialize the value of @child/@children during bind lifecycle, hence you get what you want in attached.
  • With native shadow off: content elements of a custom element will be removed during compilation, and added later during bind phase. This is to do the projection for <slot/> emulation, and it will trigger mutation observer and thus give you the value you want. The downside of this, is every mutation callback will be a tick later. And in your example, it's 3 layers of tick, while attached is only 1 tick after bind, hence undefined in attached as you saw. This, unfortunately is the only reliable way to have slot emulation work, so change handler should be encouraged in emulation scenario.

@EisenbergEffect EisenbergEffect removed their assignment Dec 13, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants