Como usar o serviço de transação
You may get advantage of the Transaction Service when using any component that needs to preserve the state of its data source and to commit many transactions at once.
When working with the Ignite UI for Angular grid components, you may use the igxTransactionService and igxHierarchicalTransactionService that are integrated with the grids and provide batch editing out of the box. However, if you need to use transactions with any other Ignite UI for Angular or custom component, you may again use the igxTransactionService and implement similar behavior.
Angular How to use the Transaction service Example
In this topic we will use igxList component to demonstrate how to enable transactions. We will demonstrate how to add transactions, how to transform the data through a pipe and how to visually update the view in order to let the user see the changes that are about to be committed.
Include Transaction Service
Include Transaction Service in project
We have two options to include IgxTransactionService in our application. The first one is to add it to AppModule or other parent module in the application, as it is done in the demo above:
@NgModule({
...
providers: [
IgxTransactionService
]
})
export class AppModule { }
A outra opção é fornecê-lo no componente onde o serviço de transação é usado:
@Component({
selector: 'transaction-base',
styleUrls: ['./transaction-base.component.scss'],
templateUrl: 'transaction-base.component.html',
providers: [IgxTransactionService]
})
export class TransactionBaseComponent { }
Inject Transaction Service in component
In our ts file, we should import igxTransactionService from the igniteui-angular library, as well as the State and Transaction interfaces and the TransactionType enum, which will be needed by our application:
import { IgxTransactionService, State, Transaction, TransactionType } from 'igniteui-angular/core';
// import { IgxTransactionService, State, Transaction, TransactionType } from '@infragistics/igniteui-angular'; for licensed package
Então o Transaction Service deve ser importado no construtor:
constructor(private _transactions: IgxTransactionService<Transaction, State>) { ... }
Define igxList
In our html template, we define an igxList component with edit, delete and add actions, which modify the list and its items:
<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
The list component from above uses the transactionBasePipe to display changes to the items in the wishlist without affecting the original data. Here is how the pipe looks like:
@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
O segundo item da lista contém um botão de edição, que atualiza os dados do item.
<igx-icon igxListAction (click)="onEdit()" *ngIf="item.id === 1 && item.price !== '$999'">edit</igx-icon>
When the button is pressed, inside the onEdit event handler, an 'UPDATE' transaction is created:
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]);
}
Além disso, há uma função que verifica itens em busca de edições não salvas:
public isEdited(id): boolean {
const state = this.transactions.getState(id);
return state && state.type === TransactionType.UPDATE;
}
Define delete functionality
O terceiro item da lista contém um botão de exclusão, que exclui os dados do item.
<igx-icon igxListAction (click)="onDelete()" *ngIf="item.id === 2 && !isDeleted(item.id)">delete</igx-icon>
When the button is pressed, inside onDelete event handler, a 'DELETE' transaction is created:
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]);
}
Além disso, há uma função que verifica se há itens excluídos não salvos:
public isDeleted(id): boolean {
const state = this.transactions.getState(id);
return state && state.type === TransactionType.DELETE;
}
Define add functionality
No final da lista, é adicionado um botão ADICIONAR, que adiciona um novo item à lista.
<button igxButton (click)="onAdd()" [disabled]="itemAdded(4)">Add New</button>```
When the button is pressed, inside the onAdd event handler, an 'ADD' transaction is created:
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 });
}
Além disso, há uma função que verifica itens em busca de adições não salvas:
public itemAdded(id: number): boolean {
const found = this.transactions.getState(id) || this.wishlist.find(x => x.id === 4);
return !!found;
}
Transaction Log
A demonstração demonstra as transações pendentes dentro de um log:
<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);
});
}
Também adicionaremos uma representação do estado atual da nossa lista. Ela mostrará como os dados parecem antes das transações pendentes serem confirmadas:
<div>
<h5>Data Items</h5>
<div *ngFor="let item of this.wishlist">
<div>{{item.name}} - {{item.price}}</div>
</div>
</div>
Commit pending transactions
Once we are done with all our changes, we may commit them all at once using the commit method of the igxTransactionService. It applies all transactions over the provided data:
<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);
}
If we are using the igxHierarchicalTransactionService we can also use an overload of the commit method which expects primaryKey and childDataKey as arguments.
public onCommit(): void {
this.transactions.commit(this.wishlist, primaryKey, childDataKey);
}
Clear pending transactions
At any point of our interaction with the list, we may clear the Transaction log, using the clear method.
<button igxButton="contained" (click)="onClear()" [disabled]="this.getTransactionLog().length === 0">Clear Transactions</button>
public onClear(): void {
this.transactions.clear();
}