2

I am making a select-box (select + options).

In the select component I have a list of option component instances :

@ContentChildren(forwardRef(() => SelectOptionComponent)) private options: QueryList<SelectOptionComponent>;

Also I know which one option is selected so I have a

private selectedOption: SelectOptionComponent;

attribute. Now I would like to display the selected option into the select-box main top frame (what remains of the select box when it's option list is closed). As I want to display any content and not only text, I would like to "copy" the option dom node and insert that into the main frame.

I tried several approaches without any success but I have the feeling that should be possible. Any clue ?

5
  • Something like that ? Commented Dec 10, 2018 at 8:30
  • @trichetriche Yes, but using an existing component instance instead of instantiating a new one. I've already use that method elsewhere by the way. Commented Dec 10, 2018 at 9:18
  • 1
    You could play on its position and container overflown properties, like material selects do Commented Dec 10, 2018 at 10:16
  • That is a good idea but I want to be sure there is no clean alternative before doing that Commented Dec 10, 2018 at 10:18
  • Well you have several solutions, such as using injectors to get the component instance, you can also use your @ContentChildren to get it, but in every way, you will have to copy that instance a second time to display it (unless you move it, as proposed earlier) Commented Dec 10, 2018 at 10:25

2 Answers 2

1

I'm just sort of thinking aloud, but:

  1. Inject ElementRef into the SelectOptionComponent and make it public.
  2. Inject ElementRef into your select component.
  3. Add a setter function to selectedOption in the select component that, when triggered, does selectedOption.el.nativeElement. // gets dom node and copies it to wherever you want it copied to in the select component's dom (using the ElementRef of the select component).

i.e.

private _selectedOption: SelectedOptionComponent;

set selectedOption(option: SelectedOptionComponent) {
  this._selectedOption = option;

  // do other stuff as needed
  // e.g:
  // this.el.nativeElement.querySelector('').appendChild(option.el.nativeElement)
}

Obviously, this won't be Angular Universal / SSR friendly. Personally, I wouldn't touch the dom directly. Instead I might use the angular renderer to insert the component in the dom. Or, more likely, I'd simply use ngIf to toggle a special "selected" component / view.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I was trying a solution with Renderer2, I'll let you know the result. I think I tried it before but I couldn't clone the element.
0
export class SelectOptionComponent {
    constructor(public elt: ElementRef) { }

Then

export class SelectBoxComponent {
@ViewChild('label', {read: ElementRef}) labelNode: ElementRef;
private selectedOption: SelectOptionComponent;

constructor(private renderer: Renderer2) {}
...

private updateLabel() {
    Array.from(this.labelNode.nativeElement.children).forEach(child => {
        this.renderer.removeChild(this.labelNode.nativeElement, child);
    });
    if (this.selectedOption) {
        let cloned = this.selectedOption.elt.nativeElement.cloneNode(true);
        this.renderer.appendChild(this.labelNode.nativeElement, cloned);
    }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.