show element and hide the other elements within ng-repeat - angularjs

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>

Related

Adding boolean flag to Angular ng-repeat

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

Parsing json in Angular returns undefined

I am new to Angular and I am going through this tutorial and I have problem
with parsing the given json which looks like this:
{ "records": [
{
"Name" : "Alfreds Futterkiste",
"City" : "Berlin",
"Country" : "Germany"
},
{
"Name" : "Centro comercial Moctezuma",
"City" : "México D.F.",
"Country" : "Mexico" },
{
"Name" : "Ernst Handel",
"City" : "Graz",
"Country" : "Austria" },
{
"Name" : "FISSA Fabrica Inter. Salchichas S.A.",
"City" : "Madrid",
"Country" : "Spain" },
{
"Name" : "Island Trading",
"City" : "Cowes",
"Country" : "UK"
}
] }
The problem is that the json is returned as "undefined" and not shown on page
at all. This is the index.html:
<!DOCTYPE html>
<html ng-app="MyApp">
<head>
<title>AngularJS Tutorial Series</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div ng-controller="HelloController">Hi {{name}}, welcome to AngularJS Tutorial Series</div>
<div ng-controller="AboutController">Brought to you by {{name}}.</div>
<h2>Load me some JSON data : )</h2>
<table ng-controller="HelloController">
<tr>
<th>Name</th>
<th>City</th>
<th>Country</th>
</tr>
<tr ng-repeat="country in countries">
<td>{{country.Name}}</td>
<td>{{country.City}}</td>
<td>{{country.Country}}</td>
</tr>
</table>
<!-- Angular JS Scripts -->
<script src="js/angular.min.js"></script>
<script src="js/angular-route.min.js"></script>
<!-- AngularJS Application Specific Scripts -->
<script src="app/app.js"></script>
<script src="app/controllers/homeController.js"></script>
<script src="app/controllers/aboutController.js"></script>
</body>
</html>
and this is homeController.js file:
MyApp.controller('HelloController', hello);
function hello($scope, $http){
$scope.name = "Rodrick";
$http.get('countries.json').then(function(data) {
$scope.countries = data.records;
});
}
Debugging with Google Chrome Developer Tools gives me one warning which says:
Calling Element.createShadowRoot() for an element which already hosts
a shadow root is deprecated. See
https://www.chromestatus.com/features/4668884095336448 for more
details.
ng-inspector lists countries as undefined under "HelloController".
For the sake of completion, here are app.js and aboutController.js:
app.js:
var MyApp = angular.module("MyApp", []);
aboutController.js:
MyApp.controller('AboutController', about);
function about($scope)
{
$scope.name = "Kode Blog Tutorials";
}
Any help would be much appreciated and thank you in advance.
Angular's $http object returns a promise which supports the standard .then() function, and a deprecated .success() function. The .then() returns a standard response object; the deprecated .success() function returns a data object.
You (correctly) changed your code to the updated .then() function, rather than the .success() used in the tutorial, but didn't account for the difference in the returned object.
Instead of
$http.get('countries.json').then(function(data) {
$scope.countries = data.records;
});
You should use:
$http.get('countries.json').then(function(response) {
$scope.countries = response.data.records;
});
http://plnkr.co/edit/O9OyooBZLO9xaCQg8HpH?p=preview
Some of the code changes you have to made in your code :
Why use ng-controller="HelloController" multiple times for the same view ?
--> You have to initialize one controller only once when working on the same view.So, put the ng-controller="HelloController" in the root element of the view and remove others from the page.
Why you use separate controller for just displaying the text {{name}} ?
--> you can do this in same controller HelloController only.
Working demo :
var myApp = angular.module('myApp',[]);
myApp.controller('HelloController',function ($scope) {
$scope.countries = [
{
"Name" : "Alfreds Futterkiste",
"City" : "Berlin",
"Country" : "Germany"
},
{
"Name" : "Centro comercial Moctezuma",
"City" : "México D.F.",
"Country" : "Mexico" },
{
"Name" : "Ernst Handel",
"City" : "Graz",
"Country" : "Austria" },
{
"Name" : "FISSA Fabrica Inter. Salchichas S.A.",
"City" : "Madrid",
"Country" : "Spain" },
{
"Name" : "Island Trading",
"City" : "Cowes",
"Country" : "UK"
}
];
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="HelloController">
<table>
<tr>
<th>Name</th>
<th>City</th>
<th>Country</th>
</tr>
<tr ng-repeat="country in countries">
<td>{{country.Name}}</td>
<td>{{country.City}}</td>
<td>{{country.Country}}</td>
</tr>
</table>
</div>

Angular hide or show a button if the content of the field in table contains a specific text

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>

how to display the key name which is dynamic to html

Here I have a mongo collection like
"dashboard" : {
"todo" : {
"_id" : "GdfaHPoT7FXW78awi",
"_maxCount" : "1",
"_title" : "todo",
}
"task" : {
"_id" : "GdfaHPoT7FXW78awi",
"_maxCount" : "1",
"_title" : "task",
}
}
here task and todo are dynamic field names, I have looped the dashboard in an ng-repeat.
Now I want to know how to display details inside dashboard.
Go through it
var jimApp = angular.module("mainApp", []);
jimApp.controller('mainCtrl', function($scope){
$scope.dashboard = {
"todo" : {
"_id" : "GdfaHPoT7FXW78awi",
"_maxCount" : "1",
"_title" : "todo"
},
"task" : {
"_id" : "GdfaHPoT7FXW78awi",
"_maxCount" : "1",
"_title" : "task",
}
};
});
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="mainApp" ng-controller="mainCtrl">
<div class="col-xs-4" ng-repeat="(itemName, item) in dashboard">
<div class="panel panel-info">
<div class="panel-head bg-info">{{itemName}}</div>
<div class="panel-body">{{item._title}} {{item._maxCount}}</div>
</div>
</div>
</div>
Could do something like
<div ng-repeat="(key1, value1) in dashboard">
{{key1}}
<div ng-repeat="(key2, value2) in value1">
{{key2}}: {{value2}}
</div>
</div>
Let's say you assign dynamic field name "todo" which is a string to a variable var1
you can access _maxCount of some docX as :
docX["dashboard"][var1]["_maxCount"]

when I put ng-controller in div instead of body autocomplete stops working

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

Resources