Dynamisches Binden von Modell und Vorlage an den DOM-Knoten in Winkel 2
Dies Plunker definiert ein<view>
-Komponente, die ein beliebiges Modell + Vorlage rendern kann. Dies muss in @ geändert werdersetze die zuvor gerenderten Inhalte, anstatt neue Peers hinzuzufügen.
EDIT: Dies funktioniert jetzt, dank der Antwort von user3636086.
Ein Problem bleibt weiterhin bestehen: Im Gegensatz zu Angular 1 zwingt Angular 2 mich, eine verschachtelte Komponente zu erstellen, um eine Vorlage zu aktualisieren (da Vorlagen effektiv eine statische Eigenschaft der @ -Eigenschaft einer Komponente sinKlass), so habe ich eine Reihe von unnötigen DOM-Knoten hinzugefügt.
Lange VersioAngular 1In unserem Projekt würden wir bevorzugendie meiste unseres Codes, um keine direkte Abhängigkeit von einem UI-Framework zu haben. Wir haben eine viewmodel-Klasse, die ein Modell und eine Ansicht miteinander verbindet. Hier sind vereinfachte Beispiele:
interface IView {
template: string;
}
class SalesView implements IView {
sales: number = 100;
get template() { return "<p>Current sales: {{model.sales}} widgets.<p>"; }
}
class CalendarView implements IView {
eventName: string = "Christmas Party";
get template() { return "<p>Next event: {{model.eventName}}.<p>"; }
}
class CompositeView implements IView {
calendarView = new CalendarView();
salesView = new SalesView();
get template() { return
`<div view='model.salesView'></div>
<div view='model.calendarView'></div>`;
}
}
Wir haben einview
Direktive, die eine der folgenden Ansichten anzeigen kann:
<div view='viewInstance'></div>
WennviewInstance
ei Änderungen wird an dieser Stelle im DOM ein neues Ansichtsobjekt (Modell + Vorlage) gerendert. Diese Dashboard-Ansicht kann beispielsweise eine beliebige Liste von Ansichten enthalten, die gerendert werden können:
class Dashboard implements IView {
views: Array<IView> = [ new SalesView(), new CalendarView(), new CompositiveView() ];
activeView: View;
get template() { return "<h1>Dashboard</h1> <div view='model.activeView'>"; }
}
Ein entscheidender Punkt ist, dass dies zusammensetzbar ist. Das<view>
kann ein @ enthalt<view>
welches ein @ enthalten ka<view>
, und so weiter und so fort
In Angular 1, unserview
Direktive sieht ungefähr so aus:
.directive("View", [ "$compile",
($compile: ng.ICompileService) => {
return <ng.IDirective> {
restrict: "A",
scope: { model: "=View" },
link(scope: ng.IScope, e: ng.IAugmentedJQuery, atts: ng.IAttributes): void {
scope.$watch((scope: any) => scope.model, (newValue: any) => {
e.html(newValue.template);
$compile(e.contents())(scope.$new());
});
}
};
}
]);
Angular 2Ich versuche, dies auf Angular 2 zu portieren, aber das dynamische Laden einer neuen Vorlage an einem DOM-Speicherort ist sehr umständlich und zwingt mich, jedes Mal einen neuen Komponententyp zu erstellen.
Dies ist das Beste, das ich mir ausgedacht habe (aktualisiert mit dem Feedback von user3636086):
@Component({
selector: 'view',
template: '<span #attach></span>',
})
export class MyView {
@Input() model: IView;
previousComponent: ComponentRef;
constructor(private loader: DynamicComponentLoader, private element: ElementRef) {
}
onChanges(changes: {[key: string]: SimpleChange}) {
var modelChanges = changes['model']
if (modelChanges) {
var model = modelChanges.currentValue;
@Component({
selector: 'viewRenderer',
template: model.template,
})
class ViewRenderer {
model: any;
}
if (this.previousComponent) {
this.previousComponent.dispose();
}
this.loader.loadIntoLocation(ViewRenderer, this.element, 'attach')
.then(component => {
component.instance.model = model;
this.previousComponent = component;
});
}
}
}
Gebraucht so etwas:
@Component({
selector: 'app',
template: `
<view [model]='currentView'></view>
<button (click)='changeView()'>Change View</button>
`,
directives: [MyView]
})
export class App {
currentView: IView = new SalesView();
changeView() {
this.currentView = new CalendarView();
}
}
EDIT: Dieseshätte Probleme, die jetzt behoben wurden.
Das verbleibende Problem besteht darin, dass eine Reihe unnötiger verschachtelter DOM-Elemente erstellt wird. Was ich wirklich will ist:
<view>VIEW CONTENTS RENDERED HERE</view>
Stattdessen haben wir:
<view>
<span></spawn>
<viewrenderer>VIEW CONTENTS RENDERED HERE</viewrenderer>
</view>
Dies wird umso schlimmer, je mehr Ansichten wir verschachtelt haben, ohne dass die Hälfte der Zeilen hier irrelevant ist:
<view>
<span></spawn>
<viewrenderer>
<h1>CONTENT</h1>
<view>
<span></spawn>
<viewrenderer>
<h1>NESTED CONTENT</h1>
<view>
<span></spawn>
<viewrenderer>
<h1>NESTED NESTED CONTENT</h1>
</viewrenderer>
</view>
</viewrenderer>
</view>
</viewrenderer>
<viewrenderer>
<h1>MORE CONTENT</h1>
<view>
<span></spawn>
<viewrenderer>
<h1>CONTENT</h1>
</viewrenderer>
</view>
</viewrenderer>
</view>