angular 2 include html templates - html

in angular 2 I need to create a large html-template with redundant parts.
Therefore I want to create multiple html-templates and put them together by including them in the main html-file (like ng-include in angular1)
But how can I include sub-templates in the main-template?
example:
<!-- test.html -->
<div>
this is my Sub-Item
<!-- include sub1.html here-->
</div>
<div>
this is second Sub-Item
<!-- include sub2.html here-->
</div>
-
<!-- sub1.html -->
<div>
<button>I'am sub1</button>
</div>
-
<!-- sub2.html -->
<div>
<div>I'am sub2</div>
</div>

You can create components like sub1 sub2 etc. And On those child components add these html files as template .
On main html call the component selectors respectively. It will work

Let me tell you first of all that ng-include from Angular1.x is not supported by Angular2 so obviously $Compile is not present in Angular2. So, you can go ahead with CRF-ComponentFactoryResolver as shown here to add HTML dynamically with angular context.
DEMO--(CFR) : https://plnkr.co/edit/YdRlULhWQR3L3akAr2eb?p=preview
If your HTML piece has angular context, you should use CFR-ComponentFactoryResolver.
As in sub1.html, you have button, you might want to click it and fire its click event. This can be achieved with CFR as shown below,
You can do lot with CRF. This is probably the easiest example.
#Component({
selector: 'my-app',
template: `
<button (click)="addComponents()">Add HTML (dynamically using CRF)</button>
<h1>Angular2 AppComponent</h1>
<hr>
<div>
<h5>sub1.html goes here</h5>
<div class="container">
<template #subContainer1></template>
</div>
</div>
<hr>
<h5>sub2.html goes here</h5>
<div class="container">
<template #subContainer2></template>
</div>
`,
})
export class App {
name:string;
#ViewChild('subContainer1', {read: ViewContainerRef}) subContainer1: ViewContainerRef;
#ViewChild('subContainer2', {read: ViewContainerRef}) subContainer2: ViewContainerRef;
constructor(
private compFactoryResolver: ComponentFactoryResolver
) {
this.name = 'Angular2'
}
addComponents() {
let compFactory: ComponentFactory;
compFactory = this.compFactoryResolver.resolveComponentFactory(Part1Component);
this.subContainer1.createComponent(compFactory);
compFactory = this.compFactoryResolver.resolveComponentFactory(Part2Component);
this.subContainer2.createComponent(compFactory);
}
}
}

Related

Use component HTML in other component as part of the page

I have a component with some feature and its html say a.component.ts
class AComponent {
....
}
a.component.html
<div>
Bunch of HTML with many logic
</div>
Now I have extended above a component in b.component.ts
class BComponent extends AComponent {
Have some it's own code
}
b.component.html
<div>
// Include A HTML
</div>
<div>
B's html code goes here
</div>
I don't want to use the A component directly here like <a-component></a-component> because in this case A Component code will be called twice.
Any Idea how to how only the html of a component in other component as part of the page without calling the component.

How to use slots inside of template components in HTML

I'm trying to use slots inside of a Vue component to display different titles more easily. However, when I try to replace the slot with data, regardless of the relative positioning in the markup, the slot only uses it's fallback option.
It's my understanding that the template to be used goes first, with a label, then slots are put in and given a "name," with fallback text between the opening and closing slot tags, like so:
<template id="somename-template>
<slot name="attrname>Some Fallback</slot>
</template>
Then data is stored as such:
<somename>
<span slot="attrname">Real text</slot>
</somename>
I have tried repositioning the both above and below the script, and above and below the , however no combination provides the expected results.
My actual code:
<body>
<template id="comp-dem-template">
<header-component></header-component>
</template>
<script>
customElements.define('comp-dem',
class extends HTMLElement {
constructor() {
super();
const template = document.getElementById('comp-dem-template').content;
const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(template.cloneNode(true));
}
});
Vue.component('header-component', {
template: '<h1><slot name="pagetitle">Page Title Fallback</slot></h1>'
})
new Vue({ el: '#comp-dem-template' })
</script>
<comp-dem>
<span slot="pagetitle">
Images
</span>
</comp-dem>
</body>
The markup should look like:
<h1>Images</h1>
However, instead looks like:
<h1>Page Title Fallback</h1>
I can tell it's probably a super simple thing that I'm doing wrong (or it's the wrong tool for the job), but even looking at other working examples, I can't tell what that exactly is.
It's not quite clear to me what you're trying to accomplish. You're passing the <span slot="pagetitle">Images</span> to <comp-dem> but the <comp-dem> component doesn't have a slot - it's the <header-component> that has a slot. Why do you need to wrap a component in a component?
For the code to work, the slot needs to be passed like so:
<body>
<template id="comp-dem-template">
<header-component>
<span slot="pagetitle">
Images
</span>
</header-component>
</template>
<script>
Vue.component('header-component', {
template: '<h1><slot name="pagetitle">Page Title Fallback</slot></h1>'
})
new Vue({ el: '#comp-dem-template' })
</script>
</body>
Or, if you insist on using <comp-dem>, I think you might need to do the following:
<body>
<template id="comp-dem-template">
<header-component>
<span slot="pagetitle">
<slot name="pagetitle"><slot>
</span>
</header-component>
</template>
<script>
customElements.define('comp-dem',
class extends HTMLElement {
constructor() {
super();
const template = document.getElementById('comp-dem-template').content;
const shadowRoot = this.attachShadow({mode: 'open'}).appendChild(template.cloneNode(true));
}
});
Vue.component('header-component', {
template: '<h1><slot name="pagetitle">Page Title Fallback</slot></h1>'
})
new Vue({ el: '#comp-dem-template' })
</script>
<comp-dem>
<span slot="pagetitle">
Images
</span>
</comp-dem>
</body>

Angular 8 accordion with Dynamic data without using bootstrap/angular material

I am trying to implement accordion functionality without using bootstrap/angular material accordion. My data is coming dynamically from an api.
I tried doing below but that opens and closes all the panels together. I understand the reason behind it but I don't understand how to approach.
Component.ts
export class AccordionComponent implements OnInit {
isHidden = true;
mFaqs: IFaq[];
constructor(private faqService: FaqService) { }
ngOnInit() {
this.faqService.getFaqs()
.subscribe(faqData => this.mFaqs = faqData );
}
}
component.html
<div class="custom-header" hideToggle="true" (click)="isHidden = !isHidden" *ngFor="let faq of mFaqs?.faqs">
<section>
<section>
Q: {{ faq.question }}
</section>
<p [hidden]="isHidden">
{{ faq.answer }}
</p>
</section>
</div>
It should only close/open the clicked one.
You need to pass unique id for that.
Might be it'll help you.
Angular on click event for multiple items
please go through it.

Problem with Styling and Visibility while showing modal in Angular 4 Application --

Facing problem with opening and displaying a modal in my Angular4 .NET Application. I would click a link and consecutively a modal would show. In my case the date link for invoice number [pl see the image].
I followed the approach shown here -- http://jasonwatmore.com/post/2017/01/24/angular-2-custom-modal-window-dialog-box
Now what I have currently is, my opaque screen blocking the background but the modal is not displaying as I was hoping for. Like this
I don't know why the modal didn't appear. I am guessing z-index problem maybe? Cause I do not see any console errors. So probably not angular code related matter. Most likely CSS is what I feel. My main app screen is divided into 2 segments as you can see, col-sm-3 and col-sm-9 body content.
Basically this is what I wrote to test my code.
my main app window layout -
<div class='container-fluid'>
<div class='row'>
<div class='col-sm-3'>
<nav-menu></nav-menu>
</div>
<div class='col-sm-9 body-content'>
<alert-component></alert-component>
<router-outlet></router-outlet>
</div>
</div>
</div>
my modal related html --
<div class="col-md-4" style="border-radius:8px; background:linear-gradient(50deg, #e1ecfa, #f2fbde); text-align:right; margin-left:12px; padding:10px;">
<b style="color:darkblue">Invoices issued to this customer</b>
<ul style="list-style:none" *ngFor="let i of iObj">
<li (click)="openInvoiceModal('custom-modal-1')" class="glyphicon glyphicon-arrow-right">
<a>
<b>{{i.inv_id}}, on {{i.inv_date}}</b>
</a>
</li>
</ul>
</div>
*** my test modal ***
<modal id="custom-modal-1">
<div class="modal">
<div class="modal-body">
<h1>Invoice Modal!</h1>
<p>
Home page text: Hello There!
</p>
<button (click)="closeModal('custom-modal-1');">
Close
</button>
</div>
</div>
<div class="modal-background"></div>
</modal>
typescript with this page --
openInvoiceModal(id: string) {
this.modalService.open(id);
}
closeInvoiceModal(id: string) {
this.modalService.close(id);
}
All the other files and code are the same as has been written in that link/tutorial. I tried experimenting at one place with z-index also. But it didn't serve the purpose. So I am baffled.
A few alterations in the modalcomponent file also according to my layout css etc, so I am posting it here.
export class ModalComponent implements OnInit, OnDestroy {
#Input() id: string;
private element: JQuery;
constructor(private modalService: ModalService, private el: ElementRef) {
this.element = $(el.nativeElement);
}
ngOnInit(): void {
let modal = this;
// ensure id attribute exists
if (!this.id) {
console.error('modal must have an id');
return;
}
this.element.appendTo('.container-fluid');
this.element.on('click', function (e: any) {
var target = $(e.target);
if (!target.closest('.modal-body').length) {
modal.close();
}
});
this.modalService.add(this);
}
// remove self from modal service when directive is destroyed
ngOnDestroy(): void {
this.modalService.remove(this.id);
this.element.remove();
}
open(): void {
this.element.show();
$('.container-fluid').addClass('modal-open');
}
// close modal
close(): void {
this.element.hide();
$('.container-fluid').removeClass('modal-open');
}
}
I am not sure why the modal itself is not showing. Although the opaque background is being called means - I am going the right way. ALMOST!
What am I missing? Where is the glitch? Surely it has to be some small tricky part that I am failing to grab! Kindly guide me.
Let me know if you need more code stubs from me to understand my scenario. I will be happy to share.
In anticipation,

How to display dynamic HTML correctly?

I have an object called article that comes from the backend. It contains id, title and description. The description contains HTML data and I want to be parsed as HTML code by browser however, browser treats it as text. So, I am wondering why. And how to ask browser to parse it as HTML?
interface BodyComponentProps {
name: string;
article: article;
}
class BodyComponent extends React.Component<BodyComponentProps> {
public render() {
const art = this.props.article;
return (
/* <!-- Main container --> */
<nav className="level body-container">
{/* <!-- Left side --> */}
<div className="level-left">
<div className="level-item">
<nav className="panel content-block">
<p className="panel-heading">{art.title}</p>
<div className="panel-block">{art.description}</div>
</nav>
</div>
</div>
{/* <!-- Right side --> */}
<div className="level-right">
<div className="level-item sidebar-item">
<SidebarPanel title={this.props.name}/>
</div>
</div>
</nav>
);
}
}
const mapStateToProps = (state: NahjReduxState) => ({
article: state.content.article,
});
export default connect(mapStateToProps)(BodyComponent);
React treats it as text, not HTML, for security reasons. Allowing inserting HTML from the backend means you're opening your site up for cross-site scripting (XSS - https://en.wikipedia.org/wiki/Cross-site_scripting).
Cross-site scripting (XSS) means that malicious scripts can be injected into your website by other people.
However, if you truly want to do this, you can use the dangerouslySetInnerHtml prop. dangerouslySetInnerHtml requires you to pass an object with the key __html (notice the double underscore), and the value is the HTML you want to render.
Example:
<div dangerouslySetInnerHTML={{__html: 'First ยท Second'}} />
React dangerouslySetInnerHtml docs