In the following example, https://stackblitz.com/edit/angular-1acvol
I have creating multiple views using a TemplateRef
and am attaching them to the same ViewContainer
. But I am unable to figure out how to delete a specific View
from the ViewContainer
.
I know there are methods in ViewContainerRef
like remove
, detach
and indexOf
but I can't find a way to use them.
My template is
<ng-template #thumbnailTemplate let-description="description">
<div>
<a href="#" (click)="deleteView()">Delete {{description}}} (</a>
</div>
</ng-template>
The HTML is
<button #showTmplButton (click)="showTemplate()">{{buttonTitle}} </button>
<ng-container #vc></ng-container>
On clicking button
, a new instance of the template gets added to ng-container
. I want that on clicking a
, that specific view gets deleted. But how do I know at which index of ViewContainer
the view is stored and how to pass it to the deleteView
function?
The logic to add a view is
showTemplate(){
let view:ViewRef = this.vc.createEmbeddedView(this.tmpl, {description: 'description '+(this.id++)})
}
But I don't how to delete a specific view
deleteView(){
/*what to do here.
this.vc.remove(...);
*/
}
This seems to work. I am trying to delete a view from a container but I needed the reference of the view to delete.
Few new things I learned
When creating a view, we can pass a context object. This is like data passed to the template (see it as arguments and template is the function).
let view:ViewRef = this.vc.createEmbeddedView(this.tmpl,
{option:{divId:'thumbnail-'+(this.divId++),
closeId:'close-'+(this.closeId++)
}} );
If the template is
<ng-template #thumbnailTemplate let-option="option" let-index="index">
<div id="{{option.divId}}">
<img>
<a href="#" id="{{option.closeId}}" (click)="deleteIt(option)">template inserted at index {{option.index}}, {{option.divId}}, {{option.closeId}}</a>
</div>
</ng-template>
then let-option matches with option:
, {option:{divId:'thumbnail-'+(this.divId++), closeId:'close-'+(this.closeId++)}}
is the context object and I can then use option
in the template as {{option.divId}}
. It is explained here - What is $implicit in angular 2?
Once I learned how to pass data a template, I thought of using createEmbeddedView
and passed index
to it and then later also update the context object of the view with the index value. I can then later retrieve this value and use it in remove
of ngContainerRef
to remove that view. That seemed to work initially but after I stored say views 0,1,2,3 and then deleted index 1, the container would reorganise the views and assign them new indexes. However, the value in the context object didnt get updated.
Thus, instead of storing index, I store ViewRef
in the context object and when I want to delete a view, I called indexOf
to get the correct index value and use it in remove
Code.
showTemplate(){
/*
You need to pass an object with the keys that match the let-keyname syntax:
The ng-template in html uses let-option and let-index so the object passed need to have index and option keys
*/
//create view and pass context data
let view:ViewRef = this.vc.createEmbeddedView(this.tmpl,
{option:{divId:'thumbnail-'+(this.divId++),
closeId:'close-'+(this.closeId++)
}} );
//after view is created, get its index and updat context. Note that ViewIndexRef was not in initial context object.
view.context.option.viewIndexRef = view;//store ref of this view
}
//pass the entier context object to the function
deleteIt(option){
//get viewRef from context and then get index of the viewref
let index = this.vc.indexOf(option.viewIndexRef)
//remove the view
this.vc.remove(index);
}
In the html, template gets option object and the click
callback of a
passes it to deleteIt
function
<ng-template #thumbnailTemplate let-option="option" let-index="index">
<div id="{{option.divId}}">
<img>
<a href="#" id="{{option.closeId}}" (click)="deleteIt(option)">template inserted at index {{option.index}}, {{option.divId}}, {{option.closeId}}</a>
</div>
</ng-template>