1

I have an angular autocomplete-tree component and I have an issue with the autocomplete panel width.

I have two requirements that I can solve individually but not together:

  • The panel should grow once the content is wider than the panel. I used [panelWidth] = "auto" for this and it works perfectly.
  • The panel should have a minimum width of the host input. Can also use panelWidth for this but then I lose the functionality in the first point.

From Change the mat-autocomplete width?) I saw I can use [panelWidth] = "auto".

I know I can use the css styling .mat-autocomplete-panel{min-width: "300px"} but don't know how to get the width of the specific input.

So I resorted to javascript. I saw in the documentation that AutocompletePanel exposes the panel ElementRef, but this value seems to be undefined no matter what I do? Is the right way to acquire this value with @ViewChild? I have the following code that runs on the opened event.

<mat-autocomplete #autocomplete (opened)="opened()" [panelWidth]="auto" #auto="matAutocomplete">
@ViewChild("auto") autocomplete: MatAutocomplete;
@ViewChild("autoTreeInput") autoTreeInput: ElementRef;

  opened = () => {
    setTimeout(()=>{

    let p = this.autocomplete.panel?.nativeElement; //always null because panel is undefi
    console.log("opened", p, this.autocomplete);
    if (!p ) return
    p.style.minWidth =
      this.autoTreeInput.nativeElement.getBoundingClientRect().width + "px";
    },1000)
  };

Stackblitz

Pieter Buys
  • 1,280
  • 1
  • 10
  • 20

2 Answers2

1

The panel elementRef shows up after (not on) opened event is fired. More specifically, after the panel is added to the DOM. So simply adding a setTimeout in which I get the element works. Unfortunately this means that the element shows up with the wrong width and then jumps to the width of the input.

There might be a better solution, but this is what I'm going with now.

 opened = ()=> {
    let inputWidth = this.autoInput.nativeElement.getBoundingClientRect().width
    setTimeout(()=>{
      let panel = this.autocomplete.panel?.nativeElement;

      if (!panel ) return
      panel.style.minWidth = inputWidth + "px";
    })
  }

Working stackblitz

Pieter Buys
  • 1,280
  • 1
  • 10
  • 20
0

I have reviewed you stackblitz example.

It looks like is more a css issue.

Try this on autocomplete-simple-example.css file

.example-form {
  min-width: 150px;
  // max-width <-- remove it to use 100% of width
  width: 100%;
}

.example-full-width {
  width: 100%; // add this to use all width.
  transition: width 0.5s ease;
}
.mat-focused {
  width: 270px;
}

A working example is here: stackblitz

Edit

You can add any valid css to width css. In this way a have added calc(100% - 60%) to make it fixed same as input

.example-form {
  min-width: 150px;
  width: 100%;
}

.example-full-width {
  width: 100%;
  transition: width 0.5s ease;
}
.mat-focused {
  width: 100%;
}
<mat-autocomplete (opened)="opened()" panelWidth="calc(100% - 60px)" </mat-autocomplete>

Working example

Luis Reinoso
  • 748
  • 4
  • 13
  • So I need the panel to be the *same* width as the , or more if the content becomes wider. And this does not seem to happen in your example – Pieter Buys Jan 19 '21 at 14:47
  • Sorry, still no dice. panelWidth="calc(100% - 60px)" will make the panel 100% of the window and not 100% of the input, so resizing the input will not affect the width of the panel. Also, if panelWidth is not set to "auto", the panelWidth will not grow as content grows. Please take notice of both of the requirements in my question as I know of ways to achieve each individually but not together. – Pieter Buys Jan 20 '21 at 08:00