Динамически переключайте html-шаблоны на действие пользователя в angular 2

С помощью Angularjs 1.x вы можете легко переключаться на html-шаблоны при нажатии кнопки между модулем edit/readonly. Директива ng-include была ключом.

<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>

Функция get getTemplate выполняет этот код:

$scope.getTemplate = function (contact) {
    if (contact.id === $scope.model.selected.id) return 'edit';
    else return 'display';
};

который снова приводит к тому, что один из этих шаблонов будет активен в пользовательском интерфейсе:

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>

ИЗМЕНИТЬ

<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/

С Angular 2 RC 4 не существует n-include.

Как бы я сделал ту же функцию только с Angular 2 RC4?

Ответ 1

Я бы использовал директиву ngTemplateOutlet, чтобы сделать это.

Поскольку версия 2.0.0-rc.2 (2016-06-15) была добавлена ​​в ngTemplateOutlet

чтобы вы могли использовать эту функцию, как описано в демонстрационном плунжере (обновлено до 4.xx)

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;
    }
}

Ответ 2

Вам нужно немного изменить то, как вы думаете об этом. Это не просто шаблон, это ветвь дерева компонентов приложения. Подумайте об этом с точки зрения компонентов и с какой целью они служат в вашем приложении.

В вашем случае, если у вас есть "редактировать" и "отображать" виды, тогда было бы целесообразно разработать приложение с помощью компонентов редактирования и отображения и переключить их с помощью ngIf или ngSwitch. Затем каждый из этих компонентов должен был бы иметь возможность брать модель данных в качестве свойства (Input) и делать так, как ему нужно.

Так может быть что-то вроде этого:

<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. Вот простая демонстрация подхода:

http://plnkr.co/edit/drzI1uL4kkKvsrm0rgOq?p=info