heyred heyred - 7 months ago 84
Javascript Question

Validation on radio buttons with AngularJS

I have a cross platform app that uses AngularJS, Monaca and Onsen UI.

On one of my views I have an array of list items, and each list item can have have a random amount of radio buttons associated with it.

The list array is built at runtime from a JSON that is returned via an API call.
An example of my JSON is below:

[{
"fruitID": "1",
"fruitname": "Apple",
"options": [{
"optionID": "1",
"optiondescription": "Has seeds"
}, {
"optionID": "2",
"optiondescription": "Can be eaten raw"
}, {
"optionID": "3",
"optiondescription": "Has edible skin"
}]
}, {
"fruitID": "2",
"fruitname": "Banana ",
"options": [{
"optionID": "1",
"optiondescription": "Has no seeds"
}, {
"optionID": "2",
"optiondescription": "Can be eaten raw"
},
{
"optionID": "3",
"optiondescription": "Needs to be peeled"
},
{
"optionID": "4",
"optiondescription": "Short shelf life"
}]
}]


So for instance the list may contain a random number of fruit items and each fruit may have a random number of options associated with it. E.g.

- Apple (1)
-- Has seeds (1)
-- Can be eaten raw (2)
-- Has edible skin (3)


- Banana (2)
-- Has no seeds (1)
-- Can be eaten raw (2)
-- Needs to be peeled (3)
-- Short shelf life (4)


- Pineapple (3)
*-- Can be eaten raw (1)
-- Needs to be peeled (2)

For each fruit, the user must select one option. When the user selects an option, I need to save both the fruitID e.g. Banana (2) as well as the optionID e.g. Can be eaten raw (2) so that these values can be sent back to my Database as a JSON.

At the moment I register events on the radio buttons in my view via an ng-click() and pass the function in my controller the values of fruitID and optionID as follows:

<ul class="list">
<li class="list__item" ng-repeat="checkFruitDescription in data"> <!-- Where data is the JSON -->
<span class="list__item__line-height"><strong>{{checkFruitDescription.fruitname}}</strong></span>

<label class="radio-button" ng-repeat="option in checkFruitDescription.options">
<input type="radio"
name="option_question_id_{{checkFruitDescription.fruitID}}"
ng-model="checkFruitDescription.selected_id"
ng-click="doSomething(checkFruitDescription.fruitID, option.optionID)"
ng-value="option.optionID">
<div class="radio-button__checkmark"></div>

Description: {{option.optiondescription}}
</label>
</li>
</ul>


In my doSomething() function I want to save the values of fruitID and optionID for each radio button selected to an array (is this the best option?). However, I need to validate the radio buttons - so if the user select an option for Apples but then changes their mind, I need to update the values currently stored.

In my doSomething() function I tried:

$scope.selectedRadioArray = [];

$scope.doSomething = function(fruitID, optionID)
{
// Where data = JSON
if ($scope.data.fruitID.indexOf(fruitID) != -1)
{
// There is a match for fruitID in data.fruitID
// Save the values to an array
$scope.selectedIDS = [fruitID, optionID];

// Push the array to a new array
$scope.selectedRadioArray.push($scope.selectedIDS);
}
else
{
// Do something else
}
}


But I run into issues here. Saving the selectedIDS array to the selectedRadioArray works, but:


  • Sorting through the array to match the fruitID to the optionID becomes very difficult

  • If the user changes their mind and selects a new optionID for e.g. Apple, then the old value still remains in the database. I tried to implement the indexOF() function, but the issue there is that optionID is the same for a lot of the fruit options (1, 2, 3, ...). So if I check the indexOF() optionID for Apples it may return that it is already selected, even though it may be finding the value for Bananas.



What is the best way to handle validation on radio buttons and what is the best way to save the values that are returned on radio button clicks?

Answer

You can save yourself the hassle of manually picking out the fruitID and optionID by defining them as in one object in the ng-value of the radio buttons, like this:

ng-value="{fruit: checkFruitDescription.fruitID, option: option.optionID}"

this way the checkFruitDescription.selected_id holds both the fruitID and selected option. You can take it 1 step further and make an adjustment to the ng-model of the radio buttons to make the radio buttons function without writing any code in the controller:

ng-model="selectedArray[$parent.$index]"

Now the selectedArray contains all the results. Just keep in mind to create the selectedArray in your controller first. Here's a plunkr: http://plnkr.co/edit/IgpAXu8tbKUXj9ACPtZs?p=preview