Im trying to make select element width equal to it's option text width in angular.
My HTML component simply look like this:
<form [formGroup]="profileForm">
...
<select (change)="adjustSelectWidth($event.target)" formControlName="members">
<option value="1">Me</option>
<option value="2">Me, my spouse</option>
<option value="3">Me, my spouse and my kids</option>
</select>
...
</form>
What I have tried:
clientWidth
then apply that to select element but that width is 0. export class AppComponent {
profileForm = new FormGroup({
members : new FormControl(''),
})
adjustSelectWidth(e){
const optionValue = this.profileForm.get('members').value;
const optionWidth = document.querySelector(`option[value="${optionValue}"]`).clientWidth;
e.style.width= optionWidth + "px"
}
}
innerHTML
length then mutiply it with a fixed pixel but it not a dynamic optionexport class AppComponent {
profileForm = new FormGroup({
members : new FormControl(''),
})
adjustSelectWidth(e){
const optionValue = this.profileForm.get('members').value;
const optionTextLength = document.querySelector(`option[value="${optionValue}"]`).innerHTML.length;
e.style.width= optionTextLength*8 + "px";
}
}
innerHTML
to a span element for measuring width, but then that span clientWidth
does not accurate when I apply it's to the select element export class AppComponent {
//This temp is bind to a span via string interpolation {{...}}
temp:string;
profileForm = new FormGroup({
members : new FormControl(''),
})
adjustSelectWidth(e){
const optionValue = this.profileForm.get('members').value;
const optionText = document.querySelector(`option[value="${optionValue}"]`).innerHTML;
this.temp = optionText;
const spanWidth = document.querySelector(`.temp`).clientWidth;
e.style.width = spanWidth + "px";
}
}
Since im using angular, i prefer not to use JQuery. Additionally, why the clientWidth
seem to not solve my problem here
I created a stackbliz example: https://stackblitz.com/edit/angular-bbimkz
There is a way to measure text width. I think it is sufficiently reliable, but might be a bit expensive in terms of performance, depending on your app of course. (The simplistic example in Stackblitz has no performance problem.)
The method is to actually append a hidden element to the document containing the text you want to measure, read the clientWidth
, and remove the element immediately.
Modify adjustSelectWidth()
as follows:
adjustSelectWidth(e: HTMLSelectElement){
// assuming something is always selected, please test!
const displayedText = e.options[e.selectedIndex].innerText;
const dummy = document.createElement('div');
dummy.innerText = displayedText;
dummy.style.position = 'absolute';
dummy.style.visibility = 'hidden';
document.body.insertBefore(dummy, document.body.firstChild);
const measuredWidth = dummy.clientWidth;
document.body.removeChild(dummy);
e.style.width = (measuredWidth + 30) + 'px'
}
Modified Stackblitz: https://stackblitz.com/edit/angular-mpjxbd?file=src/app/app.component.ts - tested in latest Firefox, Chrome, Edge