I have a component which uses named slots from <another-component>. I was trying to get the <span> by calling this.shadowRoot.getElementById('title') in <another-component>, it always returns null:
render() {
return html`
<another-component>
<h2 slot="header">
<span id="title"></span>
</h2>
<div slot="footer">
${this.renderFooter()}
</div>
</another-component>
`;
}
Any ideas?
After some digging, i found this is by design. Please correct me if i'm wrong. Basically, you can only access a DOM element under a shadow root where it's defined no matter if it's in a <slot> or not.
For example, let's say in your main component, you have a component A with an element with an ID:
// main component's render
<a>
<p id="title"></p>
</a>
Component A uses component B, and maps its slot content to another slot in component B:
// component A's render
<b>
<p slot="header">blabla</p>
<slot slot="content"></slot>
</b>
Neither A nor B can access the element via shadowRoot.getElementById. Only the main component can get the element by ID.
Related
I do not want to render a new component or go to a new route, this is not my intention. I cannot use a single variable with an *ngIf to handle rendering the component as I cannot predict the amount of variables I will need to render.
Here is the situation.
<div ngFor="let stuff of lotsOfStuff">
<div (click)="generateAnotherComponent()">
<span>some basic info</span>
<my-child-component></my-child-component> //component to render on click
</div>
<div (click)="generateAnotherComponent()">
<span>some basic info</span>
<my-child-component></my-child-component> //component to render on click
</div>
</div>
You can generate the component dynamically.
There are various ways to achieve this, but one would be to use a template variable placed on an element, for example
<div #ChildInsertionPoint></div>
And then targeting this "insertion point" as where you'll place the newly generated components by using ViewContainerRef:
#ViewChild('ChildInsertionPoint', { read: ViewContainerRef })
childInsertionPoint: ViewContainerRef;
generateAnotherComponent() {
this.childInsertionPoint.createComponent(ChildComponent);
}
Dynamic component generation became a lot easier with Angular 13 (that's what I've assumed you're using). But if not
Finally, I'm assuming that you will bind your click event to a button instead of the div element itself.
Here's a small example on Stackblitz
I have an external div that I need to render inside my Vue app. I'm trying to use a slot, like but that's a no go as nothing renders.
Any ideas?
Goal is to have HTML like this (Vue mounts on #app):
<div id="app" data-slot-header="#header"></div>
<div id="header">
<h1>Title here</h1>
</div>
Then the Vue component
<template>
<div>
<slot name="header"></slot>
</div>
</template>
You can use a dynamic <component> and refer to your #header element as a template reference.
For example
new Vue({
data: () => ({
headerComponent: {
template: '#header' // refer to template element by selector
}
}),
}).$mount('#app')
#app:before,#header:before{position:absolute;top:0;right:0;color:rgba(1,1,1,.5);font-size:.8rem}#app{border:1px solid #666;position:relative}#app:before{content:'Vue app'}#header{position:relative;opacity:.5}#header:before{content:'Original header'}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.min.js"></script>
<div id="app">
<p>Dynamic component rendered here 👇</p>
<component :is="headerComponent"></component>
</div>
<div id="header">
<h1>Title here</h1>
</div>
Slots are mainly used with reusable Vue components so that the parent component can render custom stuff inside designated sections of the child. The root component does not have a parent, so it doesn't make sense to use slots for this.
Why can't you just hard-code the div in the template? Or do you need it to be dynamic; will you be swapping out the header contents in some situations? Please provide more information about what your use-case is, otherwise my answer is "just hard-code it".
Take a look at portal-vue. It allows child components to render templates anywhere in the DOM. This might work for your situation.
talents. I want to create beautiful button for vue. But I have a problem. I want to pass class attribute to child from parent component easily.
Parent component is like this:
<!-- parent component -->
<template>
<custom-element class="wanted-class">
<span slot="custom-body">
Some Effects or text
</span>
</custom-element>
</template>
and "custom-element" component is
<template>
<div id="custom-element">
Some elements or text
<slot name="custom-body">
Some default text
</slot>
</div>
</template>
<script>
export defatult{ ...
I really want the root element in child ( $("#custom-element") for jQuery expression) to have "wanted-class" from parent. Is it possible? or it's too easy?
I have a component called tab which has <ng-content select="[tabItem]"></ng-content>
Sometimes tabItem is inside other child components. My problem is Angular selects the content from direct children, not inner children (app-my-tab), is there any way to do it?
app.component.html
<app-tabs>
<div tabItem>
Tab 1
</div>
<div tabItem>
Tab 2
</div>
<app-my-tab></app-my-tab>
</app-tabs>
my-tab.component.html
<div tabItem>
My Tab
</div>
<div>
Other content
</div>
See this stackblitz
There is no solution for deep selection.
I thing it is logical, because:
understand and real code easily
easy to debug.
If you want really do that use *ngIf in app-my-tab.
To use *ngIF:
All element in app-tabs must have tabItem attribute
send your condition to show/hide some other element in to app-my-tab component. and app-my-tab receive it as #Input() property
in app-my-tab html use *ngIf to show or hide some element
Example: https://stackblitz.com/edit/deep-ng-content-2gyttv?file=src/app/app.component.html
Let's say I'm developing an enhanced popper.js for Vue and I'm about to give it some additional functionality. This is how the very (child) component looks like:
<popper>
<div :is="tag" class="popper">
{{ content }}
</div>
<button class="btn btn-primary" slot="reference">
Reference Element
</button>
</popper>
As you can see, for it to work it requires defining reference element right beneath the ".popper" div with a slot="reference" attribute.
Question:
How to turn my enhanced-popper component into a re-usable entity, aka be able to pass slotted data indirectly - from
<enhanced-popper> //referenced element// </enhanced-popper> so that it has the slot="reference" attribute inside the child (popper.js-based) component?
What did not work:
Employing slots and having the attribute in a component passed in by the parent component does not yield desired results, as it does not get rendered at all.
<popper>
<div :is="tag" class="popper">
{{ content }}
</div>
<slot></slot>
</popper>
To ensure having the attribute out there I also tried to replace said button in the child component with a named slot inside a slot and go like this in my enhanced-popper:
<slot name="reference">
<slot></slot>
</slot>
That way the first slotted component has the attribute - and it almost works, but since there are two "slot-layers" (no idea how to call it), the referenced component is not the first one as a child, and popper gets mis-positioned.
Cheers,
Paco