Angularjs ng-repeat filter counting variables? - javascript

I'm creating a tree view of the amount of forms employees either haven't filled out, have started or completed. There can be multiple nested levels.
For a simple example the rows are:
Year 2014: missing:3, started=7, completed=7
John Doe: missing=2, started=3, completed=5
Phil Smith: missing=1, started=4, completed=2
What if I filter on employee? Then I want the missing, started and completed count to change for the year row. How do I have those variables be dynamically calculated with an ng-repeat?

You would want to calculate the subtotals in the controller. Your problem is that you want the subtotals to update according to the filters that are applied on view. You can achieve this by injecting $filter into your controller.
Have a look at the plunk here: http://plnkr.co/edit/JwUOzm5u3G7379I1W6hk?p=preview
I created a filter in an input box. Try changing the text, the subtotals update accordingly.
In this case I use the 'filter' filter both in the view as well as the controller so that the view and the subtotal update simultaneously.
Code below:
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#*" data-semver="1.3.1" src="//code.angularjs.org/1.3.1/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app">
<div ng-controller="mainCtrl as main">
<input type="text" ng-model="main.empName" placeholder="name filter">
<div ng-repeat="year in main.data">
{{year.yearNum}}:{{main.calculateTotal(year.yearNum)}}
<div ng-repeat="employee in year.employees|filter:main.empName">
{{employee.name}} : {{employee.cost}}
</div>
</div>
</div>
<script>
angular.module('app',[])
.controller('mainCtrl',function($filter){
var main=this;
main.calculateTotal=function(yearNum){
var data=main.data;
var total=0;
for(var i=0;i<data.length;i++){
if(data[i].yearNum==yearNum)
{
var employees=$filter('filter')( main.data[i].employees, main.empName );
for(var j=0;j<employees.length;j++){
total+=employees[j].cost;
}
}
}
return total;
}
main.data=[
{
yearNum:2012,
employees:[
{
name:"jane",
cost:200
},
{
name:"jow",
cost:400
}
]
},
{
yearNum:2013,
employees:[
{
name:"jane",
cost:250
},
{
name:"jow",
cost:450
}
]
}
];
});
</script>
</body>
</html>

Related

Angular ngSelected not working in version > 1.3

Markup:
<!DOCTYPE html>
<html ng-app="test">
<head>
<script data-require="angular.js#1.5.6" data-semver="1.5.6" src="https://code.angularjs.org/1.5.6/angular.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-controller="ctrl">
<h1>Hello Plunker!</h1>
<select ng-model="user.item_id">
<option ng-selected="i.id == user.item_id" ng-repeat="i in items" value={{i.id}}>{{i.name}}</option>
</select>
</body>
</html>
JS:
var module = angular.module("test", []);
module.controller('ctrl', function($scope){
$scope.items = [
{id: 1, name: 'foo'},
{id: 2, name: 'bar'},
{id: 3, name: 'baz'},
];
$scope.user = {};
$scope.selectedItem = {id: 1};
$scope.user.item_id = $scope.selectedItem.id;
});
Plunker: https://plnkr.co/edit/7oi4KwzMhGi3kdltSklg?p=preview
Problem: if you inspect the html code of the select, you will see that the HTML selected attribute is properly placed.
However, it doesn't show as the highlighted option. Why?
== EDIT ==
That plunker code is working as expected on angular 1.3.20, but it's broken in 1.4.x or 1.5.x
Working plunker: https://plnkr.co/edit/0ApQeZ6Kar2yQisELXfT?p=preview
== EDIT2 ==
I've issued a ticket on angularjs queue: https://github.com/angular/angular.js/issues/14876#issuecomment-231010972
Basically, they say we should stick to ngOptions, though they don't know why ngSelected got broken.
Well, you could use ng-options instead...
<select ng-model="user.item_id" ng-options="i.id as i.name for i in items">
</select>
Check here https://plnkr.co/edit/G4Hu4ZpShaUPCE5zTsdV
I don't see this working on any version that you mention. Anyway, check this plunker
https://plnkr.co/edit/V0ybr70kRpkcaxLKBHTK?p=preview
The way that you wrote the select, i can reproduce the same thing on any input. And the reason is because it is not how angular binding works, your select doesn't know anything about his model, unless you change the model (i.e. using ng-init).
Using this way:
<option ng-selected="i.id == user.item_id" ng-repeat="i in items" value={{i.id}}>{{i.name}}</option>
doesn't mean that your model will update, it only updates the dom element.

My html5 app fail to display model

I'm using angularJS to do some custom filter work, but it failed to display model information at the first stage.
<html lang="en" data-ng-app="myApp">
<Head>
<title>Custom filter</title>
<meta charset="utf-8">
</head>
<body>
<div data-ng-init="varNum=0">
<p>
<label for="number">Enter number from 1 to 99:</label>
<input type="number" data-ng-model="varNum" id="number"/>
</p>
<p>Your number: {{ varNum }}</p>
</div>
<script src="js/angular.min.js"></script>
<script src="js/appromannumber.js"></script>
</body>
</html>
appromannumber.js
var app = angular.module("myApp", []);
app.filter("myFilter", function (){
return function(myNum) {
var formatedNumber = "";
switch(myNum) {
0:formatedNumber="zero";break;
return formatedNumber;
}
});
But if I remove the value of ng-app, like data-ng-app = "", it will start to display the varNum. I have no idea why this happen.
Should not work angular without bootstrap module means without ng-app="moduleName". I suspect that you miss something else and I mentioned bellow some problem in your code that may will help you
in your filter you missed
case in switch statement. need case 0: instead of 0:...
return formatedNumber; this statement is unreachable. should use after switch statement
you can try like:
app.filter("myFilter", function (){
return function(myNum) {
var formatedNumber = "";
switch(myNum) {
case 0:formatedNumber="zero";break;
case 1:formatedNumber="One";break;
}
return formatedNumber;
};
});
and in html:
<div data-ng-init="varNum=0">
<p>
<label for="number">Enter number from 1 to 99:</label>
<input type="number" data-ng-model="varNum" id="number"/>
</p>
<p>Your number: {{ varNum | myFilter }}</p> // shown filtered value
</div>

ng-change doesn't work on input

I'm new to AngularJS and currently struggling with the following problem.
As you can see here in my plnkr I can change the value of the $scope.myDate.value.
The problem now is, that I can't work with this scope in a function, when adding ng-change="barFunc()" to the <input>.
How is it possible to work with ng-change or ng-watch here?
It would be great if someone could make my plnkr work.
<!DOCTYPE html>
<html ng-app="demo">
<head>
<link href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
<link href="//rawgithub.com/g00fy-/angular-datepicker/1.0.3/dist/index.css" rel="stylesheet">
<style>
input {margin: 45px 0 15px 0;}
pre{padding: 15px; text-align: left;}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-4">
<div ng-controller="foo">
<input type="datetime" class="form-control" date-time ng-model="myDate.value"
ng-change="barFunc()" format="yyyy-MM-dd hh:mm:ss" placeholder="Select datetime">
<pre>myDate: {{myDate.value}}</pre>
<pre>myDate + " abc": {{ custom.value }}</pre>
</div>
</div>
</div>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<script src="//code.angularjs.org/1.4.8/angular.js"></script>
<script src="//rawgithub.com/g00fy-/angular-datepicker/1.0.3/dist/index.js"></script>
<script>
angular.module('demo', ['datePicker']).controller('foo',['$scope', function($scope){
$scope.myDate = {
value: ''
};
$scope.barFunc = function() {
$scope.custom.value = $scope.myDate.value + " abc";
};
}]);
</script>
</body>
</html>
You have to define $scope.custom before you can access to $scope.custom.value
I would use $watch in this case:
in your controller:
$scope.custom = {
value : ''
};
$scope.$watch('myDate.value', function() {
$scope.barFunc();
});
$scope.barFunc = function() {
$scope.custom.value = $scope.myDate.value + " abc";
};
or in plunkr
You could set up a watcher like this:
$scope.$watch('myDate', function(oldValue, newValue) {
$scope.barFunc(newValue);
});
but you'll also need to define your custom object:
$scope.custom = {
value: ''
};
and it should work. I don't feel like this is the best solution - I generally feel like if I'm setting watchers because I don't understand why something's not working as expected then it's better to figure out why it's not working. I get that's what you're trying to do, and am only offering this as something that would solve your problem quickly if that's what you need.

Multiple digest run for the code below

I am getting a infinite digest cycle error with the filter code below. What is incorrect with it. I do not see an issue with this. Is there a different method of assignation or is it a known bug? I am not sure whats happening here with this error
<!DOCTYPE html>
<html ng-app="demo">
<head>
<meta charset="UTF-8">
<title>Directives</title>
<script src="lib/angular.min.js"></script>
<script src="lib/app.js"></script>
<link rel="stylesheet" href="lib/style.css">
</head>
<body>
<h1>Test Text for style</h1>
<div ng-controller="firstCtrl">
<input type="text" ng-model="search">
<div ng-repeat="var in variable | filtername:'test':'test2':'test3' track by $index">
{{var}}
</div>
</div>
<script>
var app = angular.module("demo",[]);
app.filter("filtername",function(){
return function(array, arrayField, arrayField1, arrayField2){
/* modification here */
var myArr = [];
for(var i=0;i<array.length;i++){
if((array[i].name===arrayField) || (array[i].name===arrayField1) ||(array[i].name===arrayField2)){
myArr.push({name: angular.uppercase(array[i].name)});
}
}
return myArr;
}
})
app.controller("firstCtrl",function($scope){
$scope.variable = [
{name:"test"},
{name:"test2"},
{name:"test3"},
{name:"test4"}];
})
</script>
</body>
</html>

Angular: when using ng-include, number variable become NaN [duplicate]

This question already has answers here:
What are the nuances of scope prototypal / prototypical inheritance in AngularJS?
(3 answers)
Closed 7 years ago.
I have a problem when i try to fragment my html with ng-include:
This is what my index.html page looks like when it works (prix=price, TVA=tax):
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<link type="text/css" rel="stylesheet" href="style.css" />
<title> TVA </title>
</head>
<body>
<div>
<div ng-app="app" ng-controller="appCtrl">
<input ng-model="tva" placeholder="TVA" /><br />
<input ng-model="prix" placeholder="Prix" />
<select ng-model="taxe">
<option>HT</option>
<option>TTC</option>
</select>
<button id="btn" ng-click="calcul()">Calculer</button>
<p>{{ total }}</p>
</div>
</div>
<script src="angular.min.js"></script>
<script src="script.js"></script>
</body>
</html>
The script.js :
app = angular.module('app', []);
app.controller('appCtrl', ['$scope', function ($scope) {
$scope.calcul = function() {
if ($scope.taxe == "TTC") {
$scope.total = parseInt($scope.prix) + $scope.prix * $scope.tva /100;
} else if($scope.taxe == "HT") {
$scope.total = 1/(1+$scope.tva/100)*$scope.prix;
}
};
}]);
So this works, the result is an number (the price with or without tax).
When I use the ng-include like this:
<div>
<div ng-app="app" ng-controller="appCtrl">
<div ng-include="'tva.html'"></div>
<input ng-model="prix" placeholder="Prix" />
<select ng-model="taxe">
<option>HT</option>
<option>TTC</option>
</select>
<button id="btn" ng-click="calcul()">Calculer</button>
<p>{{ total }}</p>
</div>
</div>
I only tried to replace the first input with a new HTML page.
The tva.html :
<input ng-model="tva" placeholder="TVA" /><br />
Now the results show "NaN" (I put those codes on a server so that I can check online). Why is this?
#Josh Beam Answered & explained ng-include creates a child scope on creating the DOM. I'd suggest you to use dot rule in angular that will follow prototypal inheritance on that object and you object value will access in child scope.
Now your object structure will changed to $scope.model={}; and this model will have all the input values. like all will become like model.prix, model.taxe & model.tva so that the prototypal inheritance will follow.
Markup
<div ng-app="app" ng-controller="appCtrl">
<div ng-include="'tva.html'"></div>
<br />
<input ng-model="model.prix" placeholder="Prix" />
<select ng-model="model.taxe">
<option>HT</option>
<option>TTC</option>
</select>
<button id="btn" ng-click="calcul()">Calculer</button>
<p>{{ total }}</p>
</div>
Code
app.controller('appCtrl', ['$scope', function ($scope) {
$scope.model = {};
$scope.calcul = function() {
if ($scope.model.taxe == "TTC") {
$scope.total = parseInt($scope.model.prix) + $scope.model.prix * $scope.model.tva /100;
} else if($scope.model.taxe == "HT") {
$scope.total = 1/(1+$scope.model.tva/100)*$scope.model.prix;
}
};
}]);
tva.html
<input ng-model="model.tva" placeholder="TVA" /><br />
Demo Plunkr
Short answer: don't use ng-include in this instance.
Long answer: ng-include creates a new child scope, so ng-model inside the ng-include isn't appCtrl's TVA. I don't see a reason here to use ng-include anyway, your code is fine without it.
So basically you're getting NaN (not a number) because $scope.TVA is never set when using the ng-include... you're attempting to multiply an undefined variable by another number, which returns NaN:
The reason for that is the ng-include creates a new scope under the scope when the HTML was included, but you can access to the parent scope by specifying $parent
<input ng-model="$parent.tva" placeholder="TVA" /><br />
A better approach is give an alias to your controller, so it will be clear semantically to children controllers accessing to a specific parent.
<div ng-app="app" ng-controller="appCtrl as vmMain">
<div ng-include="'tva.html'"></div>
... and in the other file:
<input ng-model="vmMain.tva" placeholder="TVA" /><br />

Categories