Динамически привязывать модель и шаблон к узлу DOM в Angular 2
этоPlunker определяет<view>
компонент, который может визуализировать произвольную модель + шаблон. Это должно быть изменено назамещать ранее визуализированное содержимое, а не добавление новых пиров.
РЕДАКТИРОВАТЬ: Это работает сейчас, благодаря ответу пользователя 3636086.
Одна проблема все еще остается: в отличие от Angular 1, Angular 2 вынуждает меня создавать вложенный компонент для обновления шаблона (поскольку шаблоны фактически являются статическим свойством компонента).учебный класс), поэтому у меня есть куча ненужных узлов DOM.
Длинная версияУгловой 1В нашем проекте мы бы предпочлисамый нашего кода, чтобы не иметь прямой зависимости от инфраструктуры пользовательского интерфейса. У нас есть класс viewmodel, который связывает воедино модель и представление. Вот упрощенные примеры:
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>`;
}
}
У нас естьview
директива, которая может отображать одно из следующих представлений:
<div view='viewInstance'></div>
ЕслиviewInstance
изменения, новый объект View отображается (модель + шаблон) в этом месте в DOM. Например, это представление Dashboard может иметь произвольный список представлений, которые он может отображать:
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'>"; }
}
Важным моментом является то, что это составно.<view>
может содержать<view>
который может содержать<view>
, так далее и так далее.
В Angular 1 нашview
Директива выглядит примерно так:
.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());
});
}
};
}
]);
Угловой 2Я пытаюсь перенести это на Angular 2, но динамическая загрузка нового шаблона в DOM-месте очень неуклюжа, заставляя меня каждый раз создавать новый тип компонента.
Это лучшее, что я придумал (дополнено отзывами от пользователя 3636086):
@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;
});
}
}
}
Используется что-то вроде этого:
@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();
}
}
РЕДАКТИРОВАТЬ: Этоимел проблемы, которые сейчас исправлены.
Оставшаяся проблема заключается в том, что он создает кучу ненужных вложенных элементов DOM. Что я действительно хочу это:
<view>VIEW CONTENTS RENDERED HERE</view>
Вместо этого мы имеем:
<view>
<span></spawn>
<viewrenderer>VIEW CONTENTS RENDERED HERE</viewrenderer>
</view>
Это тем хуже, чем больше мы вкладываем представлений, при этом половина строк здесь не является посторонним дерьмом:
<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>