Put projected Angular content into a component through routing - javascript

In a context of a micro-front-end application I have a projected content in the app.module.ts that I want to put in a component that was instantiated via the router.
Here is a solution that does not work:
I referenced the projected content as follow
<ng-template #projected>
<ng-content></ng-content>
</ng-template>
<router-outlet></router-outlet>
I set the reference in a service
#ViewChild('projected', { static: true }) templateRef: TemplateRef<unknown>;
// ...
this.service.projectedRef = templateRef;
use it in the component that was created by the router
<ng-container [ngTemplateOutlet]="service.projectedRef"></ng-container>
Any idea why doesn't that work and how I can solve this problem?
Note: when I use <ng-container [ngTemplateOutlet]="service.projectedRef"></ng-container> inside the app.component.html, it works fine, but not inside the routed component.

Related

Include component from parent app in component contained in node_modules directory

I am working on Vue app that incorporates Vue Bootstrap Calendar, and I would like to be able to override the content of the day cell (handled by the Day.vue component) to add my own custom content inside. My thought was initially to modify the Day component to include <slot></slot> tags and pass in the custom content that way.
The problem has to do with accessing the Day component. To include the calendar in your app, you include the Calendar.vue component, which includes Week.vue, which in turn includes Day.vue. As I understand slots, I have to have the child component (Day.vue in this case) included in the component where I'm passing the data, which means it would need to be included in my own component.
If this is not possible, my other thought is to perhaps modify the library by adding another configuration prop (something like dayCustomContent) to the Calendar.vue that indicates that the Day cell content is custom content, pass that in to Calendar.vue, and then down to Day.vue, and then in the Day.vue template, have a v-if conditional based on this prop that either displays the custom content or the default cell content, something like:
<template>
<div class="day-cell" v-if="dayCustomContent">
...my custom content here...
</div>
<div class="day-cell" v-else>
...default events from my.events goes here...
</div>
</template>
I would probably then need to define a custom component to render whatever custom content I want to display, and somehow include that component within Day.vue.
So to sum up, my questions are these:
1) Is there a way to do what I need with slots?
2) For my second option, am I going down the right path? I'm open to suggestions.
UPDATE: I was able to get this done by adding a boolean customDayContent prop in Calendar.vue like so and passing it down to Week.vue and then to Day.vue:
<template>
...
<div class="dates" ref="dates">
<Week
v-for="(week, index) in Weeks"
:firstDay="firstDay"
:key="week + index"
:week="week"
:canAddEvent="canAddEvent"
:canDeleteEvent="canDeleteEvent"
:customDayContent="customDayContent"
:displayWeekNumber="displayWeekNumber"
#eventAdded="eventAdded"
#eventDeleted="eventDeleted"
></Week>
</div>
...
</template>
<script>
export default {
...
props: {
...
customDayContent: {
type: Boolean,
default: false
}
},
}
</script>
and then in Day.vue, do like I had suggested with v-if:
<template>
<div class="day-cell" v-if="customDayContent">
<custom-day></custom-day>
</div>
<div
class="day-cell"
:class="{'today' : day.isToday, 'current-month' : day.isCurrentMonth, 'weekend': day.isWeekEnd, 'selected-day':isDaySelected}"
#click="showDayOptions"
v-else
>
... existing code goes here...
</div>
</template>
The last part is referencing the CustomDay.vue component referenced in my v-if block. I want the user to be able to define the content of their own custom CustomDay.vue template in their own parent app. However, I'm having trouble trying to figure out how to do that. Following the pattern of including components already in this component, I added this in the components section of Day.vue:
CustomDay: require("../../../../src/Components/CustomDay.vue").default
? require("../../../../src/Components/CustomDay.vue").default
: require("../../../../src/Components/CustomDay.vue")
However, no matter what I try along these lines, I get an error that the relative module was not found. On top of that, I need to add it to the componentsarray only if customDayContent is true. What is the best way to do that? In a watcher or computer property, perhaps? Or another way?

How is templates working in primeng grid Angular 6

I am using primeng TurboTable where for templates a pTemplate directive is added. And then accordingly DOM gets rendered I am trying to implement a very same approach in my project to create a reusable(DUMB) component. Tried searching for a solution but couldn't find a proper solution. Thought about using ng-container but when passing ng-template from Smart component to child component nothing is happening. PFB a sample of the solution I tried
Smart Component Template
<dumb-component>
<ng-template #content> Content is placed here .... </ng-template>
</dumb-component>
Dumb Component Template
<ng-container *ngTemplateOutlet="content">
</ng-container>
Link to primeng documentation : primeng docs
Since your component Dumb Component receives a template. It needs to access the template with #ContentChild
Dump Component
<ng-container *ngTemplateOutlet="content">
</ng-container>
#ContentChild(TemplateRef) content: TemplateRef<any>;
Example:https://stackblitz.com/edit/angular-ephusu

How to load conditionally templateUrl html file in Angular 5 component

There is one scenario in my project,
Consider, I have one testDynamic component
#Component({
templateUrl: "./test-dynamic.html", // Need to override this file
styleUrls: ['./test-dynamic.css']
})
export class testDynamic {
constructor() { }
}
here need to check if an override1.html file is exists in override folder then load this file as templateUrl otherwise load the component default test-dynamic.html.
Any idea how to achieve this.?
refer the following image for clearly understanding
refer the following link, this is a good example of dynamic templateUrl
Angular 2/4 component with dynamic template or templateUrl
You can't add more than one HTML file.
What you can do is, use *ngIf or *ngSwitchCase to show only parts of the template if that is your intention. Then you have only one template html file.
Then html of your template will be something like this:
<div *ngIf="YOUR_CONDITION">View 01</div>
<div *ngIf="YOUR_CONDITION">View 02</div>

Pass ng-template into component

I am facing the problem, that I need to pass multiple ng-template into another component as a template, example:
<app-datatable>
<ng-template tdDataTableTemplate="description" let-value="value" let-row="row" let-column="column">
<p matTooltip="{{ row[column ]}}">{{ row[column] }}</p>
</ng-template>
<ng-template tdDataTableTemplate="vendorName" let-value="value">
<p matTooltip="{{ value }}">{{ value }}</p>
</ng-template>
</app-datatable>
app-datatable is my component and I need to pass these templates to it as a template.
td-data-table is Teradata covalent DataTable component. It has functionality, that I can template each column with ng-template. But I want to pass ng-template through my component into td-data-table - hope it makes sence
Solution:
I didn't manage to find Covalent way solution. But I've managed to rewrite Teradata grid to custom grid, which allows me more control over it. Here is Stackblitz: Demo
I encountered the same problem and managed to fix it with the following:
In datatable.component.ts:
#Component({
selector: 'app-data-table',
templateUrl: './data-table.component.html',
styleUrls: ['./data-table.component.scss']
})
export class DataTableComponent implements OnChanges, AfterContentInit {
ngAfterContentInit(): void {
for (let template of this.templates.toArray()) {
if (!template.tdDataTableTemplate) {
continue
}
this.tdDataTable._templateMap.set(template.tdDataTableTemplate, template.templateRef)
}
}
#ViewChild(TdDataTableComponent) tdDataTable;
#ContentChildren(TdDataTableTemplateDirective) templates;
}
This mimics how TdDataTableCompponent handles the templates under the hood.
Also, for completeness, I spoke to the OP on the covalent gitter and they said that they solved it by rewriting the data table from the individual covalent components. They shared a stackblitz here.

Vuejs template inheritance

How can I use template inheritance (Like what jade has, extends file.jade and then the blocks with the same name would be overwritten)?
I know that I can do everything with composition, but for components like footer and header which appear on every single page except one or two (e.g.login page) I must write them on every single component. In my app I have a two level navigation and it seems painful to repeat them on every one of those child components :(
I know that I can use jade and then inherit a jade file within my components, but it seems wrong because I would have some jade and some Vue files, is there any other way to do this?
// Component.vue
<template lang="jade">
extends ./StandardLayout
block content
router-view
</template>
// StandardLayout.Vue
<template lang="jade">
div
navbar
div.container
div.spacer
div.row
block content
<template>
What I've settled for, is a layouts folder filled with jade layouts and I use them to extend my components. I used vue-cli with webpack template.
In the most general case if you have to repeat the same HTML over and over, one option you could use is <partial>s.
<partial name="header"></partial>
<div>My content content</div>
<partial name="footer"></partial>
Where you declare partials as
Vue.partial('header', '<h3>This is the title: {{title}}</h3>')
Vue.partial('footer', '<footer>Mini footer</footer>')
However if you are building a Single Page Application the strategy you could follow is to simply have a header and a footer around your <router-view>, here is a jsfiddle that demonstrates how to do.
https://jsfiddle.net/gurghet/vdqutw2y/
<header><h1>
My title: {{title}}
</h1></header>
<p>
<a v-link="{ path: '/foo' }">Go to Foo</a>
<a v-link="{ path: '/bar' }">Go to Bar</a>
</p>
<router-view></router-view>
<footer>Such footer, many links, wow!</footer>
If you know Chinses, please look it
// Base Component
<template>
<div class="base-thing special-class">
<Button />
</div>
</template>
<script>
import Button from './ButtonClick'
export default {
components: { Button }
}
</script>
// Inheriting Component
<script>
import BaseComponent from './BaseComponent'
import Button from './OtherButton'
export default {
extends: BaseComponent
components: {
Button
}
}
</script>
The Button of Child Component will be replaced OtherButton. We can do something in the OtherButton

Categories

Resources