Problems with slots in wrapped components
See original GitHub issueI have a simple Vue component with a default slot. I create an AngularJs wrapper using createVueComponent
and then use the wrapper in AngularJS app. A simplified version of my setup is shown below.
const customLink = Vue.component('CustomLink', {
template: '#custom-link',
})
angular.module('app', ['ngVue']).directive(
'ngCustomLink',
createVueComponent => createVueComponent(customLink),
);
angular.element(() => {
angular.bootstrap(document.getElementById('app'), ['app']);
});
<div id="app">
<p>
No children (no text): <ng-custom-link></ng-custom-link>
</p>
<p>
Expected to see the default text: <i>Default Text</i>
</p>
<hr>
<p>
Text child (fails): <ng-custom-link>Raw text</ng-custom-link>
</p>
<p>
Expected to see: <i>Raw text</i>
</p>
<hr>
<p>
Span child (ok): <ng-custom-link><span>span text</span></ng-custom-link>
</p>
<p>
Expected to see: <i>span text</i>
</p>
</div>
<template id="custom-link" type="x-template">
<a href="#">
<slot>Default Text</slot>
</a>
</template>
The setup is available at https://jsfiddle.net/nqr876os/5/
There are 3 problems:
- When the AngularJS wrapper has a single child that is a text Node, an exception is thrown and the component is not rendered at all.
- When the AngularJS wrapper has no children, the default slot of the original Vue component is not displayed.
- When the AngularJS wrapper has multiple children, only the first one is displayed.
- VueJS is v2.6.6
- Angular is 1.6.6
- ngVue is 1.6.0
Issue Analytics
- State:
- Created 5 years ago
- Reactions:3
- Comments:9 (6 by maintainers)
Top Results From Across the Web
Building Component Slots in React | Articles - Sandro Roth
Slots are an way to pass elements to a component and let them render ... It then wraps the header and footer in...
Read more >Vue - how to pass down slots inside wrapper component?
I ran into this issue when wanting to wrap the Kendo UI Grid component and exposing its cell template slots. – incutonez. Jul...
Read more >Using templates and slots - Web Components | MDN
This article explains how you can use the and elements to create a flexible ... The <template> wraps the named slots in a...
Read more >Shadow DOM slots, composition
What if the outer code wants to add/remove menu items dynamically? The browser monitors slots and updates the rendering if slotted elements are ......
Read more >A comprehensive guide to Svelte components with slots
In the code above, we created a Card component. The slot component allows us to pass child data and content to the Card...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
I feel sorry that we will not fix this bug and
<slot/>
has to be deprecated because your refactored code will get harder & harder to develop, test and debug.With
<slot/>
the vue components have to take care of the angular runtime and eventually those will be tightly coupled.If you have to preserve the angular code in the vue components perhaps you could use web components as a bridge between these two runtimes 😃
So found a quick solution to this, at least when it comes to passing plain text inside of the component references tags.
Wrap your plain text content in the template where you reference the component with
<span></span>
tags. This will prevent the error from coming up, and cleanly pass the content through into the slot.However, this still does not fix the issue where default content assigned into the slot does not appear, when not passed in from the template component reference.
Possible long term solution? After playing around with the jsfiddle created by korya above, I think a workable solution to this might be to first wrap whatever contents is found in
jqElement[0].innerHTML
with<span></span>
tags first, then run it through the compiler. The extraneous span tags can then be removed from the resulting HTML before it is injected into the DOM.Reason: This is caused by how AngularJS/jqLite processes bare strings without any wrapping tags around them.
It starts out with this line: https://github.com/ngVue/ngVue/blob/master/src/angular/ngVueLinker.js#L34, that attempts to have AngularJS $compile whatever the passed content is.
This in turn is sent by Angular to the JQLite constructor, which attempts to parse it (from the angular.js file):