3

I having an array of objects which I am passing to the ng-options,the array contains objects of currencies in the next pattern:

[{
        "cur_iso": "ILS",
            "cur_symbol": "\u20aa",
            "cur_name_he": "\u05e9\u05e7\u05dc",
            "cur_rate_in_nis": "1.0000",
    }, {
        "cur_iso": "USD",
            "cur_symbol": "$",
            "cur_name_he": "\u05d3\u05d5\u05dc\u05e8",
            "cur_rate_in_nis": "3.8580"
    }]

I am using ng-options to make a select from this array.

<select ng-model="bindCurrencyModel" ng-init="bindCurrencyModel='ILS'" 
ng-options="currency.cur_iso as currency.cur_symbol+' '+currency.cur_name_he for currency in currencies track by currency.cur_iso" 
                    ng-change="setCurrency(currency)">
</select>   

when user is changing the selection I want to update 2 fields: bindCurrencyModel with the cur_iso value and bindRateModel with the cur_rate_in_nis value.

so I had created the next method:

            $scope.setCurrency=function(currency){
                $scope.bindRateModel=parseFloat(currency.cur_rate_in_nis);
            };

the and set ng-change="setCurrency(currency)" but the problem is I am getting:

   TypeError: Cannot read property 'cur_rate_in_nis' of undefined

another strange behavior is empty line I am getting in the beginning of the select.

to see all the code I had created a fiddle....

http://jsfiddle.net/d9esbgjf/5/

THANKS!

Wazime
  • 1,423
  • 1
  • 18
  • 26

4 Answers4

4

The short version is as follows:

Change your <select> markup to the following:

<select ng-model="selectedCurrency" ng-init="selectedCurrency=currencies[0]" 
    ng-options="currency as currency.cur_symbol+' '+currency.cur_name_he for currency in currencies track by currency.cur_iso" 
    ng-change="setCurrency(selectedCurrency)">
</select>

Change your $scope.setCurrency() method to the following:

$scope.setCurrency = function (currency) {
    $scope.bindRateModel = parseFloat(currency.cur_rate_in_nis);
    $scope.bindCurrencyModel = currency.cur_iso;
};

Why does this work?

The first difference is that I am binding the whole currency object to a new selectedCurrency scope property. This gives you access to the whole object, not just the cur_iso property. This saves you having to look through the currencies array to find the full object.

Then I changed the ng-change expression to pass in this whole object to $scope.setCurrency using the scope property that it is bound to. This allows that method access to the full object.

Finally, you need to set $scope.bindCurrencyModel inside the $scope.setCurrency() function, so that it will equal just the field that you are interested in.

GregL
  • 37,147
  • 8
  • 62
  • 67
  • Thanks, but I need `bindCurrencyModel` to have only the currency cur_iso, this code is part of a directive, and the directive expose it to the controller whom expect the bindCurrencyModel to be string of currency ISO. – Wazime Mar 03 '15 at 18:15
  • @Wazime I changed my answer to accommodate your needs. – GregL Mar 03 '15 at 18:20
1

You're doing some strange things here, I think you could simplify it a lot.

Firstly, setCurrency(currency) will be evaluated against the scope. As you never define a field currency on the scope then this will always be undefined.

You're using a lot of extra variables to reference properties that you could just reference directly. Cleaning this up would make your life much simpler.

Instead of your approach, consider this:

<select
  ng-model="selectedCurrency"
  ng-options="currency as currency.cur_symbol + ' '
              + currency.cur_name_he for currency in currencies">

We removed ng-change and make the selectedCurrency the model, which references the whole currency object not just the ISO symbol.

Now you can do this:

<input type="number" 
       ng-model="selectedCurrency.cur_rate_in_nis">

And {{selectedCurrency.cur_iso}} for example would be the ISO code.

Finally to remove the blank line at the start of the select, initialise the value.. e.g.:

$scope.currencies = [{
    "cur_iso": "ILS",
        "cur_symbol": "\u20aa",
        "cur_name_he": "\u05e9\u05e7\u05dc",
        "cur_rate_in_nis": 1.0000,
        "cur_last_update": "",
        "cur_order": "1",
        "cur_available": "1"
}, {
    "cur_iso": "USD",
        "cur_symbol": "$",
        "cur_name_he": "\u05d3\u05d5\u05dc\u05e8",
        "cur_rate_in_nis": 3.8580,
        "cur_last_update": "2015-02-24 13:34:25",
        "cur_order": "2",
        "cur_available": "1"
}];
// Initialise value so select is initially selected on something.
$scope.selectedCurrency = $scope.currencies[0]

Hopefully you see that this jsfiddle is a lot neater and much easier to follow than your original approach.

Ed_
  • 18,798
  • 8
  • 45
  • 71
  • Some good points here, your approach is cleaner. You need to address the requirement (which was added to the question later) about setting `$scope.bindCurrencyModel` and `$scope.bindRateModel`, though. – GregL Mar 03 '15 at 18:24
  • Thanks, but this code is part of directive which exposes `bindCurrencyModel` and `bindRateModel ` to the controller. the controller is expecting to get **bindCurrencyModel** as string of the curency and **bindRateModel** as the rate of the currency. – Wazime Mar 03 '15 at 18:26
  • I missed that part of the question, apologies. However I would still argue you should pass the values you want those models bound to to the directive, rather than have the directive rely on a specific controller structure. Just makes it more repeatable. – Ed_ Mar 03 '15 at 19:55
0

I believe your setCurrency() method won't have access to currency, only the usual scope variables. In this case the bindCurrencyModel variable could be used.

Timothy Walters
  • 16,866
  • 2
  • 41
  • 49
  • 10x, but, bindCurrencyModel should get the currency code (the option value) not the currency object. – Wazime Mar 03 '15 at 18:08
  • @Wazime That doesn't make sense. You need the full object from the `currencies` array in order to access the `cur_rate_in_nis` property on that object. If you only pass the function the currency code, then you need to look up the full object in the `currencies` array _first_, then you can access the other property you need on it (`cur_rate_in_nis`). – GregL Mar 03 '15 at 18:12
0

Update your ng-options to read:

ng-options="currency as currency.cur_symbol+' '+currency.cur_name_he for currency in currencies track by currency.cur_iso"

This will populate your model with the full object you are expecting in the setCurrency function.

nweg
  • 2,825
  • 3
  • 22
  • 30
  • ok, but then the bindCurrencyModel get's the selected currency object while I want it to get only the value (cur_iso) – Wazime Mar 03 '15 at 18:11
  • You can access the cur_iso property by using bindCurrencyModel.cur_iso in your controller. You need the whole object the way your setCurrency function is coded. – nweg Mar 03 '15 at 18:14
  • thanks, I know, I thought I'll might find a way to separate the select model from the array of the currencies... – Wazime Mar 03 '15 at 18:17
  • You can do that, but then you would have to update your setCurrency function so that it doesn't expect the whole object coming in – nweg Mar 03 '15 at 18:21