Cómo utilizar el servicio de transacciones

    Puede aprovechar el Transaction Service cuando utilice cualquier componente que necesite preservar el estado de su fuente de datos y realizar muchas transacciones a la vez.

    Cuando trabaje con la Ignite UI for Angular, puede usar igxTransactionService e igxHierarchicalTransactionService que están integrados con las cuadrículas y brindan edición por lotes lista para usar. Sin embargo, si necesita usar transacciones con cualquier otra Ignite UI for Angular o un componente personalizado, puede volver a usar igxTransactionService e implementar un comportamiento similar.

    Angular How to use the Transaction service Example

    En este tema usaremos el componente igxList para demostrar cómo habilitar transacciones. Demostraremos cómo agregar transacciones, cómo transformar los datos a través de una tubería y cómo actualizar visualmente la vista para permitir al usuario ver los cambios que están a punto de confirmarse.

    Include Transaction Service

    Include Transaction Service in project

    Tenemos dos opciones para incluir IgxTransactionService en nuestra aplicación. La primera es agregarlo a AppModule u otro módulo principal en la aplicación, como se hace en la demostración anterior:

    @NgModule({
        ...
        providers: [
            IgxTransactionService
        ]
    })
    export class AppModule { }
    

    La otra opción es proporcionarlo en el componente donde se utiliza el servicio de transacciones:

    @Component({
        selector: 'transaction-base',
        styleUrls: ['./transaction-base.component.scss'],
        templateUrl: 'transaction-base.component.html',
        providers: [IgxTransactionService]
    })
    export class TransactionBaseComponent { }
    

    Inject Transaction Service in component

    En nuestro archivo ts, debemos importar igxTransactionService de la biblioteca igniteui-angular, así como las interfaces State y Transaction y la enumeración TransactionType, que será necesaria para nuestra aplicación:

    import { IgxTransactionService, State, Transaction, TransactionType } from 'igniteui-angular';
    // import { IgxTransactionService, State, Transaction, TransactionType } from '@infragistics/igniteui-angular'; for licensed package
    

    Luego, Transaction Service debe importarse en el constructor:

    constructor(private _transactions: IgxTransactionService<Transaction, State>) { ... }
    

    Define igxList

    En nuestra plantilla html, definimos un componente igxList con acciones editar, eliminar y agregar, que modifican la lista y sus elementos:

    <igx-list>
        <igx-list-item [isHeader]="true">Wishlist</igx-list-item>
        <igx-list-item *ngFor="let item of this.wishlist | transactionBasePipe"
            [ngClass]="{ deleted: isDeleted(item.id), edited: isEdited(item.id) }">
            <p igxListLineTitle>{{item.name}}</p>
            <p igxListLineSubTitle>Costs: {{item.price}}</p>
            <igx-icon igxListAction (click)="onEdit()" *ngIf="item.id === 1 && item.price !== '$999'">edit</igx-icon>
            <igx-icon igxListAction (click)="onDelete()" *ngIf="item.id === 2 && !isDeleted(item.id)">delete</igx-icon>
        </igx-list-item>
        <button igxButton (click)="onAdd()" [disabled]="itemAdded(4)">Add New</button>
    </igx-list>
    

    Pipe for pending changes

    El componente de lista anterior utiliza transactionBasePipe para mostrar cambios en los elementos de la lista de deseos sin afectar los datos originales. Así es como se ve la tubería:

    @Pipe({
        name: 'transactionBasePipe',
        pure: false
    })
    export class TransactionBasePipe implements PipeTransform {
        /**
         * @param transactions Injected Transaction Service.
         */
        constructor(public transactions: IgxTransactionService<Transaction, State>) { }
    
        public transform(data: WishlistItem[]) {
            // the pipe should NOT operate on the original dataset
            // we create a copy of the original data and then use it for visualization only
            const _data = [...data];
            const pendingStates = this.transactions.getAggregatedChanges(false);
    
            for (const state of pendingStates) {
                switch (state.type) {
                    case TransactionType.ADD:
                        // push the newValue property of the current `ADD` state
                        _data.push(state.newValue);
                        break;
                    case TransactionType.DELETE:
                        // pipe doesn't delete items because the demo displays them with a different style
                        // the record will be deleted once the state is committed
                        break;
                    case TransactionType.UPDATE:
                        const index = _data.findIndex(x => x.id === state.id);
                        // merge changes with the item into a new object
                        // to avoid modifying the original data item
                        _data[index] = Object.assign({}, _data[index], state.newValue);
                        break;
                    default:
                        return _data;
                }
            }
    
            return _data;
        }
    }
    

    Edit, delete, add functionality

    Define edit functionality

    El segundo elemento de la lista contiene un botón de edición, que actualiza los datos del elemento.

    <igx-icon igxListAction (click)="onEdit()" *ngIf="item.id === 1 && item.price !== '$999'">edit</igx-icon>
    

    Cuando se presiona el botón, dentro del controlador de eventos onEdit, se crea una transacción 'ACTUALIZAR':

    public onEdit(): void {
        const newPrice = "$999";
        // there can be multiple `UPDATE` transactions for the same item `id`
        // the `newValue` property should hold only the changed properties
        const editTransaction: Transaction = {
            id: this.wishlist[0].id,
            type: TransactionType.UPDATE,
            newValue: { price: newPrice }
        };
        // provide the first wishlist item as a `recordRef` argument
        this.transactions.add(editTransaction, this.wishlist[0]);
    }
    

    Además, hay una función que verifica los elementos en busca de ediciones no guardadas:

    public isEdited(id): boolean {
        const state = this.transactions.getState(id);
        return state && state.type === TransactionType.UPDATE;
    }
    

    Define delete functionality

    El tercer elemento de la lista contiene un botón de eliminación, que elimina los datos del elemento.

    <igx-icon igxListAction (click)="onDelete()" *ngIf="item.id === 2 && !isDeleted(item.id)">delete</igx-icon>
    

    Cuando se presiona el botón, dentro del controlador de eventos onDelete, se crea una transacción 'ELIMINAR':

    public onDelete(): void {
        // after a `DELETE` transaction, no further changes should be made for the same `id`
        // the `newValue` property should be set to `null` since we do not change any values,
        const deleteTransaction: Transaction = {
            id: this.wishlist[1].id,
            type: TransactionType.DELETE,
            newValue: null
        };
        // provide the second wishlist item as a `recordRef` argument
        this.transactions.add(deleteTransaction, this.wishlist[1]);
    }
    

    Además, existe una función que comprueba si los elementos se han eliminado sin guardar:

    public isDeleted(id): boolean {
        const state = this.transactions.getState(id);
        return state && state.type === TransactionType.DELETE;
    }
    

    Define add functionality

    Al final de la lista se agrega un botón AGREGAR, que agrega un nuevo elemento a la lista.

    <button igxButton (click)="onAdd()" [disabled]="itemAdded(4)">Add New</button>```
    

    Cuando se presiona el botón, dentro del controlador de eventos onAdd, se crea una transacción 'ADD':

    public onAdd(): void {
        // it must have a unique 'id' property
        const item: WishlistItem = { id: 4, name: 'Yacht', price: 'A lot!' };
    
        // in an `ADD` transaction you do not need to provide a `recordRef` argument,
        // since there is nothing to refer to yet
        this.transactions.add({ id: 4, type: TransactionType.ADD, newValue: item });
    }
    

    Además, hay una función que comprueba si hay elementos añadidos no guardados:

    public itemAdded(id: number): boolean {
        const found = this.transactions.getState(id) || this.wishlist.find(x => x.id === 4);
        return !!found;
    }
    

    Transaction Log

    La demostración muestra las transacciones pendientes dentro de un registro:

    <div>
        <h5>Transaction Log</h5>
        <div *ngFor="let transaction of this.getTransactionLog()">
            {{transaction.type.toUpperCase()}} -> {{transaction.name}} Costs: {{transaction.price}}
        </div>
    </div>
    
    public getTransactionLog(): any[] {
        return this.transactions.getTransactionLog().map(transaction => {
            const item = this.wishlist.find(x => x.id === transaction.id);
            return Object.assign({ type: transaction.type }, item, transaction.newValue);
        });
    }
    

    También agregaremos una representación del estado actual de nuestra lista. Mostrará cómo se ven los datos antes de que se confirmen las transacciones pendientes:

    <div>
        <h5>Data Items</h5>
        <div *ngFor="let item of this.wishlist">
            <div>{{item.name}} - {{item.price}}</div>
        </div>
    </div>
    

    Commit pending transactions

    Una vez que hayamos terminado con todos nuestros cambios, podemos confirmarlos todos a la vez usando el método commit de igxTransactionService. Aplica todas las transacciones sobre los datos proporcionados:

    <button igxButton="contained" (click)="onCommit()" [disabled]="this.getTransactionLog().length === 0">Commit Transactions</button>
    
    public onCommit(): void {
        // the `commit` function expects the original data array as its parameter
        this.transactions.commit(this.wishlist);
    }
    
    

    Si usamos igxHierarchicalTransactionService también podemos usar una sobrecarga del método commit que espera PrimaryKey y ChildDataKey como argumentos.

    public onCommit(): void {
        this.transactions.commit(this.wishlist, primaryKey, childDataKey);
    }
    

    Clear pending transactions

    En cualquier punto de nuestra interacción con la lista, podemos borrar el registro de transacciones utilizando el método clear.

    <button igxButton="contained" (click)="onClear()" [disabled]="this.getTransactionLog().length === 0">Clear Transactions</button>
    
    public onClear(): void {
        this.transactions.clear();
    }
    
    

    Additional Resources