I am new to Angular and am trying to build a simple app to teach myself. I have the following select options which are displaying just the keys of a data object so far. What I want to do is show a value underneath the second select box for each team, which shows the value associated with the key when a first option is selected, then adds to that value when the second option selected. How do I do that in angular?
I tried {{v}} for just the first one but that didn't work, and I would still need to add the second one.
<div>Team 1</div>
<br> Player 1:
<select class="form-control" ng-model="selectedItem1">
<option ng-repeat="(k,v) in data.playerInfo">{{k}}</option>
</select>
Player 2:
<select class="form-control" ng-model="selectedItem2">
<option ng-repeat="(k,v) in data.playerInfo">{{k}}</option>
</select>
<!-- show value here -->
<br>
<br>
<br>
<div>Team 2</div>
<br> Player 1:
<select class="form-control" ng-model="selectedItem3">
<option ng-repeat="(k,v) in data.playerInfo">{{k}}</option>
</select>Player 2:
<select class="form-control" ng-model="selectedItem4">
<option ng-repeat="(k,v) in data.playerInfo">{{k}}</option>
</select>
<!-- show value here -->
<div ng-show="k == v">{{v}}</div>
Values would go under the team two boxes.
UPDATE:
This worked for me!
$scope.calc = function() {
$scope.calculatedValue = Number($scope.selectedItem1);
if($scope.selectedItem2){
$scope.calculatedValue = Number($scope.selectedItem1) + Number($scope.selectedItem2);
}
}
$scope.calc2 = function() {
$scope.calculatedValue2 = Number($scope.selectedItem3);
if ($scope.selectedItem4) {
$scope.calculatedValue2 = Number($scope.selectedItem3) + Number($scope.selectedItem4);
};
}
<div>Team 1</div>
<br> Player 1:
<select class="form-control" ng-model="selectedItem1" ng-change="calc()">
<option ng-repeat="(k,v) in data.playerInfo" ng-value="v" >{{k}}</option>
</select>
Player 2:
<select class="form-control" ng-model="selectedItem2" ng-change="calc()">
<option ng-repeat="(k,v) in data.playerInfo" ng-value="v">{{k}}</option>
</select>
<!-- show value here -->
<p> Total Value: {{calculatedValue}} </p>
<br>
<br>
<br>
<div>Team 2</div>
<br> Player 1:
<select class="form-control" ng-model="selectedItem3" ng-change="calc2()">
<option ng-repeat="(k,v) in data.playerInfo" ng-value="v" >{{k}}</option>
</select>Player 2:
<select class="form-control" ng-model="selectedItem4" ng-change="calc2()">
<option ng-repeat="(k,v) in data.playerInfo" ng-value="v">{{k}}</option>
</select>
<!-- show value here -->
<p> Total Value: {{calculatedValue2}} </p>
I put together a fiddle based on your example. You need to add a change event to the select forms to tell your controller to calculate the values and create a new property on the $scope which stores the calculated value, which can be bound to in the html.
HTML
<select class="form-control" ng-model="selectedItem1" ng-change="calc()">
<option ng-repeat="(k,v) in data.playerInfo" ng-value="v">{{k}}</option>
</select>
JS
// these should be set to default number values
$scope.selectedItem1 = 0;
$scope.selectedItem2 = 0;
$scope.data = {
playerInfo : {
a:1,
b:2,
c:3
}
};
// this method will calculate the value
$scope.calc = function(){
$scope.calculatedValue = parseFloat($scope.selectedItem1) + parseFloat($scope.selectedItem2);
}
One thing to note, you need to set the default values of selectedItem1 and selectedItem2 or the change event won't know how to calculate the non-numeric undefined values of the unchanged selects.
Here is a working example based on your code:
https://jsfiddle.net/gu9fm5xh/1/
so a couple of things,
First: using ng-repeat in options is usually not they way you want to go, you want to use ng-options on the select element. But this isn't a major problem.
<select class="form-control" ng-options="data.displayValue for data in data.playerInfo" ng-model="selectedItem4">
This will show on the select "data.displayValue" which can be any property on the playerInfo object. And it will set selectedItem4 to the actual data object.
Second: In your div you are using the k and v variables that are in your ng-repeat. ng-repeat creates its own scope and the scope variables k and v are not accessible outside of your repeat and each ng-repeat uses its own k and v. If you want to use the selected values outside of the ng-repeat you need to set them to scope variable. luckily with option you can do this my setting the value field.
<option ng-repeat="(k,v) in data.playerInfo" ng-value="v">{{k}}</option>
ng-options does this for you behind the scenes. What this will do is bind your selects ng-model to the current option being shown. so if this option is under this select then selectedItem4 will be set to the value of the option selected.
<select class="form-control" ng-model="selectedItem4">
Meaning in your div if you change it to be
<div >{{selectedItem4}}</div>
This should work, a little better.
Related
The below is my 3 drop down section.I want to change in the 3rd drop down which having the values AND/OR. After changing the drop down there will be another clone of all the 3 same drop down filed will come and condition is only in the clone section for first select field the value shouldn't be there which was previously chosen(If I choosen Category in first select, then in the clone section for first select field there willn't be any Category section).
Also as per there is 3 option value in first select and those are (Category, Genre and Cast), so while on changing the AND/OR section we can only clone 2 more div, except the first one.
Also, if we already chosen Category section in first section and then we choose AND/OR option field then other 2 option will vanish from the first select field. Similarly it will proceed like this
I have got some how to clone it, but can't do exactly what our requirement. Below is my HTML and js code.
**HTML**
<div class="radio">
<input type="radio" id="test2" name="specific_content" value="2">
<label for="test2">
<div class="col-md-4">
<select class="form-control" id="content-form" name="content_form">
<option selected disabled hidden>Select</option>
<option value="category">Category</option>
<option value="genre">Genre</option>
<option value="cast">Cast</option>
</select>
</div>
<div class="col-md-4">
<select class="form-control content-type-section" id="content_type" name="content_type" disabled="disabled" onchange="removeDisableFromCondition(this)">
<option selected disabled hidden>Select</option>
<option value="123">Movie</option>
<option value="321">TV</option>
<option value="345">Cast</option>
<option value="987">Genre</option>
</select>
</div>
<div class="col-md-4">
<select class="form-control condition-section" id="sel1" name="conditions" disabled="disabled" onchange="showAnotherSection()">
<option selected disabled hidden>Select</option>
<option value="1">AND</option>
<option value="2">OR</option>
</select>
</div>
<div id="cloned_copy">
</div>
JS
$(document).ready(function() {
$('#sel1').change(function() {
var selectedVal = $('#content-form').val();
var target = $("#cloned_copy");
target.empty();
$("#content-form").clone().appendTo(target);
$("#cloned_copy option[value='"+ selectedVal +"']").remove();
});
});
After choosing AND/OR select drop down
I have a dropdown which uses ng-options (angular).
I have a default option selected with an empty value. (so it has the "selected" attribute and same value as the model)
Whenever I add another element to the ng-options, which is not empty, if the model has an empty value (which is pointing to the default empty option), the new added option is automatically selected.
The value of the model is still empty, but the dropdown now shows the new added option automatically.
I've also tried to make the default option be " " instead of just "", but it still does the same change.
Any way to guarantee new added options are not automatically selected?
`<select class="form-control section" ng-model="action.prop">
<option value="" disabled selected>Select Property</option>
<option ng-repeat="prop in tr.props| orderBy:prop.name"
value="{{prop.name}}"> {{prop.name}} </option>
</select>`
Try this :)
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<select ng-model="selectedName" ng-options="x for x in names">
</select>
<p>{{selectedName}}</p>
<button ng-click="add()">add</button>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.names = [""];
$scope.selectedName = $scope.names[0]
$scope.add = function() {
$scope.names.push("new");
}
});
</script>
</body>
</html>
You can simply just set your ng-model in the controller to the following before running your get dropdown function. This way it will always be set to default.
Controller
$scope.action = {};
$scope.action.prop = '';
Even though Roth's solution would work well in my case.
So would Nishant's if I used ng-options and a filter.
I decided instead, on the ng-repeat, to have an ng-if="prop.name != ''".
Since what was happening for me was that for about a second, ng-repeat would have latest prop with empty name for a second, and as ng-model = "", it was setting that option as selected.
<select class="form-control section" ng-model="action.prop">
<option value="" disabled selected>Select Property</option>
<option ng-if="prop.name != ''" ng-repeat="prop in tr.props| orderBy:prop.name"
value="{{prop.name}}"> {{prop.name}} </option>
</select>
Below is my code,
<div ng-dropdown-multiselect options="master_days_name" selected-model="selected_days_name" ></div>
<select name="end_time" ng-model="PostJobData.facility_hours.end_time" data-bvalidator="required" class="form-control" data-bvalidator-msg="Required">
<option value="">End Time</option>
<option ng-repeat = "val in time_array" value="{{val}}">{{val}}</option>
</select>
Add More
Current Result
Now I want, if user click to add more then this dropdown get repeated, with tuesday, wednesday, saturday, sunday(with uncheck values)
Add more functionality
<div class="row dobBlock" ng-repeat="(hours_key,hours_value) in PostJobData.facility_hours">
<div ng-dropdown-multiselect options="master_days_name" selected-model="selected_days_name" ></div>
</div>
Js code
$scope.PostJobData.facility_hours = [];
$scope.addMoreFacilityHours = function()
{
var temp = {'days':[],'start_time':'', 'end_time':'' };
$scope.PostJobData.facility_hours.push(temp);
console.log($scope.PostJobData.facility_hours);
}
But this giving same array clone means I want to show only uncheck option in second select box how can do this ?
Result
I would like to watch on select tag with ng-repeat and disable the save button.I have a set up like this.
Initially i will have three select boxes with values, where user has to select at least one select value out of three boxes to get Save btn enabled
user will also have a provision to add more select boxes.
Now,how do i watch the select boxes,if we have 5 select boxes -how can we watch all of them and enable/disable the Save button ,if none got selected.
Here is a fiddle link..similar to my situation: Js fiddle
Please help me!!
Well, you can put all the selects inside a form and set them as required.
In the button, you valid the ng-disabled tag if de form is $invalid.
Example:
<ng-form name="selectForm">
<select class="form-control" ng-model="item.name" name="select" ng-required="true">
<option>Select a campus</option>
<option>Campus 1</option>
<option>Campus 2</option>
<option>Campus 3</option>
</select>
<button type="submit" ng-disabled="selectForm.$invalid">Save</button>
</ng-form>
You can use the same object as model for all ng-selects:
$scope.selectedValues = {};
Then each select box inside ng-repeat will use as model different object property:
<select class="form-control" ng-model="selectedValues['campus_' + $index]">
<option>Select a campus</option>
<option>Campus 1</option>
<option>Campus 2</option>
<option>Campus 3</option>
</select>
To check whether all values are filled you'll watch the selectedValues for changes with last parameter set to true:
$scope.$watch('selectedValues', function(newValue, oldValue) {
// Check whether all values in $scope.selectedValues are filled
var allFilled = true;
angular.forEach($scope.selectedValues, function(value, key) {
if (!value) {
allFilled = false;
}
});
if (allFilled) {
// enable button
} else {
// disable button
}
}, true);
The last parameter true is essential because it tells Angular to compare all values in the object. See https://docs.angularjs.org/api/ng/type/$rootScope.Scope.
If I have a bunch of table rows and with select tags in them how would I get the selected value?
If the variable "selected_ingr_action" is the same for every row then when I select an item they all change instead of just the one.
I know I'm missing something.
{{#Ingredients}}
<tr>
<td class="ingr-bid-col"></td>
<td>
<div class="row">
<div class="col-xs-12">
<p class="ingr-name">{{Name}}</p>
</div>
</div>
<div class="row">
<div class="col-xs-6">
{{VendorName}}<br />
<b>pack:</b><span>{{Pack}}</span>
</div>
<div class="col-xs-6" style="padding-bottom:5px;">
<div class="caption">
<b>unit price</b><br />
<span>{{UnitPrice}}</span>
</div>
<div class="caption">
<b>case price</b><br />
<span>{{CasePrice}}</span>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<select class="form-control" value="{{selected_ingr_action}}">
<option value="-1" selected disabled>Action</option>
<option value="0">Rename</option>
<option value="1">Edit Unit Price</option>
<option value="2">Archive</option>
</select>
</div>
</div>
</td>
</tr>
{{/}}
I think perhaps you might be asking a much simpler question about why the rows are sharing the value. If this is the case, the short answer is to use a restricted reference (notice the .):
<select class="form-control" value="{{.selected_ingr_action}}">
<option value="-1" selected disabled>Action</option>
<option value="0">Rename</option>
<option value="1">Edit Unit Price</option>
<option value="2">Archive</option>
</select>
This causes the selected_ingr_action to be bound to the list item, not the root of the ractive instance.
You can access the result on each item with a wilcard observer:
r.observe('list.*.selected_ingr_action', function(n, o, k, i){
console.log('list index', i, 'changed from', o, 'to', n);
});
Check it out here.
The behavior of defaulting to root, rather than current context, is under consideration to be changed to resolve to the current context.
One option would be to have a separate map of selected values, and use two-way binding to update that map (rather than a single selected_ingr_action property, or a selected_ingr_action property belonging to each item in the list). You can see an example of this approach here - the details are different but the principle is the same.
{{#Ingredients :i}} <!-- note the index reference -->
...
<select class="form-control" value="{{selected_ingr_actions[i]}}">
<option value="-1" selected disabled>Action</option>
<option value="0">Rename</option>
<option value="1">Edit Unit Price</option>
<option value="2">Archive</option>
</select>
There are to ways to solve this.
First, bind the value of the select into data.
I.e. turn this string:
<select class="form-control" value="selected_ingr_action">
into this:
<select class="form-control" value="{{selected_ingr_action}}">
Assuming that your data structure is something like this:
var Ingredients = [
{
Name: String,
VendorName: String,
UnitPrice: Number,
CasePrice: Number,
selected_ingr_action: String
},
/* other entries */
];
As a second thought, maybe you don't want to store action type inside your data.
I beleive that better approach would be to use so-called Proxy Events with custom arguments and Method Calls.
Here, I add key into your template and when you change your select value, corresponding event handler are called with the index of your row.
Like this:
{{#each Ingredients: key}} <!-- <<< note that key -->
<!-- skip -->
<div class="row">
<div class="col-xs-12">
<select class="form-control" on-change="changeAction(this, key)" value="{{this.selected_ingr_action}}">
<!-- note this too ^^^^^^^^^^^^^^^^^^^^^^ -->
<option value="-1" selected disabled>Action</option>
<option value="0">Rename</option>
<option value="1">Edit Unit Price</option>
<option value="2">Archive</option>
</select>
</div>
</div>
{{/each}}
Note, into your Ractive component you can introduce method changeAction, which will receive current row (with corresponding Name, VendorName etc. properties) and it's key. Like this:
var ractive = new Ractive({
/* skip */
changeAction: function (ingridient, key) {
// do something with that ingridient
}
/* skip */
});