Tengo un componente angular que es un grid designer donde puedo editar celdas y renderizar componentes en ellas.Tiene una opción de multiselección para elegir varios componentes y después en el modo visualización elegir entre ellos con un ng-select, pero al elegir entre varios tiene que renderizar el primero de la lista por defecto.
El problema es que para renderizar ese componente, en createComponent tengo  kpiNumber = col.selectedContent.value; y necesito que sea así, pero en col.selectedContent se está metiendo solo un número sin array de label y value y necesito que se inserte también como array de label y value para que  kpiNumber = col.selectedContent.value; funcione.

import { Component, OnInit, ViewContainerRef, ViewChildren, QueryList, AfterViewInit, NgModule, HostListener, ViewChild, ElementRef,inject } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { NgxSpinnerModule, NgxSpinnerService } from 'ngx-spinner';


import * as ace from 'ace-builds';
import 'ace-builds/src-noconflict/mode-json';
import 'ace-builds/src-noconflict/theme-dracula';

import { GaugeComponent } from '../gauge/gauge.component';
import { DataGridComponent } from '../data-grid/data-grid.component';
import { KpiListComponent } from '../kpis/kpi-list.component';
import { KpiService } from '../../services/kpi.services'
import { NgSelectModule } from '@ng-select/ng-select';

@Component({
  selector: 'app-grid-designer',
  standalone: true,
  imports: [CommonModule, FormsModule, NgSelectModule, NgxSpinnerModule],
  templateUrl: './grid-designer.component.html',
  styleUrl: './grid-designer.component.scss'
})
export class GridDesignerComponent implements OnInit, AfterViewInit {
  @ViewChildren('dynamicComponentContainer', { read: ViewContainerRef }) dynamicComponentContainers!: QueryList<ViewContainerRef>;
  @ViewChild('contextMenu') contextMenuElement!: ElementRef;
  private kpiService = inject(KpiService);

  
  gridData: any[] = [];
  gridDataString: string = '';
  isHidden = false;
  jsonValid: boolean | null = null;
  private editor: ace.Ace.Editor | null = null;
  editingCell: any = null;
  contextMenuVisible = false;
  contextMenuX = 0;
  contextMenuY = 0;
  selectedCell: any = null;
  componentOptions: { label: string; value: any }[] = [];





  constructor(private http: HttpClient,
              private toastr: ToastrService,
              private spinner: NgxSpinnerService
  ) {}

  ngOnInit(): void {
    this.getListKPI()
    this.http.get('assets/grid-default.json').subscribe((data: any) => {
      this.gridData = this.initializeGridData(data);
      this.gridDataString = JSON.stringify(this.gridData, null, 2);
      this.updateEditorValue();
      this.configToastr();
    });
  }

  ngAfterViewInit(): void {
    this.initAceEditor();
    setTimeout(() => this.renderDynamicComponents(), 100);
  }

  getListKPI(): void {
    this.kpiService.getListKPI().subscribe(
      (data: any[]) => {        
        this.componentOptions = data.map(item => ({
          label: `kpi-${item.idKPI} - ${item.representacion} - ${item.nombre}`,
          value: item.idKPI
        }));                
      },
      (error: any) => {
        // Manejo de errores
      }
    );
  }
  

  onMultiselectionListChange(e:any, col:any){
  console.log("🔰 ~ onMultiselectionListChange ~ col:", col)
  console.log("🔰 ~ onMultiselectionListChange ~ e:", e)
  const { rowIndex, colIndex } = this.getCellIndices(col);
  this.renderDynamicComponents(rowIndex, colIndex);
  }
  
  getCellIndices(cell: any): { rowIndex: number, colIndex: number } {
    for (let i = 0; i < this.gridData.length; i++) {
      const row = this.gridData[i];
      const columns = row.columns;
      for (let j = 0; j < columns.length; j++) {
        if (columns[j] === cell) {
          return { rowIndex: i, colIndex: j };
        }
      }
    }
  
    return { rowIndex: -1, colIndex: -1 }; // Si no se encuentra
  }
  

  private initializeGridData(data: any[]): any[] {
    return data.map(row => ({
      ...row,
      columns: row.columns.map((col: any) => ({
        ...col,
        content: col.content || null,
        alternativeContent: null,
        showSwitch: false,        
        switchLeftText: 'Izquierda',  // texto por defecto
        switchRightText: 'Derecha',  // texto por edfecto
        switchActiveSide: 'left', // switch izquierdo por defecto
        multiSelection: false
      })),
      height: row.height || '20%',
    }));
  }

  private initAceEditor(): void {
    const editorElement = document.getElementById('editor');
    if (editorElement) {
      this.editor = ace.edit(editorElement);
      this.editor.setTheme('ace/theme/dracula');
      this.editor.session.setMode('ace/mode/json');
      this.editor.setOptions({
        fontSize: '14px',
        showPrintMargin: false,
        showGutter: true,
        highlightActiveLine: true,
        enableBasicAutocompletion: true,
        enableLiveAutocompletion: true,
        enableSnippets: true
      });

      this.updateEditorValue();

      this.editor.getSession().on('change', () => {
        this.gridDataString = this.editor?.getValue() ?? '';
        this.jsonValid=false;
      });
    } else {
      console.error('Error al inicializar el Editor Ace');
    }
  }

  onRightClick(event: MouseEvent, cell: any) {
    event.preventDefault();
    this.contextMenuVisible = true;
    this.contextMenuX = event.clientX;
    this.contextMenuY = event.clientY;
    this.selectedCell = cell;
  }

  @HostListener('document:click')
  onDocumentClick() {
    this.contextMenuVisible = false;
  }

  addColumnToRow() {
    if (this.selectedCell) {
      const rowIndex = this.gridData.findIndex(row => row.columns.includes(this.selectedCell));
      if (rowIndex !== -1) {
        const newColumn = { content: '', colSpan: 1, rowSpan: 1, isComponent: false, width: 'auto' };
        this.gridData[rowIndex].columns.push(newColumn);
        this.updateJsonAndEditor();
      }
    }
    this.contextMenuVisible = false;
  }

  changeRowHeight(event: Event, row: any) {
    const inputElement = event.target as HTMLInputElement;
    row.height = this.validateHeight(inputElement.value);
    this.updateJsonAndEditor();
  }

  private validateHeight(value: string): string {
    if (value.endsWith('px') || value.endsWith('%')) {
      return value;
    }
    const num = parseInt(value);
    if (isNaN(num)) return '20%';
    return `${Math.max(5, Math.min(100, num))}%`;
  }

  changeWidth(event: Event) {
    if (this.selectedCell) {
      const inputElement = event.target as HTMLInputElement;
      this.selectedCell.width = this.validateWidth(inputElement.value);
      this.updateJsonAndEditor();
    }
  }

  private validateWidth(value: string): string {
    if (value.endsWith('px') || value.endsWith('%')) {
      return value;
    }
    const num = parseInt(value);
    if (isNaN(num)) return '100%';
    return `${Math.max(10, Math.min(100, num))}%`;
  }

  adjustWidth(change: number) {
    if (this.selectedCell) {
      if (!this.selectedCell.width || this.selectedCell.width === 'auto') {
        this.selectedCell.width = '100%';
      }

      if (this.selectedCell.width.endsWith('px')) {
        const currentPx = parseInt(this.selectedCell.width);
        this.selectedCell.width = `${Math.max(50, currentPx + change)}px`;
      } else {
        const currentPercent = parseInt(this.selectedCell.width);
        this.selectedCell.width = `${Math.max(10, Math.min(100, currentPercent + change))}%`;
      }
      this.updateJsonAndEditor();
    }
  }

  adjustRow(row: any, change: number) {
    if (!row.height || row.height === 'auto') {
      row.height = '20%';
    }

    if (row.height.endsWith('px')) {
      const currentPx = parseInt(row.height);
      row.height = `${Math.max(50, Math.min(900, currentPx + change))}px`;
    } else {
      const currentPercent = parseInt(row.height);
      row.height = `${Math.max(5, Math.min(100, currentPercent + change))}%`;
    }
    this.updateJsonAndEditor();
  }


  getSelectedRow(): any {
    return this.gridData.find(row => row.columns.includes(this.selectedCell));
  }

  adjustColSpan(change: number) {
    if (this.selectedCell) {
      this.selectedCell.colSpan = Math.max(1, (this.selectedCell.colSpan || 1) + change);
      this.updateJsonAndEditor();
    }
  }

  adjustRowSpan(change: number) {
    if (this.selectedCell) {
      this.selectedCell.rowSpan = Math.max(1, (this.selectedCell.rowSpan || 1) + change);
      this.updateJsonAndEditor();
    }
  }

  deleteCell() {
    if (this.selectedCell) {
      const rowIndex = this.gridData.findIndex(row => row.columns.includes(this.selectedCell));
      if (rowIndex !== -1) {
        const columnIndex = this.gridData[rowIndex].columns.indexOf(this.selectedCell);
        this.gridData[rowIndex].columns.splice(columnIndex, 1);
        if (this.gridData[rowIndex].columns.length === 0) {
          this.gridData.splice(rowIndex, 1);
        }
        this.updateJsonAndEditor();
      }
    }
    this.contextMenuVisible = false;
  }

  
  addRow() {
    const newRow = {
      height: '100px',
      columns: [{ content: '', colSpan: 1, rowSpan: 1, isComponent: false, width: '100%' }]
    };
    this.gridData.push(newRow);
    this.updateJsonAndEditor();
  }

  addColumn() {
    this.gridData.forEach(row => {
      row.columns.push({ content: '', colSpan: 1, rowSpan: 1, isComponent: false });
    });
    this.updateJsonAndEditor();
  }

   updateJsonAndEditor() {
    this.gridDataString = JSON.stringify(this.gridData, null, 2);
    this.updateEditorValue();
    //setTimeout(() => this.renderDynamicComponents() );
  }

  private updateEditorValue(): void {
    if (this.editor && this.gridDataString) {
      this.editor.setValue(this.gridDataString);
      this.editor.clearSelection();
    }
  }


  configToastr(){
    this.toastr.toastrConfig.positionClass = 'toast-top-full-width';
    this.toastr.toastrConfig.extendedTimeOut = 0;
    this.toastr.toastrConfig.timeOut = 2900;
  }

  toggleSidebar() {
    this.isHidden = !this.isHidden;
}

  getGridTemplateColumns(columns: any[]): string {
    return columns.map(col => col.width).join(' ');
  }

  getGridTemplateRows(): string {
    return this.gridData.map(row => row.height).join(' ');
  }

  validateAndApplyJson() {
    try {
      const parsedData = JSON.parse(this.gridDataString);
      this.gridData = parsedData;
      this.jsonValid = true;
      setTimeout(() => this.renderDynamicComponents(), 100);
    } catch (error) {
      this.jsonValid = false;
      this.toastr.warning(`Error al procesar el JSON: ${error}`, 'Advertencia');
    }
  }

  renderDynamicComponents(specificRowIndex?: number, specificColIndex?: number): void {    
    console.log("🔰 ~ renderDynamicComponents ~ specificRowIndex:", specificRowIndex, "specificColIndex:", specificColIndex);
    setTimeout(() => {
      if (!this.dynamicComponentContainers) return;
  
      let containerIndex = 0;
      this.gridData.forEach((row, rowIndex) => {
        row.columns.forEach((col: any, colIndex: number) => {
          if (col.isComponent) {
            if (specificRowIndex === undefined || (rowIndex === specificRowIndex && colIndex === specificColIndex)) {
              const container = this.dynamicComponentContainers.get(containerIndex);
              if (container) {
                container.clear();
                this.createComponent(col.content, container, col, rowIndex, colIndex);
              }
            }
            containerIndex++;
          }
        });
      });
    }, 100);
  }

  
  
  

  async createComponent(componentName: string[], container: ViewContainerRef, col: any, rowIndex: number, colIndex: number): Promise<void> {
    console.log("🔰 ~ createComponent ~ col:", col)
    console.log("🔰 ~ createComponent ~ componentName:", componentName)
    this.spinner.show();
    try {
      const spinnerName = `spinner-${rowIndex}-${colIndex}`;
      this.spinner.show(spinnerName);
      

      // const kpiNumber = componentName[0]; // Extract the number from the array
      let kpiNumber;

      if (col.multiSelection) {
        // En multiselección, usamos el selectedContent
        kpiNumber = col.selectedContent.value;
        console.log("🔰 ~ createComponent ~ kpiNumber:", kpiNumber)
      } else {
        // Verificamos si el switch está activo y usamos el contenido correspondiente
        if (col.showSwitch) {
          if (col.switchActiveSide === 'left') {
            kpiNumber = col.content[0];
          } else {
            kpiNumber = col.alternativeContent[0];
          }
        } else {
          kpiNumber = col.content[0];
        }
      }
      console.log("🔰 ~ createComponent ~ kpiNumber:", kpiNumber)
  
  
      
      const ComponentType = await this.loadDynamicComponent(`kpi-${kpiNumber}`);
      const componentRef = container.createComponent(ComponentType);
  
      (componentRef.instance as any).kpiNumber = kpiNumber;
  
      // Verificamos si el componente tiene representación de tarjeta
      if ((componentRef.instance as any).isCard) {        
        col.isCard = true;
      } else {
        col.isCard = false;
      }
  
      this.spinner.hide(spinnerName);

    } catch (error) {
      this.spinner.hide(`spinner-${rowIndex}-${colIndex}`);

      this.toastr.error(`Error al crear el componente: ${componentName}`);
    } finally {
      // this.spinner.hide(); // ocultar el spinner
    }
      
  }
  

private async loadDynamicComponent(componentName: string): Promise<any> {
    const kpiNumber = parseInt(componentName.split('-')[1]);    
    const kpiRequest = {
        fechaDesde: "2023-01-01",
        fechaHasta: "2023-12-31",
        listKpi: [kpiNumber],
        sucursales: ""
    };
    
    const data = await this.kpiService.getKPI(kpiRequest).toPromise();
    console.log("🔰 ~ loadDynamicComponent ~ data:", data)

    let representacion: string | null = null;

    if (data.representacion) {
        representacion = data.representacion;
    }

    if (!representacion) {
        this.toastr.error(`No se encuentra "representacion" en el json para: ${componentName}`);
        throw new Error(`No se encuentra "representacion" en el json para: ${componentName}`);
    }

    const module = await import(`../kpi-components/kpi-${representacion}/kpi-${representacion}.component`);
    return module[`Kpi${this.pascalCase(representacion)}Component`];
}



  // convertir a pascalcase el string para que funcione
  private pascalCase(str: string): string {
    return str.split('-').map(part => part.charAt(0).toUpperCase() + part.slice(1)).join('');
  }

  
  editKPI(col: any) {
    console.log("🔰 ~ editKPI ~ col:", col)
    if (Array.isArray(col.content)) {
      col.content = col.content.map((item: number) => `kpi-${item}`).join(', ');
    } else if (typeof col.content !== 'string' || !col.content.startsWith('kpi-')) {
      col.content = null;
    }
    
    col.switchLeftText = col.switchLeftText || 'Izquierda';
    col.switchRightText = col.switchRightText || 'Derecha';
    this.editingCell = col;
  }
  
    toggleSwitch(col: any) {            
      console.log("🔰 ~ toggleSwitch ~ col:", col)
      if (!col.showSwitch) {
        col.alternativeContent = null;
      }
      this.updateJsonAndEditor();
    }

    toggleMultiSelection(col: any) {
      col.multiSelection = !col.multiSelection;
    
      if (col.multiSelection) {
        // Aseguramos que col.content es un array y si no, se transforma
        if (!Array.isArray(col.content)) {
          col.content = col.content ? [col.content] : [];
        }
    
        // Actualizamos contentOptions para que tenga solo las opciones seleccionadas
        col.contentOptions = this.componentOptions.filter(option => col.content.includes(option.value));
    
        // Ponemos el [0] de selectedContent como el primer KPI seleccionado por defecto
        col.selectedContent = col.content[0] || null;
      } else {
        // // Fuera de multiselección, nos aseguramos de que col.content sea un array con solo un elemento
        // if (col.content && col.content.length > 0) {
        //   col.content = [col.content[0]];
        //   col.selectedContent = col.content[0];
        // } else {
        //   col.content = [];
        //   col.selectedContent = null;
        // }
    
        // Limpiamos 'contentOptions' ya que no se necesita en modo no multiselección
        col.contentOptions = [];
      }
    
      console.log("Multiselección ", col);
    }
 
  
    switchComponent(col: any, side: string) {
      // Intercambiamos las propiedades relacionadas al contenido principal y alternativo
      [col.content, col.alternativeContent] = [col.alternativeContent, col.content];
      [col.contentOptions, col.alternativeContentOptions] = [col.alternativeContentOptions, col.contentOptions];
      [col.selectedContent, col.alternativeSelectedContent] = [col.alternativeSelectedContent, col.selectedContent];
    
      col.switchActiveSide = side;
    
      // Obtener los índices de la celda
      const { rowIndex, colIndex } = this.getCellIndices(col);
    
      // Re-renderizar el componente
      this.renderDynamicComponents(rowIndex, colIndex);
    
      // Actualizar el JSON y el editor
      this.updateJsonAndEditor();
    }

    applyKPI() {
      if (this.editingCell.content) {
        let kpiNumbers = Array.isArray(this.editingCell.content)
          ? this.editingCell.content
          : [this.editingCell.content];
    
        // Convertir a números de KPI
        kpiNumbers = kpiNumbers.map((item:any) => this.extractKpiNumber(item.toString()));
        this.editingCell.content = kpiNumbers;
    
        if (this.editingCell.multiSelection) {
          console.log("ApplyKPI Multiselección");
          // Filtrar las opciones seleccionadas para contentOptions
          this.editingCell.contentOptions = this.componentOptions.filter(option => this.editingCell.content.includes(option.value));
          console.log("🔰 ~ applyKPI ~ this.editingCell.contentOptions:", this.editingCell.contentOptions)
          this.editingCell.selectedContent = kpiNumbers[0] || null;
          console.log("🔰 ~ applyKPI ~ this.editingCell.selectedContent :", this.editingCell.selectedContent )
        } else {
          this.editingCell.selectedContent = kpiNumbers[0] || null;
        }
      }
    
      // Procesar alternativeContent de manera similar
      if (this.editingCell.showSwitch && this.editingCell.alternativeContent) {
        let altKpiNumbers = Array.isArray(this.editingCell.alternativeContent)
          ? this.editingCell.alternativeContent
          : [this.editingCell.alternativeContent];
    
        // Convertir a números de KPI        
        altKpiNumbers = altKpiNumbers.map((item: any) => this.extractKpiNumber(item.toString()));

        this.editingCell.alternativeContent = altKpiNumbers;
    
        if (this.editingCell.multiSelection) {
          // Filtrar las opciones seleccionadas para alternativeContentOptions
          this.editingCell.alternativeContentOptions = this.componentOptions.filter(option => this.editingCell.alternativeContent.includes(option.value));
          this.editingCell.alternativeSelectedContent = altKpiNumbers[0] || null;
        } else {
          this.editingCell.alternativeSelectedContent = altKpiNumbers[0] || null;
        }
      }
    
      this.editingCell.isComponent = true;
    
      // Actualizar gridData y gridDataString
      const { rowIndex, colIndex } = this.getEditingCellIndices();
      let gridDataStringObj = JSON.parse(this.gridDataString);
    
      gridDataStringObj[rowIndex].columns[colIndex] = {
        ...gridDataStringObj[rowIndex].columns[colIndex],
        ...this.editingCell,
      };
    
      this.gridDataString = JSON.stringify(gridDataStringObj, null, 2);
      this.gridData[rowIndex].columns[colIndex] = gridDataStringObj[rowIndex].columns[colIndex];
    
      this.updateEditorValue();
      this.renderDynamicComponents(rowIndex, colIndex);
    
      this.editingCell = null;
    }

    getEditingCellIndices() {
      let rowIndex = -1;
      let colIndex = -1;
    
      for (let i = 0; i < this.gridData.length; i++) {
        const columns = this.gridData[i].columns;
        for (let j = 0; j < columns.length; j++) {
          if (columns[j] === this.editingCell) {
            rowIndex = i;
            colIndex = j;
            return { rowIndex, colIndex };
          }
        }
      }
    
      return { rowIndex, colIndex };
    }
 
    
    private extractKpiNumber(value: string | number): number {
      if (typeof value === 'number') {
        return value;
      }
      
      const match = value.match(/\d+/);
      return match ? parseInt(match[0], 10) : 0;
    }


}