Abrir formulario detalle desde un botón

Introducción

En este ejercicio se mostrará como, seleccionando una fila de una tabla, podremos abrir el formulario detalle.

Crear el botón y redirigir el formulario

En primer lugar, añadiremos un nuevo botón a la pestaña de las cuentas de un cliente

customers-detail.component.html

<o-form attr="customerDetail" service="customers" entity="customer" keys="CUSTOMERID" header-actions="R;I;U;D"
    show-header-navigation="no" class="fill-form">
    <o-text-input attr="CUSTOMERID" sql-type="INTEGER" enabled="no"></o-text-input>
    <div fxFlex fxLayout="row" fxLayoutGap="8px">
        <div>
            <o-image id="CUSTOMER_PHOTO" attr="PHOTO" empty-image="assets/images/no-image.png"
                sql-type="OTHER"></o-image>
        </div>
        <mat-tab-group fxFlex>
            <mat-tab label="{{ 'CUSTOMER_PERSONAL_INFORMATION' | oTranslate }}">
                <div fxLayout="row" fxLayoutGap="8px">
                    <o-text-input fxFlex="40" attr="NAME" required="yes"></o-text-input>
                    <o-text-input fxFlex="40" attr="SURNAME" required="yes"></o-text-input>
                    <o-date-input fxFlex="20" attr="STARTDATE"></o-date-input>
                </div>
                <div fxLayout="row" fxLayoutGap="8px">
                    <o-nif-input fxFlex="40" attr="ID" required="yes"></o-nif-input>
                    <o-integer-input fxFlex="40" attr="PHONE" step="0" thousand-separator=" "></o-integer-input>
                    <o-combo fxFlex="20" attr="CUSTOMERTYPEID" service="customers" entity="customerType"
                        keys="CUSTOMERTYPEID" columns="CUSTOMERTYPEID;DESCRIPTION" visible-columns="DESCRIPTION"
                        value-column="CUSTOMERTYPEID"></o-combo>
                </div>
                <o-email-input attr="EMAIL"></o-email-input>
                <o-text-input attr="ADDRESS"></o-text-input>
                <div fxLayout="row" fxLayoutGap="8px">
                    <o-real-input fxFlex="50" attr="LONGITUDE" decimal-separator="," max-decimal-digits="10"
                        min-decimal-digits="0"></o-real-input>
                    <o-real-input fxFlex="50" attr="LATITUDE" decimal-separator="," max-decimal-digits="10"
                        min-decimal-digits="0"></o-real-input>
                </div>
                <o-textarea-input attr="COMMENTS"></o-textarea-input>
            </mat-tab>
            <mat-tab label="{{ 'ACCOUNTS' | oTranslate }}">
                <o-table #accountCustomerTable attr="accountsTable" service="customers" entity="vCustomerAccount"
                    keys="ACCOUNTID" parent-keys="CUSTOMERID" insert-button="no" refresh-button="no" detail-mode="none"
                    delete-button="no" query-rows="20"
                    columns="CUSTOMERID;ACCOUNTID;ENTITYID;OFFICEID;CDID;ANID;STARTDATE;ENDDATE;INTERESRATE;ACCOUNTTYP"
                    visible-columns="ACCOUNTNUMBER;STARTDATE;ENDDATE;INTERESRATE;INTERESRATE_MONTHLY;ACCOUNTTYP">
                    <o-table-button attr="openAccount" (onClick)="openAccountDetailSelected()"
                        label="{{ 'OPEN_ACCOUNT_SELECTED' | oTranslate }}" icon="credit_card"></o-table-button>
                    <o-table-column attr="STARTDATE" title="STARTDATE" type="date" format="LL"></o-table-column>
                    <o-table-column attr="ENDDATE" title="ENDDATE" type="date" format="LL"></o-table-column>
                    <o-table-column attr="INTERESRATE" title="INTERESRATE" type="percentage" width="150px"
                        decimal-separator="," content-align="center"></o-table-column>
                    <o-table-column attr="ACCOUNTNUMBER" title="ACCOUNTNUMBER" content-align="center">
                        <app-account-number-render></app-account-number-render>
                    </o-table-column>
                    <o-table-column-calculated attr="INTERESRATE_MONTHLY" title="INTERESRATE_MONTHLY"
                        [operation-function]="intRateMonthly" type="percentage" decimal-separator=","
                        content-align="center">
                    </o-table-column-calculated>
                </o-table>
            </mat-tab>
        </mat-tab-group>
    </div>
</o-form>

En el fichero *.ts, creamos una nueva función que se invocará desde el botón del html y al hacer click, obtendrá el valor del identificador de la cuenta, y navegará hasta el elemento correspondiente en el módulo de accounts

customers-detail.component.ts

import { Component, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { OTableComponent } from 'ontimize-web-ngx';
import { intRateMonthlyFunction } from 'src/app/shared/shared.module';

@Component({
  selector: 'app-customers-detail',
  templateUrl: './customers-detail.component.html',
  styleUrls: ['./customers-detail.component.css']
})
export class CustomersDetailComponent {

  @ViewChild('accountCustomerTable') accountTable: OTableComponent;
  public intRateMonthly = intRateMonthlyFunction;

  constructor(
    private router: Router
  ) { }

  public openAccountDetailSelected() {
    let selected = this.accountTable.getSelectedItems();
    if (selected.length === 1) {
      let accountId = selected[0]['ACCOUNTID']
      this.router.navigate(['main/accounts/' + accountId]);
    }
  }

}

Añadimos las traducciones del botón:

en.json

{
  ...
  "OPEN_ACCOUNT_SELECTED": "Open Account Selected"
}

es.json

{
  ...
  "OPEN_ACCOUNT_SELECTED": "Abrir cuenta seleccionada"
}

Abrir el nuevo componente sin cambiar de módulo

En primer lugar, dado que vamos a reutilizar el componente detalle de cuentas cuentas para abrirlo dentro del módulo de clientes, es necesario que lo quitemos de la declaración del modulo de accounts, y los pasemos al módulo shared

accounts.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { OntimizeWebModule } from 'ontimize-web-ngx';
import { AccountsRoutingModule } from './accounts-routing.module';
import { AccountsHomeComponent } from './accounts-home/accounts-home.component';
import { SharedModule } from 'src/app/shared/shared.module';
import { AccountsNewComponent } from './accounts-new/accounts-new.component';
import { AddCustomerComponent } from './add-customer/add-customer.component';
import { AddMovementComponent } from './add-movement/add-movement.component';


@NgModule({
  declarations: [
    AccountsHomeComponent,
    AccountsNewComponent,
    AddCustomerComponent,
    AddMovementComponent
  ],
  imports: [
    CommonModule,
    SharedModule,
    OntimizeWebModule,
    AccountsRoutingModule
  ]
})
export class AccountsModule { }

shared.module.ts

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { OntimizeWebModule } from 'ontimize-web-ngx';
import { AccountNumberRenderComponent } from '../main/accounts/accounts-home/account-number-render/account-number-render.component';
import { CustomertypeColumnRendererComponent } from '../main/customers/customers-home/customertype-column-renderer/customertype-column-renderer.component';
import { MovementColumnRendererComponent } from '../main/accounts/accounts-detail/movement-column-renderer/movement-column-renderer.component';
import { MENU_COMPONENTS } from './app.menu.config';
import { OChartModule } from 'ontimize-web-ngx-charts';
import { AccountsDetailComponent } from '../main/accounts/accounts-detail/accounts-detail.component';

export function intRateMonthlyFunction(rowData: Array<any>): number {
  return rowData["INTERESRATE"] / 12;
}

@NgModule({
  imports: [
    OntimizeWebModule,
    OChartModule
  ],
  declarations: [
    AccountNumberRenderComponent,
    CustomertypeColumnRendererComponent,
    MovementColumnRendererComponent,
    ...MENU_COMPONENTS,
    AccountsDetailComponent
  ],
  exports: [
    CommonModule,
    AccountNumberRenderComponent,
    CustomertypeColumnRendererComponent,
    MovementColumnRendererComponent,
    ...MENU_COMPONENTS,
    OChartModule,
    AccountsDetailComponent
  ]
})
export class SharedModule { }

Indicaremos cual es la nueva ruta que se usará para el componente

customers-routing.module.ts

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CustomersHomeComponent } from './customers-home/customers-home.component';
import { CustomersDetailComponent } from './customers-detail/customers-detail.component';
import { CustomersNewComponent } from './customers-new/customers-new.component';
import { AccountsDetailComponent } from '../accounts/accounts-detail/accounts-detail.component';

const routes: Routes = [{
  path: '',
  component: CustomersHomeComponent
},
{
  path: "new",
  component: CustomersNewComponent
},
{
  path: ':CUSTOMERID',
  component: CustomersDetailComponent
},
{
  path: ":CUSTOMERID/:ACCOUNTID",
  component: AccountsDetailComponent
}];

@NgModule({
  imports: [RouterModule.forChild(routes)],
  exports: [RouterModule]
})
export class CustomersRoutingModule { }

Modificamos la funciona para que añada los elementos que faltan y que se modifique la ruta para navegar al nuevo componente

customers-detail.component.ts

import { Component, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { OTableComponent } from 'ontimize-web-ngx';
import { intRateMonthlyFunction } from 'src/app/shared/shared.module';

@Component({
  selector: 'app-customers-detail',
  templateUrl: './customers-detail.component.html',
  styleUrls: ['./customers-detail.component.css']
})
export class CustomersDetailComponent {

  @ViewChild('accountCustomerTable') accountTable: OTableComponent;
  public intRateMonthly = intRateMonthlyFunction;

  constructor(
    private router: Router
  ) { }

  public openAccountDetailSelected() {
    let selected = this.accountTable.getSelectedItems();
    if (selected.length === 1) {
      let accountId = selected[0]['ACCOUNTID'];
      let customerId = selected[0]['CUSTOMERID'];
      this.router.navigate(['main/customers/' + customerId + '/' + accountId], { queryParams: { isdetail: true } });
    }
  }

}

Abrir el formulario sin necesidad de botón

Únicamente es necesario cambiar el evento de de detalle de la tabla de cuentas, y pasar de none a dblclick para que también funcione la navegación en la tabla. Aprovecharemos para añadir al formulario el atributo #form

customers-detail.component.html

<o-form #form attr="customerDetail" service="customers" entity="customer" keys="CUSTOMERID" header-actions="R;I;U;D"
    show-header-navigation="no" class="fill-form">
    <o-text-input attr="CUSTOMERID" sql-type="INTEGER" enabled="no"></o-text-input>
    <div fxFlex fxLayout="row" fxLayoutGap="8px">
        <div>
            <o-image id="CUSTOMER_PHOTO" attr="PHOTO" empty-image="assets/images/no-image.png"
                sql-type="OTHER"></o-image>
        </div>
        <mat-tab-group fxFlex>
            <mat-tab label="{{ 'CUSTOMER_PERSONAL_INFORMATION' | oTranslate }}">
                <div fxLayout="row" fxLayoutGap="8px">
                    <o-text-input fxFlex="40" attr="NAME" required="yes"></o-text-input>
                    <o-text-input fxFlex="40" attr="SURNAME" required="yes"></o-text-input>
                    <o-date-input fxFlex="20" attr="STARTDATE"></o-date-input>
                </div>
                <div fxLayout="row" fxLayoutGap="8px">
                    <o-nif-input fxFlex="40" attr="ID" required="yes"></o-nif-input>
                    <o-integer-input fxFlex="40" attr="PHONE" step="0" thousand-separator=" "></o-integer-input>
                    <o-combo fxFlex="20" attr="CUSTOMERTYPEID" service="customers" entity="customerType"
                        keys="CUSTOMERTYPEID" columns="CUSTOMERTYPEID;DESCRIPTION" visible-columns="DESCRIPTION"
                        value-column="CUSTOMERTYPEID"></o-combo>
                </div>
                <o-email-input attr="EMAIL"></o-email-input>
                <o-text-input attr="ADDRESS"></o-text-input>
                <div fxLayout="row" fxLayoutGap="8px">
                    <o-real-input fxFlex="50" attr="LONGITUDE" decimal-separator="," max-decimal-digits="10"
                        min-decimal-digits="0"></o-real-input>
                    <o-real-input fxFlex="50" attr="LATITUDE" decimal-separator="," max-decimal-digits="10"
                        min-decimal-digits="0"></o-real-input>
                </div>
                <o-textarea-input attr="COMMENTS"></o-textarea-input>
            </mat-tab>
            <mat-tab label="{{ 'ACCOUNTS' | oTranslate }}">
                <o-table #accountCustomerTable attr="accountsTable" service="customers" entity="vCustomerAccount"
                    keys="ACCOUNTID" parent-keys="CUSTOMERID" insert-button="no" refresh-button="no"
                    detail-mode="dblclick" delete-button="no" query-rows="20"
                    columns="CUSTOMERID;ACCOUNTID;ENTITYID;OFFICEID;CDID;ANID;STARTDATE;ENDDATE;INTERESRATE;ACCOUNTTYP"
                    visible-columns="ACCOUNTNUMBER;STARTDATE;ENDDATE;INTERESRATE;INTERESRATE_MONTHLY;ACCOUNTTYP">
                    <o-table-button attr="openAccount" (onClick)="openAccountDetailSelected()"
                        label="{{ 'OPEN_ACCOUNT_SELECTED' | oTranslate }}" icon="credit_card"></o-table-button>
                    <o-table-column attr="STARTDATE" title="STARTDATE" type="date" format="LL"></o-table-column>
                    <o-table-column attr="ENDDATE" title="ENDDATE" type="date" format="LL"></o-table-column>
                    <o-table-column attr="INTERESRATE" title="INTERESRATE" type="percentage" width="150px"
                        decimal-separator="," content-align="center"></o-table-column>
                    <o-table-column attr="ACCOUNTNUMBER" title="ACCOUNTNUMBER" content-align="center">
                        <app-account-number-render></app-account-number-render>
                    </o-table-column>
                    <o-table-column-calculated attr="INTERESRATE_MONTHLY" title="INTERESRATE_MONTHLY"
                        [operation-function]="intRateMonthly" type="percentage" decimal-separator=","
                        content-align="center">
                    </o-table-column-calculated>
                </o-table>
            </mat-tab>
        </mat-tab-group>
    </div>
</o-form>

arrow_back Tutorial anterior Próximo tutorial arrow_forward