I want for my Pages induvidually to inject different components from other Pages/Components into the header. For example I want to inject an Input search Field from my content-component into my header Component. I tried with ng-Content, but this only duplicates my header in my HTML. The problem is my header is not in each Component individually, its in my app.component.
My Header Component:
<div class="header__sub">
<div class="header__title header__title--sub">
<h2 class="title title--medium">{{ subtitle }}</h2>
</div>
<div class="header__search">
<!-- Here should be my Input field -->
<ng-content></ng-content>
</div>
Component from I want to inject the input field:
<app-header>
<mat-form-field>
<input matInput (keyup)="applyFilter($event.target.value)" placeholder="Search" />
</mat-form-field>
</app-header>
....
App-Component.html:
<mat-drawer-content>
// The header
<app-header-sub>
</app-header-sub>
<div class="content__inner">
// My Content
<router-outlet></router-outlet>
</div>
</mat-drawer-content>
How can I inject from each Component individually a different tag into the header (with functionalities)?
You can use it like that:
Child component
<div class="header">
<ng-content select="[name]"></ng-content>
<div>
Parent component
<app-header>
<div name>Hello World</div>
</app-header>
Demo for your reference: https://stackblitz.com/edit/ng-content-select-attribute
Or look here: Multiple ng-content
Related
The following code is a component that i need to inject in other components:
<div class="row">
<div class="col-12 [...]" *ngFor="let course of courses">
<div class="card">
[...]
</div>
</div>
</div>
The problem is that in one of the components it is injected in, I need to apply a | slice:0:4 in the ngFor to display less data. For this reason, I modified the child component and made it so the data from the parent components is sent to the child component. So I removed the .row and .col-12 divs and put it into the parent components, this way I can use the slice only in the parent component I need to.
<div class="row">
<div class="col-12 [...]" *ngFor="let course of courses | slice:0:4">
<app-child-component [course]="course"></app-child-component>
</div>
</div>
Child component now is like this:
<div class="card">
[...]
</div>
The problem now is that I need to apply CSS classes to the child component's .row that must be visible everywhere but this way I have to modify every single parent component's .row, so more useless code. I also assume this way I'm not using Angular's components concept the way it is meant to.
Is there a way to use | slice and kind of "send it" from a single parent component to the child component like i'm doing now with [corso]="corso" in <app-component [corso]="corso"></app-component>?
Hoping I explained this well. Thank you.
//Child component ts
#Input() sliceStart = 0; //default to `0` if not passed
#Input() sliceEnd = 4; //default to `4` if not passed
courses = ['HTML', 'CSS', 'Javascript', 'Angular'];
<!-- Child component html -->
<div *ngFor="let course of courses | slice: sliceStart:sliceEnd">
{{course}}
</div>
<!-- Parent component html -->
<app-child-component [sliceEnd]="2"></app-child-component>
Stacblitz example
I am just passing a long-text as a prop into a child component in Vue project.
child component:
<template>
<div class="story">
<p class="story__content">{{ content }}</p>
</div>
</template>
parent component:
<story
content="Before your trip, I recommend researching the destination to find the most interesting photo opportunities.\n I always research the location I’m traveling to.\n I do this extensively and obsessively!"
/>
I tried css like this in tag of the child component.
.story__content {
white-space: pre-wrap;
}
But it shows no line break but shows text as is like this:
Does anybody have a similar experience to this?
Than you in advance!
Update your code adding v-html directive to your p tag, that way the content prop is used as html code:
<template>
<div class="story">
<p class="story__content" v-html="content" />
</div>
</template>
You can read more about it here
So I have the following example:
Here is my child component. Every other ones of the following components is based upon this.
<template>
<div class="content-box">
<div class="boxtitlecontainer titleColor">
<slot name="title">Title</slot>
</div>
<div class="insidebox boxColor">
<slot></slot>
</div>
</div>
</template>
This is one of the children.
<template>
<div class="example">
<box>
<div slot="title"><slot name="title">Title</slot></div>
<slot></slot>
</box>
</div>
</template>
This component is directly used in my App.vue. To use <slot>s, the only way i found is this one above.
My question is: Is there a more elegant way of doing this and to not stack up div-Boxes unnecessary? I mean, I can do it with no named slots. I guess that the <slot> can be showed recursivly like content -> slot(1st children) -> slot(2nd children) but i have no idea about how to do it with named slots.
Thanks in advance for any help.
instead of depending on slot for passing your content, why not use props instead?
<template>
<div class="example">
<box>
<div v-text="title">Title</div>
<slot></slot>
</box>
</div>
</template>
<script>
export default {
props: ['title']
}
</script>
I am trying to compose a component inside another like this:
<prompt :users="users">
...
<dataset v-for="ds in users" :user="user"></dataset>
...
</prompt>
But apparently I'm not registering it properly:
[Vue warn]: Unknown custom element: <dataset> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
(found in root instance)
Here's how I'm trying to register it:
app.js
Vue.component('prompt', {
props: ['userdata', 'users'],
template: '#prompt-template',
components: {
'dataset': {
props: ['userdataset', 'user'],
template: '#dataset-template',
}
}
});
Finally, the templates:
<template id="dataset-template">
<li>{{ user}}</li>
</template>
<template id="prompt-template">
<transition name="modal">
<div class="modal-mask">
<div class="modal-wrapper">
<div class="modal-container">
<div class="modal-header">
<slot name="header">
default header
</slot>
</div>
<div class="modal-body">
<slot name="body">
</slot>
</div>
<div class="modal-footer">
<slot name="footer">
default footer
<button class="modal-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</div>
</transition>
</template>
Are there any steps I'm missing? I can't figure out how the component isn't being registered.
The problem is that you use the dataset component as a slot within the prompt component. While the Vue vm tries to figure out the component tree it will recognize the dataset component which it does not know. Subcomponents are used in the component template but not within slots. You have to register the dataset component within the Vue vm like you did for the prompt component. Try this
Vue.component('promp', { ... })
Vue.component('dataset', { ... })
It also make sense to register the components on the same level since the templates of the components are also registered on the same level (next to each other).
Compare it to the example you mentioned in another answers comment: Here the subcomponent axis-label is only used within the template of the parent polygraph component. This is valid since now the component is in contract to figure out it sub components not the vue-vm.
In other words:
It should be possible to pass components into the slot of any component A which are not subcomponents of A. Therefore all components passed to slots of a component should be available to the vue vm.
Thumb rule could be
if a component does not appear within another components template, it is not a subcomponent.
I seriously don't know, why the fragments is the problem.
<template>
<div id="page">
</div>
<div class="some">
</div>
</template>
[Vue warn]: Attribute "id" is ignored on component "div"
You need to wrap the contents of your template in another div. When it comes to render it, it needs the single root element to replace
<template>
<div>
<div id="page">
</div>
<div class="some">
</div>
</div>
</template>
Vue v3 now supports multi-root templates. Your code should work out-of-the-box.
https://v3-migration.vuejs.org/new/fragments.html