【问题标题】:Angular component in a Browser's child window浏览器子窗口中的 Angular 组件
【发布时间】:2019-05-07 19:58:04
【问题描述】:

从 Angular 应用程序有什么方法可以创建浏览器的子窗口并在其中显示一些预定义的角度组件。

澄清:我不是在寻找模态对话框解决方案。

【问题讨论】:

  • 我没有告诉你什么是子窗口代表?
  • @R.Viral .. 浏览器的子窗口。
  • 你的意思是window.open
  • 你是说将组件加载到 iframe 中吗?

标签: angular browser components angular6 childwindow


【解决方案1】:

我之前登陆过这篇文章,所以如果有人仍然试图在不运行新应用的情况下在不同的窗口上动态加载组件,我就是这样做的:

export class ChildLoaderComponent implements OnInit, AfterViewInit {
  constructor(private r: ComponentFactoryResolver, private 
                           viewContainerRef: ViewContainerRef) { }
  public windowReference: any;
  ngAfterViewInit() {
    setTimeout(() => {
      //create the component dynamically
      const factory = this.r.resolveComponentFactory(AChildComponent);
      const comp: ComponentRef<AChildComponent> =
        this.viewContainerRef.createComponent(factory);
      //in case you also need to inject an input to the child, 
      //like the windows reference 
      comp.instance.someInputField = this.windowReference.document.body;
      //add you freshly baked component on the windows
      this.windowReference.document.body.appendChild(comp.location.nativeElement);
    });
  }

  ngOnInit() {
    //create the windows and save the reference     
    this.windowReference = window.open('', '_blank', 'toolbar=0, width=800, height=400');
  }
}

【讨论】:

  • 优秀。有时,像这些最简单的老派解决方案是我最喜欢的。完全忘记了访问新窗口/标签的正文。
  • 这正是我所需要的!我正在寻找一种在新窗口中打开 Angular 组件的方法,而无需再次引导整个应用程序。我们正在使用它来显示一个带有手册的页面,我们不想打开整个应用程序 2 次。
  • 这适用于 chrome/edge/ff 但不适用于 ie11。抛出 ERROR HierarchyRequestError
  • 使用这种方法,窗口将打开,但没有正确的 css
  • 我失去了所有的布局和样式
【解决方案2】:

这是我为自己找到的,并且完全符合您的需要。

https://stackblitz.com/edit/angular-open-window

可以在新的子窗口中显示您的自定义角度组件,并且任何角度服务也将被注入到子窗口中显示的任何组件中。

它定义了一个新的WindowComponent,其中包含一个门户主机。此门户主机附加到子窗口的主体。这意味着附加到门户主机的任何门户都将呈现到子窗口的主体。向门户主机传递componentFactoryResolverapplicationRefinjector,大概是为了初始化您的自定义角度组件并在子窗口中注入所需的服务。

const host = new DomPortalHost(
    this.externalWindow.document.body,
    this.componentFactoryResolver,
    this.applicationRef,
    this.injector
);

WindowComponent 的模板中,它使用*cdkPortal 定义了一个门户。在门户内部,它使用 ng-content 投影窗口组件的内容,由窗口内容的父级定义。

<ng-container *cdkPortal>
  <ng-content></ng-content>
</ng-container>

无论何时创建WindowComponent,它都会打开一个子窗口,并将其门户附加到门户主机。当WindowComponent被销毁时,会关闭子窗口。

  ngOnInit(){
    // STEP 4: create an external window
    this.externalWindow = window.open('', '', 'width=600,height=400,left=200,top=200');

    // STEP 5: create a PortalHost with the body of the new window document    
    const host = ...

    // STEP 6: Attach the portal
    host.attach(this.portal);
  }

  ngOnDestroy(){
    // STEP 7: close the window when this component destroyed
    this.externalWindow.close()
  }

这意味着在应用程序组件中,您可以使用窗口组件上的*ngIf 指令简单地切换弹出窗口,并嵌套您想要在模板中显示的任何内容。

<window *ngIf="showPortal">
  <h2>Hello world from another window!!</h2>
  <button (click)="this.showPortal = false">Close me!</button>
</window>

使用@angular/cdk 包,您还可以修改此示例以编程方式创建子窗口,方法是使用ComponentPortal 而不是使用@ViewChild 装饰器检索CdkPortal。通过检索对门户主机的引用,您甚至可以以编程方式将子窗口的内容替换为不同的组件。将门户附加到门户主机时,您还可以为您的实例化组件获取ComponentRef,从而允许您通过代码与之交互。

【讨论】:

  • 这似乎是一个非常干净和好的解决方案,但我遇到了以下问题: 1. 新窗口中没有应用任何 CSS 样式。甚至没有应用程序范围的样式的东西。 2. 如果我在新的浏览器弹出窗口中打开一个模块化弹出窗口,则模块化弹出窗口将在原始浏览器窗口中打开。我将 MatDialog 用于模块化弹出窗口。对此的任何帮助将不胜感激。
  • 我尝试了你的解决方案,但是当我关闭弹出窗口并再次单击打开我时,它没有显示?
  • 很遗憾,这在 Microsoft Edge 浏览器中不起作用。
  • 这是一个非常好的解决方案,但在 ie11 中不起作用
  • 你如何处理样式?
【解决方案3】:

如果您将window.open 用于子窗口,以便 显示一个角度组件,该窗口应加载一个website 使用角度这意味着您在自己的应用程序中创建一个孩子 该页面的特殊路线,然后您将自己的应用程序打开到该特定页面 路线。如果您选择此解决方案,请注意您的应用程序的大小 如果您使用异步路由,则此解决方案可以正常工作,因此当您打开 应用程序在新窗口中,您将下载 angular + other core libs 您正在使用的和 + js for that specific route

另一种选择是在您的服务器中创建另一个 Angular 应用程序 仅包含该内容,并且您在同一服务器上提供了 2 个应用程序 在这种情况下,您需要在不同的 url 上创建一个新的 Angular 应用程序 仅包含该特定内容

【讨论】:

  • 我无法创建另一个 Angular 应用程序。我想要的是在新窗口中将现有的角度“组件”显示为“弹出窗口”,以便它可以在具有所有功能的单独窗口中。
  • 嗯,所以如果我理解正确,您希望有一个链接,该链接可以打开一个具有相同应用程序的新浏览器窗口,但在您的应用程序中,您打开了一个对话框并且该对话框包含您的组件?
  • Uhmm.. 我的应用中的 每个 组件都有一个链接。如果我单击它,则应在子窗口中打开该特定组件。还不清楚吗:(
  • 如果你想根据你使用的包你可能有解决方案,所以angular-material 有一个dialog 组件,它可以让你在对话框中打开一个组件,但是那个组件如果您需要能够使用 url 访问对话框,则不受路由限制/跨度>
  • 如果答案有帮助,请告诉我,以便我更新主要答案
【解决方案4】:

您可以尝试为不同的窗口命名。这将打开具有指定名称的每个新窗口。

window.open('url', 'window 1', '');
window.open('url', 'window 2', '');

【讨论】:

    【解决方案5】:

    您可以使用带有target="_blank" 属性的链接来做到这一点

    example.component.html

    <a [routerLink]="['/route-to-your-component']" target="_blank">
      Open the component in a new tab
    </a>
    

    【讨论】:

      【解决方案6】:

      创建延迟加载组件(作为 url)并将你的 url 放入

      window.open('url', 'window name', 'settings')
      

      【讨论】:

        猜你喜欢
        • 2017-07-31
        • 2018-05-20
        • 2011-02-18
        • 1970-01-01
        • 2017-12-23
        • 2020-05-11
        • 2013-02-20
        • 2021-03-24
        • 2017-02-21
        相关资源
        最近更新 更多