1

I'd like to know the correct approach, how to update data-array after http post.

What I have is a transaction service with those methods:

getUserTransactions(user_id) {
    return this.http.get('http://localhost:3000/users/' + user_id + '/transactions', { headers: contentHeaders })
      .map(res => res.json());
  }

createTransaction(balance, amount, user_id, paymethod_id, redirect) {
    let body = JSON.stringify({ balance, amount, user_id, paymethod_id });
    this.http.post('http://localhost:3000/transactions', body, { headers: contentHeaders })
      .subscribe(
      response => {
        this.router.parent.navigateByUrl(redirect);
      },
      error => {
        alert(error.text());
        console.log(error.text());
      }
      );

and a component

export class HomeComponent {

  public transactions: Transaction[];

  constructor(
    private router: Router,
    private loginService: LoginService,
    private trnService: TransactionService
    ) {
    if (!loginService.isLoggedIn())
      this.router.parent.navigateByUrl('/logout');

    var userid = this.loginService.getUserId();
    this.trnService.getUserTransactions(userid).subscribe(transactions => this.transactions = transactions);

    return;
  }

  makeTransaction(){
    var userid = this.loginService.getUserId();
    this.trnService.createTransaction(10, 2, userid, 1, "/home");
  }

}

html:

<tbody>
    <tr *ngFor="#transaction of transactions; #index=index">
---

So first, by navigating to "/home" I am loading an array of user transactions.

by clicking a button, the makeTransaction() method is called. which executes a http post request by the service TransactionService -> createTransaction. I thought I would redirect to "/home" after transaction is successfully done, but this does not work.. ( I assume that the constructor is not called again.) may be I could update the public transactions: Transaction[]; from the service somehow? Maybe making a reference?

user1908375
  • 1,069
  • 1
  • 14
  • 33

1 Answers1

1

If you want to see the new transactions in the list of all transactions. You coud leverage a shared service that contains both the list and an observable to notify when a new transaction completed.

As a matter of fact, the transactions list in the component isn't linked to the "create transaction" calls.

Here is a sample implementation:

export class TransactionService {
  private transactionObservable:Observable<any>;
  private transactionObserver:Observer<any>;

  constructor() {
    this.transactionObservable((observer:Observer) => {
      this.transactionObserver = observer;
    }).share();
  }

  notifyTransactionCreated(transaction:any) {
    this.transactionObserver.next(transaction);
  }

  onTransactionCreated(callback:(transaction:any) => void) {
    this.transactionObservable.subscribe(callback);
  }

  (...)

createTransaction(balance, amount, user_id, paymethod_id, redirect) {
  let body = JSON.stringify({ balance, amount, user_id, paymethod_id });
  this.http.post('http://localhost:3000/transactions', body, { headers: contentHeaders })
    .subscribe(
      response => {
        this.notifyTransactionCreated(response.json()); // <------
        this.router.parent.navigateByUrl(redirect);
      },
      error => {
        alert(error.text());
        console.log(error.text());
      }
     );
   }
}

This way you can be notified within the component and update the transaction list:

export class HomeComponent {
  public transactions: Transaction[];

  constructor(
    private router: Router,
    private loginService: LoginService,
    private trnService: TransactionService
  ) {
    if (!loginService.isLoggedIn())
      this.router.parent.navigateByUrl('/logout');

    var userid = this.loginService.getUserId();
    this.trnService.getUserTransactions(userid).subscribe(transactions => {
      this.transactions = transactions;
    });

    this.trnService.onTransactionCreated(transaction => {
      this.transactions.push(transaction);
    });

    return;
  }

  makeTransaction(){
    var userid = this.loginService.getUserId();
    this.trnService.createTransaction(10, 2, userid, 1, "/home");
  }
}

To share a single instance of the service for the whole application, don't forget to specify the service when bootstrapping your application:

bootstrap(AppComponent, [
  HTTP_PROVIDERS,
  TransactionService
]);
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Thanks.. I got it.. General question: my other idea was to pass a reference to the Model into the Service, and then call a method on that Model( that would update transactions list again) is it possible to pass references to components/objects into services somehow? – user1908375 Mar 29 '16 at 10:40
  • Yes, you could do something like that. That being said, the observable-based approach is in general better since you can react on changes with your component. See this question: http://stackoverflow.com/questions/34376854/delegation-eventemitter-or-observable-in-angular2/35568924. – Thierry Templier Mar 29 '16 at 12:00