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
- API de servicio de transacciones
- Servicio de transacciones
- Jerarquía de clases de servicios de transacciones