I'm trying to create dynamic modals in Angular 2 using the ng2-bs3-modals. I would like to fill in the modal html body text dynamically based on the parameter passed to the selector used in the main component's view. When I use this code however it seems to treat my entire function as text and so my modal displays the code of my 'function determineModalContent' rather than the intended behavior which is to display the contents of the file.
I also know that my code won't return the contents of the file, just the string but I haven't yet figured out how in Angular2/TypeScript to read in the file contents.
import { Component, Input } from 'angular2/core'
@Component({
selector: 'static-modal',
template: '{{modalBody}}'
})
export class StaticModalComponent {
@Input() modalID;
template = 'app/shared/modals/static-message-1.html'
modalBody = function determineModalContent(modalID){
if(modalID == "1")
return 'app/shared/modals/static-message-1.html';
else if(modalID == "2")
return 'app/shared/modals/static-message-2.html';
else
return 'app/shared/modals/static-message-default.html';
}
}
What you need here is something like ng-include I suppose. And as you can see in this issue on the Angular repo, most probably we won't get that directive. There has been a long discussion whether we need this directive or not, and if not provided how we can implement it by our self.
I tried to make a simple example of how it can be implemented.
@Component({
selector: 'my-ng-include',
template: '<div #myNgIncludeContent></div>'
})
export class MyNgInclude implements OnInit {
@Input('src')
private templateUrl: string;
@ViewChild('myNgIncludeContent', { read: ViewContainerRef })
protected contentTarget: ViewContainerRef;
constructor(private componentResolver: ComponentResolver) {}
ngOnInit() {
var dynamicComponent = this.createContentComponent(this.templateUrl);
this.componentResolver.resolveComponent(dynamicComponent)
.then((factory: any) => this.contentTarget.createComponent(factory));
}
createContentComponent(templateUrl) {
@Component({
selector: 'my-ng-include-content',
templateUrl: templateUrl,
directives: FORM_DIRECTIVES,
})
class MyNgIncludeContent {}
return MyNgIncludeContent ;
}
}
For a demo check this Plunker.
It may be maligned as "verboten" for a number of reasons that I understand, including the underscore you will see, but this works. Fact is I have a need to do this very simply and I don't want to (nor should I have to) write a lot of code to do it. I can scrub the HTML etc. I get if this is more helpful than an answer but some may find it useful.
In the component API (ES6 style), declare a queries entry (or otherwise create your ViewChild using TS), this should map to an element with a template reference variable and so on. Note that using the queries part of the component API as I show here works fine in TS:
// Assumes you have <div #targetdiv></div> in your component template
queries: {
targetDivRef : new ViewChild ( 'targetdiv' )
}
Then in some click handler, onInit or whatever (keeping in mind not to try this too early in the comp lifecycle) get the page you want async, and just dump the contents into the div.
let elem = this.targetDivRef.nativeElement;
let svc = this.http.get ( './thepage.html' )
.map ( response => { return response [ '_body' ] } );
svc.subscribe (
( x ) => { elem.innerHTML = x },
( err ) => console.log ( err ),
( ) => console.log ( 'Complete' )
)
Again, almost surely not "recommended". But it's simple and it works. You actually don't even need the subscribe, you can just set the val in the map func, this is just more complete etc.
When we get an option similar to ng-include (which IMHO is a glaring ommission), or an otherwise three-line option to do this, I'll make the switch. Handle request errors etc. as you see fit.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With