Проектируем блочный визуальный конструктор сайтов. Сервер будет отдавать размеченный готовый HTML блоков, но весь визуальный интерфейс, все контролы, настройки каждого блока хотим обрабатывать в приложении на Angular 7.
Подскажите best practive, какие-либо статьи или материалы по навешиванию Angular приложения (навешивание событий, модификация HTML, и т.д.) на статичный (сформированный сервером) HTML.
Понимаю, что в идеальном случае весть HTML должен формироваться из самого приложения Angular, но реальность такова, что HTML, который должен "ожить" приходит с сервера.
Здесь нет никаких best practice, с этим немногие сталкиваются, но регистрирование обработчиков событий в Angular работает так же, как и в обычном JavaScript. Самое большое преимущество ручного регистрирования обработчиков событий - производительность. Такой шаблон:
<button (click)="clickMe()">Click me</button>
Компилируется в NodeDef
- определение узла. В рантайме у этого объекта будет свойство outputDefs
(массив), который будет содержать объекты OutputDef
, в случае с узлом button
объект будет таков:
{
type: OutputType.ElementOutput, // 0
target: 'component',
eventName: 'click',
propName: 'clickMe'
}
Далее Angular регистрирует обработчики событий через класс EventManager
, фактически все, что он делает это:
addEventListener(nodeDef.element, outputDef.eventName, componentInstance[outputDef.propName]);
Все, да не все. Эти действия происходят в зоне Angular, поэтому на любой асинхронное событие Angular запускает механизм обнаружения изменений по всему дереву.
Если же у нас будет готовый HTML, то мы можем регистрировать обработчики событий вне зоны и контролировать механизм обнаружения изменений, как пример возьмем компонент, в котором есть элемент, который сеттит innerHTML
через атрибут:
@Component({
selector: 'app-root',
template: `
<div [innerHTML]="html"></div>
`
})
export class AppComponent implements OnDestroy {
public html: SafeHtml = null!;
private listeners: Function[] = [];
constructor(
private zone: NgZone,
private renderer: Renderer2,
private sanitizer: DomSanitizer,
private host: ElementRef<HTMLUnknownElement>,
private service: SomeService
) {
this.service.getHTML().subscribe((html) => {
this.setHTML(html);
});
}
public ngOnDestroy(): void {
this.listeners.forEach((listener) => listener());
}
private setHTML(html: string): void {
this.html = this.sanitizer.bypassSecurityTrustHtml(html);
this.zone.runOutsideAngular(() => {
// обработчики событий мы должны регистрировать после того
// как засеттится `innerHTML`, поэтому используем `setTimeout`
setTimeout(() => this.addEventListeners());
});
}
private addEventListeners(): void {
const node = this.host.nativeElement.querySelector('some-element')!;
this.listeners.push(
this.renderer.listen(node, 'click', (e: MouseEvent) => {
console.log(e);
})
);
}
}
А вообще вы можете не знать на каких элементах вызываются события, но вы могли бы формировать HTML на сервере с подсказками, например:
<button data-event="click" data-method="clickMe">Click me</button>
<div data-event="mousemove" data-method="handleMousemove">Mousemove me</div>
В компоненте достаточно будет обойти все узлы и проверить свойства из dataset
:
const nodes = this.host.nativeElement.querySelectorAll('*');
nodes.forEach((node: HTMLElement) => {
const { event, method } = node.dataset;
if (event && method && typeof this[method] === 'function') {
this.listeners.push(this.renderer.listen(node, event, this[method]));
}
});
А еще осторожней с контекстом, нужно тогда использовать стрелочные функции для методов:
private handleMousemove = () => {}
Или биндить:
this.renderer.listen(node, event, this[method].bind(this))
Да, кстати, обязательно нужно использовать DomSanitizer.prototype.bypassSecurityTrustHtml
ибо Angular для защиты от XSS вообще удаляет все атрибуты и прочее регулярками, оставляя только элемент и текст внутри него.
Виртуальный выделенный сервер (VDS) становится отличным выбором
Имеется форма и нужно её отправить без button и input использую (a)Почему без? Ломаются стили
Уже несколько лет не верстал email-писем, изменилось ли что-нибудь? Мы по прежнему верстаем на таблицах, а стили – инлайним? Я пытался найти статистики...
Есть таблица, на предпоследней строке 3 ячейки, на последней 2: фотоПодскажите пожалуйста, как мне сделать выравнивание последней строки по центру,...