Angular CDK:将覆盖层附加到单击的元素 [英] Angular CDK : attach overlay to a clicked element

查看:168
本文介绍了Angular CDK:将覆盖层附加到单击的元素的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为表格单元格创建自定义弹出窗口,以便在单击它时显示单元格详细信息,其方式类似于

I'm trying to make a custom popover for a table cell, in order to show a cell details when clicking on it, in a way similar to mdBoostrap popovers.

现在,我有以下应用程序: https://stackblitz.com/edit/angular- m5rx6j

For now, I have the following app: https://stackblitz.com/edit/angular-m5rx6j

Popup组件显示在主组件下,但是我想将其显示在表中,即我单击的元素下.

The Popup component shown under the main component, but I would like to show it over the table, just under the element I clicked.

我想我需要做以下事情:

I suppose I need to do the following :

  • 在单击的位置获取"td"的ElementRef->我不知道
  • 将叠加层附加到该元素上->已执行此操作,但已使用根元素

推荐答案

Netanet Basal博客中有两篇关于CDK使用OverLay的精彩文章

There're a two amazing articles about using OverLay from CDK in Netanet Basal's Blog

  1. 使用Angular CDK创建强大的组件
  2. 通过Angular CDK轻松使用上下文菜单
  1. Creating Powerful Components with Angular CDK
  2. Context Menus Made Easy with Angular CDK

我尝试简化为此stackblitz

基本上,您可以插入叠加层服务

Basicaly you has a service that inject Overlay

constructor(private overlay: Overlay) { }

要打开模板,请传递组件的原点(我称其为原点"),模板(称为菜单)和组件的viewContainerRef.

To open a template you pass the origin (I called him "origin"), the template (I called menu) and the viewContainerRef of your component

    this.overlayRef = this.overlay.create(
        this.getOverlayConfig({ origin: origin})
    );
    //I can pass "data" as implicit and "close" to close the menu
    this.overlayRef.attach(new TemplatePortal(menu, viewContainerRef, {
        $implicit: data, close:this.close
    }));

getOverLayConfig返回一个类似的配置

getOverLayConfig return a config some like

private getOverlayConfig({ origin}): OverlayConfig {
    return new OverlayConfig({
        hasBackdrop: false,
        backdropClass: "popover-backdrop",
        positionStrategy: this.getOverlayPosition(origin),
        scrollStrategy: this.overlay.scrollStrategies.close()
    });
}

位置策略是您要附加模板的位置-带有您喜欢的位置的数组,例如

And the position strategie is where you want to attach the template -an array with your preferered positions, e.g.

      [
        {
            originX: "center",
            originY: "bottom",
            overlayX: "center",
            overlayY: "top"
        },
      ]

好吧,代码的另一部分是关于关闭模板元素的.我选择在服务中创建一个打开该功能的功能

Well, the other part of the code is about close the template element. I choose create in the service a function open that

1.-附加元素

2.-创建

this.sub = fromEvent<MouseEvent>(document, "click")

3.-返回一个可观察值,该返回值将返回null或您在函数"close"(*)中传递的参数.

3.-return an observable that return null or the argument you pass in a function "close"(*)

注意:不要忘记包含在CSS ~@angular/cdk/overlay-prebuilt.css

NOTE: Don't forget incluyed in your css ~@angular/cdk/overlay-prebuilt.css

(*)这允许我使用我的模板

(*) this allow me my template like

<ng-template #tpl let-close="close" let-data>
  <div class="popover" >
    <h5>{{name}} {{data.data}}</h5> //<--name is a variable of component
                                    //data.data a variable you can pass
  And here's some amazing content. It's very engaging. Right?
  <div>
   <a (click)="close('uno')">Close</a> //<--this close and return 'uno'
  </div>
  </div>
</ng-template>

更新,如果我们要首先附加组件,我们需要记住,该组件必须位于模块的entryComponents中.

Update if we want to attach a component first we need remember that must be in the entryComponents of the module

@NgModule({
  imports:      [ BrowserModule, FormsModule,OverlayModule ],
  declarations: [ AppComponent,HelloComponent], //<--HERE
  bootstrap:    [ AppComponent ],
  entryComponents:[HelloComponent]  //<--and HERE

})

好吧,附加组件很简单,只需更改附加并使用ComponentPortal,例如

Well, to attach a component is simple change the attach and use ComponentPortal, e.g.

const ref=this.overlayRef.attach(new ComponentPortal(HelloComponent,viewContainerRef))

然后,如果我们的组件有一些输入,例如

then, if our component has somes inputs, e.g.

  @Input() name="Angular";
  @Input() obj={count:0};

我们可以使用ref.instance来访问组件,例如

We can use ref.instance to access to the component, e.g

  ref.instance.name="New Name"

但是,由于我们要维护该服务的最一般用途,因此我想使用参数"data"为变量赋值,因此我们的函数"open"变为

But as we want maintain the service the most general use, I want to use the argument "data" to give values to the variables, so our function "open" becomes

open(origin: any, component: any, viewContainerRef: ViewContainerRef, data: any) {
        this.close(null);
        this.overlayRef = this.overlay.create(
            this.getOverlayConfig({ origin: origin})
        );
        const ref=this.overlayRef.attach(new ComponentPortal(component, viewContainerRef));
    for (let key in data) //here pass all the data to our component
    {
       ref.instance[key]=data[key]
    } 
    ...rest of code...
}

和往常一样,如果我们传递一个对象,则组件中的所有更改都会更改该对象的属性,因此在我们的主组件中可以做出类似的修改

As always, if we pass an object, all the changes in the component change the properties of the object, so in our main component can be make some like

obj={count:2}

open(origin:any,menu:any,index:number)
  {
    this.popupService.open(origin,HelloComponent,this.viewContainerRef,
        {name:'new Name'+index,obj:this.obj})
    .subscribe(res=>{
      console.log(res)
    })
  }

看到,当我将obj作为对象传递时,组件中的任何更改都会改变对象的属性,就我而言,组件非常简单

See that, as I pass as obj an object any change in the component change the propertie of the object, in my case the component is very simple

@Component({
  selector: 'component',
  template:`Hello {{name}}
    <button (click)="obj.count=obj.count+1">click</button>
  `
})
export class HelloComponent  {
  @Input() name="Angular";
  @Input() obj={count:0};
}

您可以在新的stackblitz中看到

Update2 要从HelloComponent关闭面板,我们需要将服务公开注入并使用close.或多或少,一个按钮

Update2 To close the panel from the HelloComponent we need inject the service as public and use close. more or less, a button

<button (click)="popupService.close(4)">close</button>

您在哪里注入服务

constructor(public popupService: MenuContextualService){}

这篇关于Angular CDK:将覆盖层附加到单击的元素的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆