I need to add an active class to first item that slipped through ng-if="!item.hidden" loop. It works fine at first as $first directive means 0 index. But Let say the 0 to 3rd indexes is hidden therefore wont be displayed, and 4th index is the first to be displayed.
Here's my actual code
<div ng-if="!item.hidden" ng-repeat="item in ctrl.event.items">
<div class="title item" ng-class="{'active': $first }">
$first directive doesn't work when the index I am applying active class is not 0.
In place of ng-if condition you can filter the items.
after that $first return index 0 by default
<div ng-repeat="item in items| filter:{hidden:false}">
<div class="title item" ng-class="{'active': $first }">
{{item.value}}
</div>
Please check working plnkr https://plnkr.co/edit/mFVhkf55bvv8Z70F9ufk?p=preview
It was a good question, the problem as you mentioned, it cannot be done by $index as $index will even get counted if it the element is hidden.
But, angular is more and more powerful and it has many more alternatives.
Here is a solution from them,
In this answer I used filter to directly filter the values from the array so that, only the filtered objects will be displayed.
ng-repeat="x in records | filter: (x.hidden == true)"
what the above lines make is, it will not take into consideration, the values where hidden is true.
so, the $index will not start from '0'
Here is the working example:
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp">
<table ng-controller="myCtrl" border="1">
<tr ng-class="{'active': $index == 0 }" ng-repeat="x in records | filter: (x.hidden == true)">
<td>{{x.Name}}</td>
<td>{{x.Country}}</td>
</tr>
</table>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.records = [
{
"Name" : "Alfreds Futterkiste",
"Country" : "Germany",
"hidden": true
},
{
"Name" : "Berglunds snabbköp",
"Country" : "Sweden",
"hidden": false
},
{
"Name" : "Centro comercial Moctezuma",
"Country" : "Mexico",
"hidden": false
},
{
"Name" : "Ernst Handel",
"Country" : "Austria",
"hidden": false
}
]
});
</script>
</body>
<style>
.active
{
background: green;
}
<style>
</html>
Here is a working DEMO
I am trying to display list of names and when click on the name it will show the country for that name , and when click on other name it will hide the previous one and show the clicked one only,
i used ng-show with variable declared in the controller but it just keep showing each items i click on it without hiding the others, this is my code:
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body ng-app="myApp">
<div ng-controller="myCtrl">
<div ng-repeat="x in records">
{{x.Name}}
<div ng-show="showDesc">{{x.Country}}</div>
</div>
</div>
<script>
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.showDesc = false;
$scope.records = [
{
"Name" : "Alfreds Futterkiste",
"Country" : "Germany"
},
{
"Name" : "Berglunds snabbköp",
"Country" : "Sweden"
},
{
"Name" : "Centro comercial Moctezuma",
"Country" : "Mexico"
},
{
"Name" : "Ernst Handel",
"Country" : "Austria"
}
]
});
</script>
</body>
</html>
ng-repeat has its own scope. So showDesc = true initializes a showDesc field in the ng-repeat scope. Each item has its own showDesc.
You want a global flag, common to all the items. And that can't just be a flag: you need to know which item must be expanded.
So just change the code to
$scope.expandedRecord = null;
$scope.expand = function(record) {
$scope.expandedRecord = record;
}
and
<div ng-repeat="x in records">
{{x.Name}}
<div ng-show="expandedRecord === x">{{x.Country}}</div>
</div>
In my html
<div ng-app="myApp" ng-controller="customersCtrl">
<table border="1">
<tr ng-repeat="x in names">
<td>{{x.Name}}</td>
<td>{{x.City}}</td>
<td>{{x.Country}}</td></tr>
</table>
</div>
<a href="#" >Show or Hide Button</a>
In my controller
var app = angular.module('myApp', []);
app.controller('customersCtrl', function($scope) {
$scope.names =[
{
"Name" : "Max Joe",
"City" : "Lulea",
"Country" : "Sweden"
},
{
"Name" : "Manish",
"City" : "Delhi",
"Country" : "India"
}
];
});
I need to show the button if there are no records or 1 of the country is India. I'm working on this but no avail http://jsfiddle.net/junedc/n8ejgtwa/1/ Thanks for the help guys really appreciated.
Use an array filter as well as array length to set a boolean
var hasIndia = $scope.names.filter(function(item){
return item.Country === 'India'
}).length;
$scope.showButton = !$scope.names.length || hasIndia;
In view:
<a ng-show="showButton" href="#" >Show or Hide Button</a>
I am just getting started on angularjs and have a basic question.
If I have a mapping of log-level to a color - say ERROR is red, WARN is yellow, DEBUG is green and I would like to display the json in html with each enum mapping to a different color, how would I achieve that ?
Here is my json input
var jsonString = [
{ "msg" : "this is warning", "level" : WARN },
{ "msg2" : "this is error", "level" : ERROR }
]
This is what I would like to be generated
<html>
<table>
<tr><th>Message</th></tr>
<tr><td bgcolor="red">this is error</td></tr>
<tr><td bgcolor="yellow">this is warn<td></tr>
</table>
Here is a proposed solution. However I never heard of that bgcolor attribute. If you want to use proper CSS instead, you could replace it by ng-style="{background-color: colors[message.level]}"
angular.module('test', []).controller('test', function($scope) {
$scope.colors = {
WARN: 'orange',
ERROR: 'red'
};
$scope.messages = [
{ "msg" : "this is warning", "level" : "WARN"},
{ "msg" : "this is error", "level" : "ERROR" }
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<html>
<body ng-app="test" ng-controller="test">
<table>
<tr><th>Message</th></tr>
<tr ng-repeat="message in messages">
<td ng-attr-bgcolor="{{colors[message.level]}}">{{message.msg}}</td>
</tr>
</table>
</body>
</html>
Alternatively, as suggested by Phil in a comment, you could use ng-class="message.level" and then add some styling to the .WARN and .ERROR classes.
I have a textbox with autocomplete capability and after clicking on click me button the text in autocomplete is added as in the table , here is the link that works perfectly fine,
var app = angular.module('app', []);
app.factory('Service', function() {
var typesHash = [ {
id :1,
name : 'lemon',
price : 100,
unit : 2.5
}, {
id : 2,
name : 'meat',
price : 200,
unit : 3.3
} ];
var localId = 3;
availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
var service = {
addTable : addTable,
getData : getData,
complete:complete
};
return service;
function complete($scope){
$( "#txt" ).autocomplete({
source: availableTags,
messages: {
noResults: '',
results: function() {}
}
});
$("#txt" ).on( "autocompleteselect", function( event, ui ) {
$scope.tableTools.inputData=ui.item.value;
} );
}
function addTable(name,price) {
typesHash.push({id:localId++, name:name, price:price,unit:1});
}
function getData() {
return typesHash;
}
});
app.controller('table', function(Service,$scope) {
//get the return data from getData funtion in factory
this.typesHash = Service.getData();
//get the addtable function from factory
this.addTable = Service.addTable;
this.complete=Service.complete($scope);
});
working link
but as soon as I put ng-controller="table as tableTools" in the div instead of body then autocompleting of text box start acting funny and it does not work properly
not working link
can anyone explain the reason and tell me how I can fix it in a way that even by putting ng-controller="table as tableTools" inside div it works?
Update:
here is the error:
Uncaught TypeError: Cannot set property 'inputData' of undefined
for this line:
$scope.tableTools.inputData = ui.item.value;
(remember the problem starts after you click on suggested text)
The issue is hidden in missunderstanding of the angularjs object life-cycles.
The most important here to know is:
services (factory/provider ... different creation, but at the end the same) are singletons
controllers are instantiated per each view. (There are many, multi instances of one controller through the angular app life time..)
So what happened?
There is one service:
app.factory('Service', function() {
...
and there is one controller passing its scope into that service
app.controller('table', function(Service,$scope) {
...
this.complete=Service.complete($scope);
And on the page we can see:
// first usage of controller
// its first instance is created, $scope is passed
<div class="row commonRow" ng-controller="table as tableTools">
// second usage
// different instance is created... and it also passes the §scope
<tbody ng-controller="table as iterateTb">
But as described above - service is only one. While first controller passes its $scope, the second does after while as well.. and that is causing the issue.
We can use services inside of controllers. That is the design principle of angular. But we should not pass the $scope...
This is happening because you have two controller on the same page with two differenct element therefore scope is not binding properly.
The best code for you to do this is :-
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script src="//code.jquery.com/ui/1.11.2/jquery-ui.js"></script>
<link data-require="bootstrap#*" data-semver="3.3.1" rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css" />
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="//code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css">
<title>Insert title here</title>
<script>
var app = angular.module('app', []);
app.factory('Service', function() {
var typesHash = [ {
id :1,
name : 'lemon',
price : 100,
unit : 2.5
}, {
id : 2,
name : 'meat',
price : 200,
unit : 3.3
} ];
var localId = 3;
availableTags = [
"ActionScript",
"AppleScript",
"Asp",
"BASIC",
"C",
"C++",
"Clojure",
"COBOL",
"ColdFusion",
"Erlang",
"Fortran",
"Groovy",
"Haskell",
"Java",
"JavaScript",
"Lisp",
"Perl",
"PHP",
"Python",
"Ruby",
"Scala",
"Scheme"
];
var service = {
addTable : addTable,
getData : getData,
complete:complete
};
return service;
function complete($scope){
$( "#txt" ).autocomplete({
source: availableTags,
messages: {
noResults: '',
results: function() {}
}
});
$("#txt" ).on( "autocompleteselect", function( event, ui ) {
console.log($scope);
$scope.tableTools.inputData=ui.item.value;
} );
}
function addTable(name,price) {
typesHash.push({id:localId++, name:name, price:price,unit:1});
}
function getData() {
return typesHash;
}
});
app.controller('table', function(Service,$scope) {
//get the return data from getData funtion in factory
this.typesHash = Service.getData();
//get the addtable function from factory
this.addTable = Service.addTable;
this.complete=Service.complete($scope);
});
</script>
</head>
<body ng-app="app" ng-controller="table as tableTools" >
<form >
<div class="row commonRow" >
<div class="col-xs-1 text-right">
item:
</div>
<div class="col-xs-5">
<input id="txt" type="text" style="width: 100%;" ng-keyup="tableTools.complete()" ng-model="tableTools.inputData">
</div>
<div class="col-xs-2">
<button class="btn btn-primary" ng-click="tableTools.addTable(tableTools.inputData);tableTools.inputData=''">
click me
</button>
</div>
</div>
</form>
<div class="row commonRow">
<div class="col-xs-1"></div>
<div class="col-xs-10">
<table class="table table-hover">
<thead>
<tr>
<th>item</th>
</tr>
</thead>
<tbody> <!--No need for controller here-->
<tr ng-repeat="x in tableTools.typesHash track by x.id">
<td>
<div>{{x.name}}</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
Plunker
If you add
$scope.tableTools={}
right below
function complete($scope){
the second one works as expected.
can anyone explain the reason
As long as the object ‘$scope.tableTools‘ has not been defined, you cannot successfully add attributes to it