Question

I have the following data:

var purchases=[
  {
    store: 'John Lewis Store',
    place: 'London, UK',
    numberOfItems: 14,
    moneySpent: 7500
  }, {
    store: 'Wal-Mart Store',
    place: 'San Francisco, USA',
    numberOfItems: 7,
    moneySpent: 4290
  }
...
];

As you see above, the moneySpent is stored in US $ and I want to display the records in the following format:

John Lewis Store
London, UK
€3067.7
7 items bought

If you look at the third row above, the US $ value is first converted to Euro € and then displayed. I also want that the search filter should be applied to the Euro value and not to the US $ value.

Implementing the filter functionality is not that easy. I cannot apply a simple filter on the ng-repeat like this:

ng-repeat="purchase in purchaseRecords | filter: searchString"

If I do so, Angular compares the search string text with the US$ values held in the purchase records. But the money spent being displayed in the view is in the Euro € currency now. As a result, the filter does not work correctly.

Again ... I want that the filter should be applied to the Euro values and not to the US $ values. How can I achieve this? Pl. guide me.

1 Answers

I am using this library for currency conversion: http://openexchangerates.github.io/money.js/

Using its fx() function, you can convert your USD amount to EUR like this:

fx(parseFloat(moneySpentInSourceCurrency)).from('USD').to('EUR')

Use the filter() function to register a custom filter fn named currencyConversion. The second argument to filter() is a factory function that accepts the Angular $filter service. Let this factory function return a new instance of the custom filter fn that accepts the following arguments: a value that holds the money spent in source currency (moneySpentInSourceCurrency), a string that identifies the source currency, and a string that identifies the target currency.

The custom filter fn does the following: i. Convert the US$ amount to EUR using the fx() function described above. ii. Use the $filter service to invoke the built-in 'currency' filter and format the converted value as the € currency. Round the value to 2 decimal places.

When you display the moneySpent while iterating the purchase records, invoke the currencyConversion() filter with the following arguments: a. source currency = 'USD' b. target currency = 'EUR' c. Note that the moneySpent is passed implicitly which is the value that Angular applies the filter on.

To make the filter work correctly (what you want to achieve), define the searchCriteriaMatch() function as a property of the $scope object of the controller. This function accepts the sourceCurrency and targetCurrency as parameters.

In its body, return an instance of an anonymous function that accepts the 'purchase' (record) as the parameter.

In the body of the anonymous function, do the following:

i. Return true if any of these 'store', 'place', or the 'numberOfItems' properties of the purchase (record) "contains" the string that the user entered into the input search field. The comparison is case sensitive.

ii. Convert the moneySpent value of the purchase (record) to EUR€ currency using the fx() function in the same way as we did before. Make sure that you must round the value to 2 decimal places. If you do not round it, the filter won't work correctly. If the resultant rounded value "contains" the string that the user entered into the input search field, return true.

<div class="row">
    <div class="col-sm-4">
        <input placeholder="Enter your search text here" ng-model="searchString" />
    </div>
</div>

<div class="row" ng-controller="MyController">
      //Invoke the searchCriteriaMatch('USD', 'EUR') filter
    <div class="col-sm-3" ng-repeat="purchase in purchaseRecords | filter: searchCriteriaMatch('USD', 'EUR')">
        <h3>{{purchase.store}}</h3>
        <h4>{{purchase.place}}</h4>
        <h4>{{purchase.moneySpent | currencyConversion: 'USD': 'EUR'}}</h4>
        <h4>{{purchase.numberOfItems + " items bought"}}</h4>
    </div>
</div>


//Initialize the currency rates
fx.base = "USD";
fx.rates = {
    "EUR" : 0.915692, //eg. 1 USD = 0.915692 EUR
    "GBP" : 0.647710,
    ...
}
var currency_symbols = {
    'USD': '$', // US Dollar
    'GBP': '£', // British Pound Sterling
    ...
};

app.controller('MyController', function ($scope) {
  $scope.purchaseRecords = purchases;

  $scope.searchCriteriaMatch = function (sourceCurrency, targetCurrency) {
    //This returns another function which has the parameters (sourceCurrency and targetCurrency) in its scope as well as the original 'purchase' record coming from the filter.
    return function(purchase) {

      //When the page is opened, we know that the input search field is empty. If you want that 'all' the purchase items should be displayed when the page is opened for the first time or when the search field is empty (null), return true.
      if ($scope.searchString == null)
        return true;
      else {
        var moneySpentInTargetCurrency = fx(parseFloat(purchase.moneySpent)).from(sourceCurrency).to(targetCurrency).toFixed(2);
        return purchase.store.indexOf($scope.searchString) > -1 || purchase.place.indexOf($scope.searchString) > -1 || purchase.numberOfItems.toString().indexOf($scope.searchString) > -1 || moneySpentInTargetCurrency.toString().indexOf($scope.searchString) > -1;
      }
    }
  };
});

app.filter("currencyConversion", function($filter) {
  return function(moneySpentInSourceCurrency, sourceCurrency, targetCurrency) {
    var moneySpentInTargetCurrency = fx(parseFloat(moneySpentInSourceCurrency)).from(sourceCurrency).to(targetCurrency);
    formattedTargetMoney = $filter('currency')(moneySpentInTargetCurrency, currency_symbols[targetCurrency], 2);
    return formattedTargetMoney;
  };
});