Adding values from an angularjs drop menu - angularjs

I am trying to add my $scope together, but having issues with it.
I am using
$scope.total = ($scope.list_category1.id || 0) + ($scope.list_category2.id || 0) + ($scope.list_category3.id || 0);
but I can't seem to add my values together until all the selects have got a value.
Please help
https://jsfiddle.net/wayneker/o9t6g7qg/8

If you watch console closely, every time calcTotals() is executed, you get error Cannot read property 'id' of undefined as list_category1 expected to be an Object and id property is not found within it. You should create default values like zeros to make sure calcTotals() will successfully function:
Object.assign($scope, {
list_category1: '',
list_category2: '',
list_category3: ''
});
Empty string are only for example as they are most easiest way to define default values for your... err... view model.

You can directly call the calcTotals instead of total.
and change the function as,
$scope.calcTotals = function(){
return ($scope.list_category1.id || 0) + ($scope.list_category2.id || 0) + ($scope.list_category3.id || 0);
};
DEMO
var app = angular.module('app', []);
app.controller('Ctrl',function($scope) {
$scope.list_categories = {
data: [
{id: 1, name: 'name1'},
{id: 2, name: 'name2'},
{id: 3, name: 'name3'},
{id: 4, name: 'name4'}
]
};
$scope.total = 0;
$scope.calcTotals = function(){
return ($scope.list_category1.id || 0) + ($scope.list_category2.id || 0) + ($scope.list_category3.id || 0);
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="Ctrl">
<select id="sel" class="input-block-level" ng-model="list_category1" ng-options="value.name for value in list_categories.data">
<option value="">Other</option>
</select>{{list_category1.id}}<br>
<select id="sel" ng-model="list_category2" ng-options="value.name for value in list_categories.data">
<option value="">Other</option>
</select>{{list_category2.id}}<br>
<select id="sel" ng-model="list_category3" ng-options="value.name for value in list_categories.data">
<option value="">Other</option>
</select>{{list_category3.id}}<br>
<br>
<div>
<b>All Points (from $scope total): {{calcTotals()}}</b><br><br>
<b>All Points (by adding directly): {{list_category1.id + list_category2.id + list_category3.id}}</b>
</div>
</div>

Related

Selected value not displayed on AngularJS Select

My problem is when i change the value of the dropdown menu the value isn't displayed in the dropdown menu but the correct value is displayed in my console. Not sure why it isn't working at the moment because i have a same implementation of this in another project. Maybe i'm overlooking things.
On initialization i set
selected_type = types[0]
// What will result in Type1 being displayed on page load.
Fiddle you can find here: https://jsfiddle.net/596tzsh8/7/
Use:
ng-options="selected_type as selected_type.Name for selected_type in types track by selected_type.Id"
// ^
// the object itself
... instead of:
ng-options="selected_type.Id as selected_type.Name for selected_type in types track by selected_type.Id"
// ^
// the object's ID
Then, in your callback function, replace:
var typeID = this.selected_type;
// ^
// the object itself
... by:
var typeID = this.selected_type.Id;
// ^
// the object's ID
... and you're all set!
See your forked JSFiddle here, or play around with the snippet below.
var app = angular.module("app", ["controllers"])
var controllers = angular.module("controllers",[]);
controllers.controller('myController', function($scope){
$scope.types = [{
Id: 1,
Name: 'Type1'
}, {
Id: 2,
Name: 'Type2'
}, {
Id: 3,
Name: 'Type3'
}];
$scope.GetValueTypeDropdown = function () {
var typeID = this.selected_type.Id;
$scope.the_type = $.grep($scope.types, function (selected_type){
return selected_type.Id == typeID;
})[0].Name;
console.log($scope.the_type);
return $scope.the_type;
};
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="myController">
<form>
<select name="type" class="col-xs-12 dropdown-list"
ng-model="selected_type" class="col-xs-8"
ng-init="selected_type = types[0]"
ng-options="selected_type as selected_type.Name for selected_type in types track by selected_type.Id"
ng-change="GetValueTypeDropdown()">
</select>
</form>
</div>
</div>
You can change the select as follows,
<select name="type" class="col-xs-12 dropdown-list" ng-model="selected_type" class="col-xs-8" ng-init="selected_type = types[0]" ng-options="type as type.Name for type in types track by type.Id" ng-change="GetValueTypeDropdown()">
also you can have a $scope variable and display it on ng-change
$scope.GetValueTypeDropdown = function() {
console.log($scope.selected);
};
DEMO

angular filtered dropdown model not updating

I'm trying to update a filtered dropdowns(combobox) model on click of a button. The model value is changing but dropdown still shows an empty selected option. If I remove the filter everything works as it should (without filtering of course).
Plunker: http://plnkr.co/edit/a48JSEiiATrkcQKxfJjx?p=preview
JS:
$scope.tasks = [
{name:'Task1', taskid: 1, custid: 2},
{name:'Task2', taskid: 2, custid: 2},
{name:'Task3', taskid: 3, custid: 3}
];
$scope.myinfo = {};
$scope.updateinfo = {name:'Cust Name', custid: 3, taskid: 3};
$scope.setMyinfo = function(){
$scope.myinfo = $scope.updateinfo;
};
});
app.filter('taskFilter', function() {
return function(input, criteria) {
var result = [];
for (var i = 0; i < input.length; i++) {
if(input[i].custid == criteria || input[i].custid === undefined){
result.push(input[i]);
}
}
return result;
}
HTML:
<button ng-click="setMyinfo()">Button</button>
<br> <br>
Filtered:
<select ng-model="myinfo.taskid">
<option>---</option>
<option ng-repeat="task in tasks | taskFilter:myinfo.custid" value="{{task.taskid}}">{{task.name}}</option>
</select>
Unfiltered:
<select ng-model="myinfo.taskid">
<option>---</option>
<option ng-repeat="task in tasks" value="{{task.taskid}}">{{task.name}}</option>
</select>
<br><br>
Value: {{myinfo.taskid}}
Thanks you for helping!
pre-filter the list by key and value:
<div ng-repeat="(k,v) in filterCustId(tasks)">
{{k}} {{v.pos}}
</div>
And on the Controller:
$scope.filterCustId = function(items) {
var result = {};
angular.forEach(items, function(value, key) {
if (!value.hasOwnProperty('custid')) {
result[key] = value;
}
});
return result;
}
From:
https://stackoverflow.com/a/14789258/4668696
Please update code following line
if(input[i].custid == criteria || input[i].custid === undefined){
by
if(input[i].custid == criteria || input[i].custid === undefined || criteria == undefined){

AngularJS Select Not Binding To Ng-Model

My angular select isn't binding. I can tell the value is correct, but the select isn't updated. Why is not binding if the value is there?
<div ng-controller="MyController" ng-app>
<select class="form-control" ng-model="colorId"ng-options="color.id as color.name for color in colorList">
<option value="">--Select a Color--</option>
</select>
<input type="button" value="submit" ng-click="Select()"></input>
function MyController($scope) {
$scope.colorList = [{
id: '1',
name: 'red'
}, {
id: '2',
name: 'blue'
}, {
id: '3',
name: 'green'
}];
var colorId = 3;
$scope.colorId = colorId;
alert($scope.colorId);
$scope.Select = function () {
var colorId = 2;
$scope.colorId = colorId;
}
}
Here is a fiddle:
http://jsfiddle.net/ky5F4/23/
you need to change the id to a string when doing Select
$scope.Select = function () {
console.log('select fired');
var colorId = 1;
$scope.mySelection.colorId = colorId + "";
}
http://jsfiddle.net/bxkwfo0s/2/
next you should use a property of an object rather than just a scope variable, this will ensure proper model binding
ng-model="mySelection.colorId"
where the object could be something simple
$scope.mySelection = {colorId : colorId };
There are two errors with your code:
You are using colorList as your model in ng-options, but you are calling it datasets in your controller.
You use strings for the id, but set the $scope.colorId to a number.
Here is an updated fiddle changing ids to numbers and changing $scope.datasets to $scope.colorList
function MyController($scope) {
$scope.colorList = [{
id: 1,
name: 'red'
}, {
id: 2,
name: 'blue'
}, {
id: 3,
name: 'green'
}];
var colorId = 3;
$scope.colorId = colorId;
alert($scope.colorId);
$scope.Select = function () {
var colorId = 2;
$scope.colorId = colorId;
}
}
Consider making your ng-model be an object, specifically one of the objects that are already in your $scope.colorList. If you do that you should be able to avoid the post-processing you're doing in the click handler.
So your select will look like this:
<select class="form-control" ng-model="selectedColor"
ng-options="color.name for color in colorList"></select>
One gotcha is that if you have an object in your controller that looks JUST LIKE your red object, like$scope.selectedColorObj = { id : '1', name:'red' } and set the select's ng-model to that option, it won't work. Angular will see that you're setting to the ng-model to an object that's not actually in your data source and add an extra option with value="?", so I use $filter in this case to grab the matching member of the array:
$scope.colorId = '3';
$scope.selectedColor = $filter('filter')( $scope.colorList,{ id: $scope.colorId})[0];
See http://jsfiddle.net/ky5F4/92/

Angular Sorting with null objects

I need to take records with null values on top , when I'm sorting by ASC
<tr ng-repeat="footballer in footballers=(footballers | orderBy:predicate)">
predicate : ['team.name','id]
Some footballers have no team, so team object == null and team.name==null, and I need to have them on the top
I wanted to rewrite sort function, but I need to save predicate
You can use something like this in your controller:
$scope.nullsToTop = function(obj) {
return (angular.isDefined(obj.team) ? 0 : -1);
};
And on the HTML:
<tr ng-repeat="footballer in footballers | orderBy:[nullsToTop].concat(predicate)">
This way you can maintain your predicate separately. Just concat the nullsToTop function in the orderBy expression to run it first.
Plunker
Create a function in the controller that will receive as parameter the entity and will return either ['team.name','id] either [] or other values that will help push the non-sortable elements to top/bottom of the list.
EDIT (example)
HTML:
<li ng-repeat="item in items | orderBy:getItemOrder track by $index">...
AngularJS Ctrl:
$scope.getItemOrder = function (entity) {
if (entity.id === null || .... === null) {
return 0;
}
return ['team.name','id];
}
I was able to do it by returning a '+' or a '-' if the value is null, close to what bmleite did but is more contained in the function itself.
1. create a function that adds a + or a - to the null values depending on the sort order (asc or desc) so that they'd always remain at either the top or bottom
function compareAndExcludeNull(element){
var compareWith = $scope.order.propertyName; // in your case that's 'predicate'
var operatorToBottom = $scope.order.reverse ? '+' : '-'; // If decending then consider the null values as smallest, if ascending then consider them biggest
var operatorToTop = $scope.order.reverse ? '-' : '+';
if(element[compareWith] == null){
return operatorToTop;
} else {
return operatorToBottom+element[compareWith];
}
}
if you want to have the null values at the bottom of the sorted array then just switch the operatorToTop with operatorToBottom and vice versa to get:
function compareAndExcludeNull(element){
var compareWith = $scope.order.propertyName; // in your case that's '
var operatorToBottom = $scope.order.reverse ? '+' : '-'; // If decending then consider the null values as smallest, if ascending then consider them biggest
var operatorToTop = $scope.order.reverse ? '-' : '+';
if(element[compareWith] == null){
return operatorToBottom;
} else {
return operatorToTop+element[compareWith];
}
}
2. Call the function and pass the array you're sorting
Javascript:
In my case I am calling this function from HTML and passing different propertyName depending on the column the user is sorting by, in your case you'd just need to pass 'predicate' as the propertyName
$scope.order.sortBy = function(propertyName){
$scope.order.reverse = (propertyName !== null && $scope.order.propertyName === propertyName) ? !$scope.order.reverse : false;
$scope.order.propertyName = propertyName;
$scope.resources = $filter('orderBy')($scope.resources,compareAndExcludeNull,$scope.order.reverse);
};
HTML:
<div>
<span ng-if="showKeywords" class="label label-info" ng-click="order.sortBy('keyword')" style="margin-right: 5px">
Order by Keywords
<span ng-if="order.propertyName=='keyword'" class="glyphicon glyphicon-triangle-{{order.reverse? 'bottom' : 'top'}}">
</span>
</span>
<span ng-if="showWebsites" class="label label-info" ng-click="order.sortBy('res_title')">
Order by Website
<span ng-if="order.propertyName=='res_title'" class="glyphicon glyphicon-triangle-{{order.reverse? 'bottom' : 'top'}}">
</span>
</span>
</div>
I know this is an old post but there is a better way for doing this and could not see it anywhere.
var myApp = angular.module('myApp', []);
myApp.controller('myCtrl', ["$scope", function($scope){
$scope.footballers = [
{id: 0, qt: 13},
{id: 1, qt: 2},
{id: 2, qt: 124},
{id: 3, qt: 12125},
{id: null , qt: 122},
{id: 4, qt: -124},
{id: 5, qt: -5235},
{id: 6, qt: 43},
]
}])
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-repeat="footballer in footballers | orderBy:['id==null || id']">
{{footballer.id}}, {{footballer.qt}}
</div>
</div>
One can also use this to show 'id' with any specific value on top of others

AngularJS checkbox filter directive

I have a AngularJS directive that allows users to select a values from a list to filter on. Pretty simple concept which is represented here:
Problem is when I click one of the checkboxes they all select unintended. My directive is pretty simple so I'm not sure why this is happening. The code around the selection and checkboxes is as follows:
$scope.tempFilter = {
id: ObjectId(),
fieldId: $scope.available[0].id,
filterType: 'contains'
};
$scope.toggleCheck = function (id) {
var values = $scope.tempFilter.value;
if (!values || !values.length) {
values = $scope.tempFilter.value = [];
}
var idx = values.indexOf(id);
if (idx === -1) {
values.push(id);
} else {
values.splice(idx, 1);
}
};
$scope.valuesListValues = function (id) {
return $scope.available.find(function (f) {
return f.id === id;
}).values;
};
and the data resembles:
$scope.available = [{
id: 23,
name: 'Store'
values: [
{ id: 124, name: "Kansas" },
{ id: 122, name: "Florida" }, ... ]
}, ... ]
the view logic is as follows:
<ul class="list-box">
<li ng-repeat="val in valuesListValues(tempFilter.fieldId)">
<div class="checkbox">
<label ng-click="toggleCheck(val.id)">
<input ng-checked="tempFilter.value.indexOf(val.id) === -1"
type="checkbox"> {{val.name}}
</label>
</div>
</li>
</ul>
First off, it toggleCheck fires twice but populates the correct data ( second time given my code it removes it though ).
After the second fire, it checks all boxes... Any ideas?
Perhaps its that the local variable doesn't get reassigned to the property of the scope property used in the view. Since your values are then non-existent and not found, the box is checked.
$scope.tempFilter.value = values
I took the interface concept you were after and created a simpler solution. It uses a checked property, found in each item of available[0].values, as the checkbox model. At the top of the list is a button that clears the selected items.
JavaScript:
function DataMock($scope) {
$scope.available = [{
id: 23,
name: 'Store',
values: [{
id: 124,
name: "Kansas"
}, {
id: 122,
name: "Florida"
}]
}];
$scope.clearSelection = function() {
var values = $scope.available[0].values;
for (var i = 0; i < values.length; i++) {
values[i].checked = false;
}
};
}
HTML:
<body ng-controller="DataMock">
<ul class="list-box">
<li>
<button ng-click="clearSelection()">Clear Selection</button>
</li>
<li ng-repeat="val in available[0].values">
<div class="checkbox">
<label>
<input ng-model="val.checked"
type="checkbox" /> {{val.name}}
</label>
</div>
</li>
</ul>
</body>
Demo on Plunker
The repeat that I used to grab the values based on the id, was the problem area.
<li ng-repeat="val in valuesListValues(tempFilter.fieldId)">
removing that and simple listening and setting a static variable resolved the problem.
$scope.$watch('tempFilter.fieldId', function () {
var fId = $scope.tempFilter.fieldId;
if ($scope.isFieldType(fId, 'valuesList')) {
$scope.valuesListValues = $scope.valuesListValues(fId);
}
}, true);
});
and then in the view:
ng-repeat="value in valuesListValues"

Resources