与用户创建的内容进行数据绑定/交互

时间:2017-10-16 17:58:46

标签: javascript html angular angular-cli angular2-aot

我的最终目标是让用户创建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">的角度语法。然后使用加载运行时编译器JitCompilerFactory和自定义装饰器的示例here将组件和模块元数据保存到JIT编译组件,并将用户创建的内容作为模板。但是对于构建优化器,这需要restoring the ctorParameters。有了这个,你就无法获得AOT的所有大小优势,因为你仍然需要加载JIT编译器并按照here - “ 由于编译器受内部变化的影响,因此它似乎存在风险。它适用于@ angular / compiler @ 4.4.5,但可能不适用于其他版本。“

  2. (DOM操作)
    在用户创建的内容<a href="/path/to/diffrent/page/in/app">中保留适当的HTML。然后在绑定到innerHTML后获取ElementRef,然后找到每个锚标记并覆盖click事件。这种DOM操作在角度上似乎非常气馁。

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

  4. 编辑添加:

    1. (收听容器“点击”事件并过滤掉它是否来自锚点)
      请参阅@cyrix的answer
    2. 实现此功能的正确方法是什么?

      编辑更新:
      我接受了一个答案作为“最佳”选项,但如果有人发现或他们发布了“Angular”方式,请添加答案。

1 个答案:

答案 0 :(得分:1)

我遇到了同样的问题并通过创建自定义指令向动态内容的容器添加click - 侦听器来解决它,如果目标是锚元素,则检查每次单击。如果它是一个锚元素阻止默认行为并采用href - 属性,请将其用作router.navigateByUrl的网址。

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