5

Background

On page load I am making a http get call to obtain some data.

There is a form on the page which submits new data to the APi. The response does not hold the new updated data but the data exist in the database after the form is submitted.

I need to access the data by making a second api call after the form is submitted.

Question

After the form is submitted, how do I make the initial API call again to retrieve current data and then update my view component with it?

Code

On page load I call this function inside

Initial call to retrieve data

ngOnInit() { this.getPaymentMethods() }

Function definition

private getPaymentMethods() {
            let params: URLSearchParams = new URLSearchParams();
            params.set('api_key', this.apiKeyData);
            params.set('email', this.auth.user.email);
            return this.http.get(STATICS.API_BASE + STATICS.API_ALL_PAYMENT_METHODS,
                { search: params })
                .map((res: Response) => res.json()).subscribe((res) => {
                    localStorage.setItem('payment_profiles', JSON.stringify(res.payment_profiles));
                });
        }

Handling Response From Initial Call

Parsing the data object response

this.PaymentMethodKeys = Object.keys(this.pMethodsData);

Inside the view I display the data like this

<div *ngFor="let key of PaymentMethodKeys">
{{pMethodsData[key].card_no}}
{{pMethodsData[key].payment_profile_id}}
</div>

This is the form that is submitted to add new data to database

    saveCreditCard(model: Payment, isValid: boolean) {
            let params: URLSearchParams = new URLSearchParams();
            params.set('api_key', this.apiKeyData);
            params.set('email', model.email);

   params.set('u_address', model.street_address);
            params.set('u_city', model.city_address);

            return this.http.get(STATICS.API_BASE + STATICS.API_PAY_METHOD,
                { search: params })
                .map((res: Response) => res.json())
                .subscribe((res) => {
                    console.log(res);
                });
        }
    }

I think part of my problem is that I am getting the keys from the object inside the constructor. So I think I keep trying to make this work but the only way it will update the keys is when the component refreshes so the constructor will run again.

Any help would be appreciated.

11
  • Can you show how you're assigning data to pMethodsData? Commented Mar 8, 2017 at 7:58
  • I can see two ways to deal with this issue. Suggestion one, you return the fresh new created data in your response and push it in the PaymentMethodKeys array. Second, you return new PaymentMethodKeys array with fresh data. (or 3, router.navigate() to reconstruct the component ?) Commented Mar 8, 2017 at 8:28
  • Of course, I don't know how far along you are with your project, or how committed you are to your API, but if you're really interested in rendering database changes to your view in real time and leveraging the full power of observables you should look into Firebase and AngularFire 2. If you were using Firebase's real-time database, you could simply subscribe to the paymentMethods node and any time it changed, it would immediately render in the client's view--in all clients' views with no need to make any other calls. Commented Mar 8, 2017 at 14:57
  • Interesting. Thanks for that I will read about it right now. I keep having problems like this. Since I started using NG2. Updating components with changes like this has been my only real issue to understand. Commented Mar 8, 2017 at 14:58
  • The reason for this is probably that you are using observables in a way that you might typically use promises or callbacks. Observables can be streams that constantly emit updated items to their observers, which you can render in real time, but http responses are one-shot deals. Rendering data from http responses simply does not take full advantage of the tech you have at your disposal with Angular 2 and observables. Commented Mar 8, 2017 at 15:16

1 Answer 1

2

We discussed Subjects, but that's not necessary. It's sufficient to render the observable in the view and simply pass it new data each time you update your database.

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/take';

private paymentMethods: Observable<any>;

private getPaymentMethods() { 
    let params: URLSearchParams = new URLSearchParams(); 
    params.set('api_key', this.apiKeyData); 
    params.set('email', this.auth.user.email); 
    this.http.get(STATICS.API_BASE + STATICS.API_ALL_PAYMENT_METHODS, 
    { search: params }) 
    .map((res: Response) => res.json()) 
    .take(1) //Takes the first observable and unsubscribes
    .subscribe(res => this.paymentMethods = res.payment_profiles)
}

saveCreditCard(model: Payment, isValid: boolean) {
    let params: URLSearchParams = new URLSearchParams();
    params.set('api_key', this.apiKeyData);
    params.set('email', model.email);

    return this.http.get(STATICS.API_BASE + STATICS.API_PAY_METHOD,{ search: params }) 
    .map((res: Response) => res.json())
    .take(1)
    .subscribe((res) => {
        //Maybe make sure status is 200. 
        console.log(res); 
        this.getPaymentMethods(); 
    });
}

ngOnInit() { 
    this.getPaymentMethods()
}

Note that since we are subscribing to the results of getPaymentMethods() within the function, it's not necessary for it to return anything and, hence, not necessary for us to assign the returned Observable to paymentMethods within ngOnInit(). Whenever getPaymentMethods() is called (e.g., on the initial load and when saveCreditCard() is called) paymentMethods subscribes to the first response emitted and then unsubscribes with the take operator.

And in your view you'll notice we aren't using the async pipe anymore. Remember that the async pipe subscribes and unsubscribes. We are doing that manually, so there's no need for that.

<div *ngFor="let item of paymentMethods">
    {{item.card_no}}
</div>

Let me know how this works out.

Sign up to request clarification or add additional context in comments.

1 Comment

In the solution you have this, this.pmntMethodsSub I am not understanding what that is supposed to be. Is it just any variable I want to declare there or what?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.