With Angularjs 1.x you could easily switch html templates on a button click between edit/readonly modus. The ng-include directive was the key.
<table>
<thead>
<th>Name</th>
<th>Age</th>
<th></th>
</thead>
<tbody>
<tr ng-repeat="contact in model.contacts" ng-include="getTemplate(contact)">
</tr>
</tbody>
</table>
The get getTemplate function executes this code:
$scope.getTemplate = function (contact) {
if (contact.id === $scope.model.selected.id) return 'edit';
else return 'display';
};
which again lead to one of those templates to be active in the UI:
DISPLAY
<script type="text/ng-template" id="display">
<td>{{contact.name}}</td>
<td>{{contact.age}}</td>
<td>
<button ng-click="editContact(contact)">Edit</button>
</td>
</script>
EDIT
<script type="text/ng-template" id="edit">
<td><input type="text" ng-model="model.selected.name" /></td>
<td><input type="text" ng-model="model.selected.age" /></td>
<td>
<button ng-click="saveContact($index)">Save</button>
<button ng-click="reset()">Cancel</button>
</td>
</script>
https://jsfiddle.net/benfosterdev/UWLFJ/
With Angular 2 RC 4 there exist no n-include.
How would I do the same feature just with Angular 2 RC4 ?
I would leverage ngTemplateOutlet
directive to do that.
Since version of 2.0.0-rc.2 (2016-06-15) context was added to NgTemplateOutlet
so you can try to use this feature as described in my demo plunker (updated to 4.x.x)
template.html
<table>
<thead>
<th>Name</th>
<th>Age</th>
<th></th>
</thead>
<tbody>
<tr *ngFor="let contact of contacts; let i = index">
<ng-template [ngTemplateOutlet]="getTemplate(contact)"
[ngOutletContext]="{ $implicit: contact, index: i }"></ng-template>
</tr>
</tbody>
</table>
<ng-template #displayTmpl let-contact>
<td>{{contact.name}}</td>
<td>{{contact.age}}</td>
<td>
<button (click)="editContact(contact)">Edit</button>
</td>
</ng-template>
<ng-template #editTmpl let-i="index">
<td><input type="text" [(ngModel)]="selected.name" /></td>
<td><input type="text" [(ngModel)]="selected.age" /></td>
<td>
<button (click)="saveContact(i)">Save</button>
<button (click)="reset()">Cancel</button>
</td>
</ng-template>
component.ts
import { Component, ViewChild, TemplateRef } from '@angular/core';
interface Contact {
id: number;
name: string;
age: number
}
@Component({
....
})
export class App {
@ViewChild('displayTmpl') displayTmpl: TemplateRef<any>;
@ViewChild('editTmpl') editTmpl: TemplateRef<any>;
contacts: Array<Contact> = [{
id: 1,
name: "Ben",
age: 28
}, {
id: 2,
name: "Sally",
age: 24
}, {
id: 3,
name: "John",
age: 32
}, {
id: 4,
name: "Jane",
age: 40
}];
selected: Contact;
getTemplate(contact) {
return this.selected && this.selected.id == contact.id ?
this.editTmpl : this.displayTmpl;
}
editContact(contact) {
this.selected = Object.assign({}, contact);
}
saveContact (idx) {
console.log("Saving contact");
this.contacts[idx] = this.selected;
this.reset();
}
reset() {
this.selected = null;
}
}
You need to change the way you think about this things a little bit. It's not just a template, it's a branch of the application component tree. Think of it in terms of components and what purpose they serve in your application.
In your case, if you have "edit" and "display" views, then it would make sense to design your app with edit and display components and switch them with ngIf or ngSwitch. Each of those components would then need to be able to take data model as a property (Input
) and render itself the way it needs.
So it could be something like this:
<tbody>
<tr *ngFor="let contact of model.contacts">
<contact-display *ngIf="getView(contact) === 'display'" [contact]="contact"></contact-display>
<contact-edit *ngIf="getView(contact) === 'edit'" [contact]="contact"></contact-edit>
</tr>
</tbody>
UDP. Here is a simple demo of the approach:
http://plnkr.co/edit/drzI1uL4kkKvsrm0rgOq?p=info
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