I'm trying to remove the called component tag from HTML to prevent some broken CSS from external libraries and just show the inner content.
something.component.html
<div>
Hello World
</div>
another.component.html
<div>
<app-something [config]="somethingConfig"></app-something>
</div>
Then outputs:
<div>
<app-something>
<div>
Hello World
</div>
</app-something>
</div>
And I want:
<div>
<div>
Hello World
</div>
</div>
This is not possible due to the nature of web components which Stencil outputs.
What you could do instead: use the CSS rule display: contents on your component which prevents it from generating a box in the layout (see https://caniuse.com/css-display-contents, still somewhat experimental).
There are also functional components in Stencil (https://stenciljs.com/docs/functional-components) which don't generate a parent element, but those are only available within JSX, so you'll always need at least one parent Stencil component (so that you can render some JSX).
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 need to be able to wrap custom HTML around my Vue template content. As you can see below, it's not simply inserting html content using <div v-html="HtmlWrapperTopHalf"> because that will automatically close any unclosed tags. The tags will always be closed in the bottom half of the dynamic HTML. Basically, I'm looking to insert the Vue template code into my dynamic template HTML.
I also can't just assume what's in the dynamic HTML and build that inside the Vue template. This HTML comes from a RichText editor that my customers create on their own. They just insert a placeholder {{MAIN_CONTENT}} in the middle of their dynamic template and that's where the Vue Template functionality should appear.
Page.vue
<template>
<div>
//Top half of dynamic XHTML wrapper goes here
<p>Inner Content Here</p>
<ComponentA />
<ComponentB />
<!-- etc. --->
<p>More Inner Content</p>
//Bottom half of dynamic XHTML wrapper goes here
</div>
</template>
<script>
axios.get("getHtmlContent").then((result) =>{
console.log("top", result.data.HtmlWrapperTopHalf)
console.log("bottom", result.data.HtmlWrapperBottomHalf)
});
</script>
console.log
top: <div class="my-dynamic-class" id="my-unique-id"><h1>DYNAMIC TITLE</h1>
bottom: <div id="my-dynamic-footer">custom footer text</div></div>
HTML Output:
<div>
<div class="my-dynamic-class" id="my-unique-id"><h1>DYNAMIC TITLE</h1>
<p>Inner Content Here<p>
<div>Hello from ComponentA!!</div>
<div>Hello from ComponentB!!</div>
<!-- etc. --->
<p>More Inner Content<p>
<div id="my-dynamic-footer">custom footer text</div></div>
</div>
Hopefully this diagram of the concept will help:
Given that other components can be a part of this split up html content, using the render syntax to generate a slot within the content seems to be the only alternative.
render(createElement) {
return createElement(
'div', { 'class': 'hello'},
this.$slots.default
)
},
Have your axios component be built out within the render (see docs), and then use this as a slot to fill in within future components.
E.g. <ClientHtmlInject> <Comp1/><Comp2/> </ClientHtmlInjection>
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.
I'm writing web components using VueJS and vue-custom-element package. The web component that I'm creating is a layout components containing multiple modules such as chat, userList and so on. I need to add the ability to add/remove elements from the layout at runtime.
How can it be possible?
<my-layout></my-layout>
This is a simple layout. How can I make these buttons work?
This is the current layout template:
<template>
<div>
<button>Add new chat module</button>
<button>Add new users module</button>
<div id="layout" class="row">
<div class="col-sm">
<my-chat></my-chat>
</div>
<div class="col-sm">
<my-users></my-users>
</div>
</div>
<block :menu="testMenu">Custom block</block>
</div>
</template>
These are possible solutions :
Calling a method inside the web component. (It's seem that it's not possible!)
document.getElementById("layout").addModule('chat')
Sending a configuration JSON as attribute containing the list of requested modules and their
count.
<my-layout conf='{"modules":{"chat":{"count":5}}"}'></my-layout>
Add a separate count attribute for each module.
<my-layout chat-count="5" users-count="2"></my-layout>
I was learning the ng-content. Why need to use it when we can easily write like this
with ng-content
menu.component.html
<div>
<app-message> <h1>Laptop</h1></app-message>
</div>
message.component.html
<div>
<ng-content></ng-content>
<p>something text to be display</p>
<button > Submit</button>
</div>
without ng-content
menu.component.html
<div>
<h1>Laptop</h1>
<app-message> </app-message>
</div>
message.component.html
<div>
<p>something text to be display</p>
<button > Submit</button>
</div>
Using <ng-content> allows you to create flexible reusable components.
For example, a custom app-modal component:
<div class="modal">
<div class="modal-title">
{{title}}
</div>
<div class="modal-body">
<ng-content></ng-content>
</div>
</div>
This is very powerful, and only the start of what you can achieve with <ng-content>
A core prinpiple of software engineering is code reuse (DRY). With this we can bundle all of the logic relating to a component into one component, and inject the content into it.
This is like asking the question
Why not just declare your CSS styles inline instead of in CSS classes?
It is possible, but unmaintainable, and we have evolved beyond that.
Your example is fairly trivial, but it is still useful if you wanted to change style or behaviour based on some injected logic.
There exist some situations when is necessary, maybe no in simple cases but when the app grows up and you have to insert a custom component inside another is very usefully
As you can see from your own example, without using ng-content, the parent component suddenly is partially responsible for the child's layout. It'll get messy real quick, the quicker the more complex the layout gets.
It's useful for displaying components inside of other components, so the components can be reusable. For example, if you want to display some text on a few pages, you call the component with the text inside of the other components that you want the text to be displayed on. It could also be useful for showing different information but styled in the same format. E.g.
if your ng-content already has the information this is an example of how it would be used:
menu.component.html
<ng-content></ng-content>
message.component.html
<ng-content></ng-content>
This is good because you can copy and paste the exact component into another one without having to rewrite the code
If your ng-content is looking for a data source for information to pass into it
<ng-content [data]='data'></ng-content>
This is good because you can recreate the component inside of another component but with different data inside of it.
If you've ever used react, you pass data into it in a similar way here as you would with react props, but instead of props in angular, it will be an #input field. Here is some example code
test.component.html
<ng-content [data]='THIS IS THE DATA'></ng-content>
This is the actual component, as you can see, it is looking for a data source
ng-content.component.html
<p>The data we are looking for is {{data}} </p>
ng-content.component.ts - this says that when the component is called, it is looking for an input called 'data' and the type has to be a string
#Input() data: string;
We would then see the test.component.html displayed like this:
The data we are looking for is THIS IS THE DATA