Kesem David Kesem David - 2 months ago 14
HTML Question

Angular2 event called only on SOME of the elements

So i have a Modal Component with a form in it, this component is used for both creating an entry to the DB and editing an existing one.

It has a subscription option to the

onSubmit
event, which is being executed on a successful submit.

What happens for some reason is that some of this component's element subscription executes and some won't, and it looks like those on the "create-mode" will and those on the "edit-mode" wont.

Code Section



CreateOrUpdateTransactionComponent:

@Component({
selector: 'create-update-transaction',
templateUrl: './CreateOrUpdateTransaction.html',
providers: [AccountTransactionsService]
})
export class CreateOrUpdateTransactionComponent {
closeResult: string;
modalRef: NgbModalRef;

@Input() transaction: Transaction = new Transaction();
@Input() isCreate: boolean;
@Output() onSubmit: EventEmitter<void> = new EventEmitter<void>();

constructor(private modalService: NgbModal,
private transactionsService: AccountTransactionsService) {}

sendTransaction(): void{
let localModalRef = this.modalRef;
this.transactionsService.createOrUpdateTransaction(this.transaction, (isSuccessful)=>{
if (isSuccessful) {
this.onSubmit.emit(); //<--- The problem is here
localModalRef.close();
}
});
}
}


The HTML:

<table>
<caption>Account Transactions</caption>
<thead>
// Omitted thead
</thead>
<template let-transaction ngFor [ngForOf]="accountTransactions" let-i="index">
<tr data-toggle="collapse" [attr.data-target]="'#'+i">
// Omitted <td>s
<td> //<----These updateTransactions() are not being executed
<create-update-transaction [isCreate]="false" [transaction]="transaction" (onSubmit)="updateTransactions()"></create-update-transaction>
</td>
</tr>
<div class="container collapse" [attr.id]="i">
// some content
</div>
</template>
</table>
<create-update-transaction [isCreate]="true" (onSubmit)="updateTransactions()"></create-update-transaction>
//<---- This updateTransactions() successfully executes


Notice




  • If I only display one row in the table not using
    ngFor
    (keeping the call to the back-end to update the DB), it works perfectly fine.



Any idea why would this happen?

Thanks in advance!

Update1



Debugging i could notice that when on the create-mode the
this.onSubmit.observers
is an array with one observer and on the edit-mode its an array with 0 observers, so thats the problem. any idea why?

Update2



Debugging again and found that the
this
in
this.transactionsService.createOrUpdateTransaction...
is fine and its'
onSubmit.observers
contains 1 observer, before reaching the callback's code, in which the
this.onSubmit.observers
is an array of 0 observers

AccountTransactionsService:

@Injectable()
export class AccountTransactionsService{
private loggedBankAccount: number;
private queryObservable: ObservableQuery;

constructor(private userManagingService: UserManagingService) {
this.loggedBankAccount = userManagingService.getLoggedBankAccountNumber();

this.queryAccountTransactions();
}

queryAccountTransactions(): void{
this.queryObservable = // querying the back-end
}

createOrUpdateTransaction(transaction: Transaction, callback: (isSuccessfull: boolean) => void): void{
let isSuccessful: boolean = false;

client.mutate(/*inserting the backend*/).then((graphQLResult) => {
const { errors, data } = graphQLResult;

if (data) {
console.log('got data', data);
isSuccessful = true;
}

if (errors) {
console.log('got some GraphQL execution errors', errors);
}

callback(isSuccessful);
}).catch((error) => {
console.log('there was an error sending the query', error);
callback(isSuccessful);
});
}

getAccountTransactions(): ObservableQuery{
return this.queryObservable;
}
}


Notice




  • If i just execute the callback give to the
    AccountTransactionService.createOrUpdateTransaction
    (removing the call to the back-end to actually update the DB) it works perfectly fine and all the subscribers to this
    onSubmit
    event are being called.



this
Console image



enter image description here

Answer

So I found out the case was that the data the ngFor is bound to was being replaced by a new instance as I updated the backend, hence, it rerendered it's child Components causing reinitializing (destory + init) of them, which made the instance of the Component to be overwritten.

In order to solve this issue i have changed the querying of the accountTransaction to be only one time querying, on initializing of the parent component, and never refetching again (which triggers the rerendering).

Im displaying to the client the changes only if they succeeded on the server side, and if they failed i use a backup of the data, so the client is kept update of the real state of the server WITHOUT refetching

For the future lookers to come:

The key to the problem was that the Parent Component's *ngFor depended on data that was changing in the Child Components, causing reinitializing of the *ngFor (the Child Components) BEFORE finishing executions of the Child Components methods.

Hope it'll be helpful to somebody :)