2017-10-16 102 views
1

我的最终目标是让用户创建HTML(来自数据库),并能够在Angular SPA中进行导航。从后端显示HTML的简单方法是使用DomSanitizer,然后绑定到某个元素的innerHTML。当用户创建的内容中的锚定标记<a href="/path/to/diffrent/page/in/app">重新启动应用程序时,会出现问题。我想到了3个解决方案,他们都有问题。与用户创建内容的数据绑定/交互

注:我想充分利用AOT和构建优化器。

  1. (与JIT编译器的动态分量)
    用户创建的内容具有角语法等<a [routerLink]="/path/to/diffrent/page/in/app">。然后使用示例here加载运行时编译器JitCompilerFactory和自定义装饰器来将组件和模块元数据保留为JIT编译组件,并将用户创建的内容作为模板。但是使用构建优化器,这需要restoring the ctorParameters。有了这个,你不会获得AOT的所有优势,因为你仍然需要加载JIT编译器,并且如上所述here - “ 而编译器受内部变化影响似乎很危险。它适用于@ angular/compiler @ 4.4.5但可能不适用于其他版本。“

  2. (DOM操作)
    在用户创建的内容中保留正确的HTML <a href="/path/to/diffrent/page/in/app">。然后绑定到innerHTML后得到一个ElementRef,然后找到每个锚标签并重写单击事件。这种DOM操控在角度上似乎非常令人沮丧。

  3. (自定义窗口事件)
    用户创建的内容看起来像<a onclick="window.someGlobalFunc("/path/to/diffrent/page/in/app")">。然后以某种方式倾听窗口事件。我更喜欢这个想法,因为它完全超出了角度。

编辑添加:

  • (听到容器 “点击” 事件和过滤器,如果它从一个锚来到)
    参见@cyrix的answer
  • 什么是实现此功能的正确方法?

    编辑更新:
    我接受了一个答案作为“最佳”选项,但如果任何人发现或他们发布了“角度”的方式来做到这一点,请添加一个答案。

    +0

    获得动态添加内容的Angular“stuff”的唯一方法是在运行时编译组件并动态添加该组件。您始终可以使用命令式方法(JavaScript)来访问和修改DOM以及添加/删除事件处理程序。 –

    +0

    @GünterZöchbauer是的,这是我的解决方案1.但这需要“黑客”,可能会改变与AOT和构建优化器一起工作。 –

    +0

    找到了[SO](https:// stackoverflow。com/questions/37676726/angular-2-innerhtml-click-binding#answer-37676847) where [@GünterZöchbauer](https://stackoverflow.com/users/217408/g%c3%bcnter-z%c3%b6chbauer )链接到此,[用户点击选择组件的Angular 2动态标签](https://stackoverflow.com/questions/36325212/angular-2-dynamic-tabs-with-user-click-chosen-components/36325468# 36325468),这导致发现这是一个可能的解决方案。 [动态地将组件插入到html中](https://stackoverflow.com/questions/45984171/insert-component-into-html-dynamically#answer-45985727) – ttugates

    回答

    1

    我遇到了同样的问题,并通过创建自定义指令并在每次点击时检查目标是否为锚点元素来为动态内容的容器添加click -listener来解决此问题。如果它是一个锚点元素,可以防止默认行为,并使用href-attribute,请将其用作router.navigateByUrl的url。

    private onClick(e: any) { 
        let link = this.checkForParentLink(e.target as HTMLElement); 
        if(link && link.getAttribute('href')) { 
         let href = link.getAttribute('href'); 
         let isMailOrPhone = href.startsWith('mailto:') || href.startsWith('tel:'); 
         if(isMailOrPhone) return; 
         e.preventDefault(); 
         if(link.getAttribute('target') === '_blank') {  
         let win = window.open(href, '_blank'); 
         win && win.focus(); 
         } else { 
         this.router.navigateByUrl(href); 
         } 
        } 
        } 
    
        private checkForParentLink(element: HTMLElement): HTMLLinkElement { 
        if(!element) return; 
        if(element.tagName === 'A') { 
         return element as HTMLLinkElement; 
        // this.element.nativeElement is in this case the container element 
        } 
        if(element.parentNode === this.element.nativeElement) { 
         return null; 
        } 
        return this.checkForParentLink(element.parentNode as HTMLElement); 
        }