Akhil Sahu
Akhil Sahu

Reputation: 637

Invoke a components function from another in angular 4

There are two component one display total price and other has shipping method. These are implemented on the cart checkout page. When I change the shipping method. It needs to be reflected on on the total price of checkout component.

The following component displays the total price Here totalAmountWithDisocunt is the total price which need to be changed when shipping component radio button is selected check-out-product.component.ts

 
 
 import { Router,ActivatedRoute  } from '@angular/router';
@Component({
  selector: 'checkout-products',
  templateUrl: './check-out-products.component.html',
  styleUrls: ['./check-out-products.component.css']
})
export class CheckOutProductsComponent implements OnInit {
   
  totalAmountWithDisocunt = 0;
  constructor(public http: Http, public configz: ConfigService,
  public shared: DataService  ) { }

  ngOnInit() {
  	this.orderDetail = (JSON.parse(JSON.stringify(this.shared.orderDetails)));
    this.products = (JSON.parse(JSON.stringify(this.shared.cartProducts)));
    console.log(this.orderDetail);
    this.calculateTotal();
     
    }
  calculateDiscount = function () {
    var subTotal = 0;
    
    this.productsTotal = subTotal;
    this.discount = (subTotal - total);  
  };

   
  calculateTotal = function () {
    let a = 0;
    for (let value of this.products) {
       
      var subtotal = parseFloat(value.total);
      a = a + subtotal;
    }
   
    let b =  (this.orderDetail.tt);
    let c =  (this.orderDetail.shipping_cost );
    this.totalAmountWithDisocunt = a;
      
    this.calculateDiscount();
  };
}

check-out-product.component.html

<table class="mdl-data-table mdl-js-data-table oxy-full-width oxy-card-order__summary-table">
                                                 
                                                
                                               
                                                    <tr>
                                                        <td>Subtotal</td>
                                                        <td>  {{productsTotal| currencyChange}}</td>
                                                    </tr>
                                                      <tr>
                                                        <td>Tax</td>
                                                        <td> {{orderDetail.total_tax| currencyChange}}</td>
                                                    </tr>
                                                    <tr>
                                                        <td>Shipping</td>
                                                        <td>{{orderDetail.shipping_cost| currencyChange}}</td>
                                                    </tr>
                                                    <tr>
                                                        <td>Total</td>
                                                        <td>{{totalAmountWithDisocunt| currencyChange}}</td>
                                                    </tr>
                                               

The following is for shipping method component.When a radio button is clicked shipping method is selected and setMethod is called which should set the shipping price in above component.

import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import { ActivatedRoute } from '@angular/router';
@Component({
  selector: 'shipping-methods',
  templateUrl: './shipping-methods.component.html',
  styleUrls: ['./shipping-methods.component.css']
}) 
export class ShippingMethodsComponent implements OnInit {
 
  shippingMethod  ;
  selectedMethod = true;

  constructor(public http: Http,public configz: ConfigService,
  public shared: DataService ) { 
   }
  
  setMethod(data) {
  	 
    this.selectedMethod = false;
    this.shared.orderDetails.shipping_cost = data.rate;
    this.shared.orderDetails.shipping_method = data.name + '(' + data.shipping_method + ')';
    console.log(this.shared.orderDetails);
  }
 
  ngOnInit() {
  }

}
  
					<div class="mdl-card__supporting-text" >
  							<p>Shipping Methods</p>
  								<div  *ngFor="let m of shippingMethod">
                                                <h5  class="mdl-typography--title mdl-typography--font-light">{{m.name}}</h5 >

                                                <p   *ngFor="let s of m.services"  >

                                                    <label  class="mdl-radio mdl-js-radio mdl-js-ripple-effect" for="{{s.name}}">
                                                        <input  type="radio" id="{{s.name}}" [value]="s" (click)="setMethod(s)" class="mdl-radio__button" name="options"  checked />
                                                        <span class="mdl-radio__label">{{s.name+' ---- '+s.rate+' '+s.currencyCode}}
                                                </span>
                                                    </label>
                                                </p>
                                                
                                            </div>
                                        </div>

Now these are used on checkout page

 <checkout-products></checkout-products>
                                            <shipping-methods></shipping-methods>

When I change the shipping methods then checkout price does not changes

Upvotes: 0

Views: 58

Answers (2)

masterfloda
masterfloda

Reputation: 3038

Use a service. It looks like your DataService is provided globally and used in both components to store the orderDetails. Just move your calculation methods there and you can use this.shared.calculateTotal().

Alternatively, you can make the orderDetails in DataService an Observable (I'd suggest rxjs/BehaviorSubject). You can subscribe to it in CheckOutProductsComponent's ngOnInit.

DataService

orderDetailsObservable: BehaviorSubject<OrderDetailsInterface> = new BehaviorSubject(this.orderDetails);

CheckOutProductsComponent

ngOnInit() {
    this.shared.orderDetailsObservable.subscribe(
        next => {
                this.orderDetail = (JSON.parse(JSON.stringify(next)));
                this.calculateTotal();
            }
        );
    }

ShippingMethodsComponent

setMethod(data) {    
    this.selectedMethod = false;
    // get the existing orderDetails
    const orderDetails = this.shared.orderDetailsObservable.value;
    // override values
    orderDetails.shipping_cost = data.rate;
    orderDetails.shipping_method = data.name + '(' + data.shipping_method + ')';
    // update Observable
    his.shared.orderDetailsObservable.next(orderDetails);
}

Upvotes: 0

rijin
rijin

Reputation: 1759

I recommend Four ways : you can use which ever easy!

  1. using event emitter

     @Output() shipmentInfoEmitter: EventEmitter<any> = new EventEmitter();
    

    and when there is changes you can emit data

    this.shipmentInfoEmitter.emit(data);
    

    and you can consume by

    this.yourService.shipmentInfoEmitter.subscribe(user => this.updateUser(user));
    
  2. Talk to parent using @Input & @Output

    <parent>
      <checkout-products [update]="callParent($event)">
      </checkout-products>
    <shipping-methods [change]="products"></shipping-methods>
    

shipment method changes pass to parent and parent push to checkout details

  1. Use same service for storing this information

  2. Use Redux/ngrx

Upvotes: 1

Related Questions