I just began learning AngularJS, and I am trying to create a pretty simple web application. Right now, I have some users. Each user is displayed in an individual table and each user has its own details which is displayed in a table under it.
$scope.userList = [{username: "Bob_t", detailsId: 1}, {username: "Mike_V", detailsId: 2}];
$scope.userDetails = [{Name: "Bob", Age: 20, id: "1"}, {Name: "Michael", Age: 18, id: "2"}];
You can see that each user has a reference to it's corresponding details (detailsId in userList corresponds to id in userDetails).
Basically, what I'm trying to do is initially have the details table hidden for each user. And when someone clicks the expand button for a specific user, open that user's corresponding details table and populate it with that user's details. What I'm having trouble with is getting the detailsId from the clicked expand button and then using that to query my DB to get the correct user's details to display in the table under it.
<div ng-repeat="user in userList | filter:searchBox">
<div class="uk-panel-box-secondary uk-overflow-container tableDiv uk-margin-large-bottom">
<table class="uk-table uk-table-hover uk-margin-top">
<thead>
<tr>
<th>Username</th>
</tr>
</thead>
</table>
<a class="uk-margin-bottom uk-margin-left" id="expandIcon" ng-click="isOpened=!isOpened; showOrHideDetails(isOpened, param)" ng-class="{'uk-icon-plus-square-o': !isOpened, 'uk-icon-minus-square-o': isOpened}"></a>
</div>
<div class="uk-panel-box-secondary uk-overflow-container uk-margin-top uk-margin-large-left uk-margin-bottom tableDiv">
<table class="uk-table uk-table-hover uk-margin-top">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th></th>
</tr>
</thead>
<tr ng-repeat="details in userDetails" id={{user.id}}>
<td>{{details.Name}}</td>
<td>{{details.Age}}</td>
<td>
</td>
</tr>
</table>
</div>
</div>
my controller:
$http({
method : "GET",
url : "http://database:8081/userAccounts/"
}).then(function mySucces(response) {
$scope.userList = response.data;
}, function myError(response) {
// $scope.userList = response.statusText;
});
$scope.showOrHideDetails = function(isOpened, param)
if(isOpened){
console.log($scope.id)
$scope[id] = true;
console.log($scope.id);
$http({
method : "GET",
url : "http://database:8081/details?id=" + index
}).then(function mySucces(response) {
$scope.userDetails = response.data;
}, function myError(response) {
$scope.userDetails = response.statusText;
});
}
else{
$scope.showDetails = false;
}
}
What is really confusing to me is once I get the correct userDetails object after querying the DB, how do I populate the corresponding table with that info?
I know I probably need a model, but this confuses me because the number of users is unknown.
First, your code is a bit confuse..
After each query you're attributing the response (which one is the details of a single user) to the whole array userDetails:
$scope.userDetails = response.data;
While it should be:
$scope.userDetails.push(response.data);
In addition, you have a single variable called isOpened, for sure it won't work, because you have multiple buttons for only 1 variable.
So my suggestion is to change it to:
<a class="uk-margin-bottom uk-margin-left" id="expandIcon" ng-click="showOrHideDetails(user)" ng-class="{'uk-icon-plus-square-o': !user.isOpened, 'uk-icon-minus-square-o': user.isOpened}"></a>
Also you have to check if the userDetail is already in your userDetails array.
Finally, since you want to show the details based on the user, you can use the native filter, because you already have the id property of users in both arrays, as below:
<tr ng-if="user.isOpened" ng-repeat="details in userDetails | filter: { id: user.detailsId }" id={{user.id}}>
A simple demo:
(function() {
angular
.module('app', [])
.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope', '$http'];
function MainCtrl($scope, $http) {
$scope.userList = [{
username: "Bob_t",
detailsId: 1
}, {
username: "Mike_V",
detailsId: 2
}];
$scope.userDetails = [{
Name: "Bob",
Age: 20,
id: "1"
}, {
Name: "Michael",
Age: 18,
id: "2"
}];
$scope.showOrHideDetails = function(user) {
user.isOpened = !user.isOpened;
function mySuccess(response) {
$scope.userDetails.push(response.data);
}
function myError(response) {
console.log(response.statusText);
}
if (user.isOpened) {
$http.get('http://database:8081/details?id=' + user.id)
.then(mySuccess)
.catch(myError);
} else {
$scope.showDetails = false;
}
}
}
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.7/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.26.4/js/uikit.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/uikit/2.26.4/css/uikit.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.min.css">
</head>
<body ng-controller="MainCtrl">
<div ng-repeat="user in userList | filter:searchBox">
<div class="uk-panel-box-secondary uk-overflow-container tableDiv uk-margin-large-bottom">
<table class="uk-table uk-table-hover uk-margin-top">
<thead>
<tr>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr>
<td ng-bind="user.username"></td>
</tr>
</tbody>
</table>
<a class="uk-margin-bottom uk-margin-left" id="expandIcon" ng-click="showOrHideDetails(user)" ng-class="{'uk-icon-plus-square-o': !user.isOpened, 'uk-icon-minus-square-o': user.isOpened}"></a>
</div>
<div class="uk-panel-box-secondary uk-overflow-container uk-margin-top uk-margin-large-left uk-margin-bottom tableDiv">
<table class="uk-table uk-table-hover uk-margin-top">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th></th>
</tr>
</thead>
<tr ng-if="user.isOpened" ng-repeat="details in userDetails | filter: { id: user.detailsId }" id={{user.id}}>
<td ng-bind="details.Name"></td>
<td ng-bind="details.Age"></td>
<td>
</td>
</tr>
</table>
</div>
</div>
</body>
</html>
I hope it helps!!
have you tried passing user from
<div ng-repeat="user in userList | filter:searchBox">
to function showOrHideDetails(user)
Related
I am receiving a list of data from server and has displayed that in table format using ng-repeat along with checkbox in each row. My requirement is to pass the selected rows back to server upon clicking a removeUserData button. Am facing issue to get it done, help would be appreciated.
<table border="2" border-color=black>
<tr data-ng-repeat="user in users">
<td><input type="checkbox"></td><td>{{user.id}}</td><td>{{user.country}}</td><td>{{user.name}}</td>
</tr>
</table><br>
<button data-ng-click="removeUserData()" data-ng-show="users.length">Remove User</button>
I'd suggest you to make use of a new property in users, something like removed, then when checkbox is checked it will be true, otherwise false.
See it working:
(function() {
angular
.module("app", [])
.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope'];
function MainCtrl($scope) {
$scope.removeUserData = removeUserData;
$scope.users = [
{
"id":1,
"country":"Italy",
"name":"Pavarotti"
},
{
"id":2,
"country":"French",
"name":"Some user"
}
];
function removeUserData() {
$scope.users = $scope.users.filter(function(user) {
return !user.removed;
})
}
}
})();
<!DOCTYPE html>
<html ng-app="app">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<table>
<tr ng-repeat="user in users">
<td>
<input type="checkbox" ng-model="user.removed">
</td>
<td ng-bind="user.id"></td>
<td ng-bind="user.country"></td>
<td ng-bind="user.name"></td>
</tr>
</table>
<div ng-if="users.length">
<hr>
<button ng-click="removeUserData()">Remove User</button>
</div>
</body>
</html>
your html
<div ng-app='myApp' ng-controller='myCtrl'>
<table border="2" border-color=black>
<tr data-ng-repeat="user in users">
<td>
<input type="checkbox" ng-change="storeIndexOfRow($index)">
</td>
<td>{{user.country}}</td>
<td>{{user.name}}</td>
</tr>
<button data-ng-click="removeUserData()" data-ng-show="users.length">Remove User</button>
Controller
var app = angular.module("myApp", []);
angular
.module('myApp')
.controller('myCtrl', ['$scope',
function ($scope) {
$scope.users = [
{ country: 'india', name: 'name1' },
{country: 'india2', name: 'name2'}
];
$scope.selectedIndex = [];
$scope.storeIndexOfRow = function (val) {
//write the logic for if checbox is checked or not
$scope.selectedIndex.push(val);
console.log($scope.selectedIndex);
};
$scope.removeUserData = function () {
angular.forEach($scope.selectedIndex, function (v, k) {
console.log($scope.users[v]);
});
};
}]);
One option is to use the ng-model to store a map that will decide for each row if it should be deleted or not,
The ng-model will bind the checkbox value to the given expression, in our case to a map.
for more information about ng-model see official documenation
the map will use user.id as a key, and will store a boolean value, based on the checkbox value.
lets call that map shouldDeleteUserMap.
Then we can filter your users array before sending it back to the server, based on shouldDeleteUserMap.
<table border="2" border-color=black>
<tr data-ng-repeat="user in users">
<td><input type="checkbox" ng-model='shouldDelteUserMap[user.id]' ></td><td>{{user.id}}</td><td>{{user.country}}</td><td>{{user.name}}</td>
</tr>
</table><br>
<button data-ng-click="removeUserData()" data-ng-show="users.length">Remove User</button>
and your controller, would look a bit like this:
angular.module('app',[])
.controller('myCtrl', function($scope){
$scope.shouldDelteUserMap = {};
$scope.users = [{
id: 1,
country: 'USA',
name: 'john'
},
{
id: 2,
country: 'Germany',
name: 'jane'
}];
$scope.removeUserData = function(){
var usersToRemove = $scope.users.filter( function(user){
return $scope.shouldDelteUserMap[user.id];
});
console.log(usersToRemove); // here comes your function that calls the server
}
});
and here is jsbin with an example:
http://jsbin.com/jisigiboha/edit?html,css,js,console,output
Functionality I want to implement is that when I click on "select All" checkbox, I want to push the selected item in new array and delete from current one.
Tried with splice function, but not able to delete all items from the first table.
enter code hereHere is the sample plnkr I have created, So when I click on "select All" from first table, all its items should get pushed in "New Table" and at the same time removed from "First table(named Old table)
This will clear your array and push all entries in $scope.merged
$scope.pushlist = function(data){
for(var item of data){
$scope.merged.push({"name":item.name});
}
data.length=0
};
Use angular.copy to make an copy of the object
var app = angular.module("myApp", []);
app.controller("SecondCtrl", function($scope) {
$scope.merged = [];
$scope.data = [{
"name": "ABC",
"selected": false
}, {
"name": "HJK",
"selected": false
}, {
"name": "PQR",
"selected": false
}, {
"name": "LMN",
"selected": false
}];
$scope.selectall = function(checkAll) {
if (checkAll) {
$scope.merged = angular.copy($scope.data);
$scope.data.length = 0;
} else {
$scope.data = angular.copy($scope.merged);
$scope.merged.length = 0;
}
};
});
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.js"></script>
<div ng-app="myApp" ng-controller="SecondCtrl">
<div>
<h1>Old Table</h1>
<table>
<thead>
<th>
<input type="checkbox" ng-click="selectall(checkAll)" ng-model="checkAll">Select All</th>
<th>Name</th>
</thead>
<tbody>
<tr ng-repeat="item in data">
<td>
<input type="checkbox" ng-model="item.selected">
</td>
<td>{{item.name}}</td>
</tr>
</tbody>
</table>
</div>
<hr>
<div>
<h2>New Table</h2>
<table ng-show="merged">
<thead>
<th>Name</th>
</thead>
<tbody>
<tr ng-repeat="item in merged">
<td>{{item.name}}</td>
</tr>
</tbody>
</table>
</div>
</div>
Fiddle Demo
How can I check what is really happening in the below delete function? Every time I delete it says "Success" but the UI doesn't update .
HTML
<md-content >
<div id="main" class="well">
<table cellpadding="20" class="table table-bordered table-striped">
<tr>
<th ng-repeat="(head, value) in models[0]">
<span>{{head}}</span>
</th>
</tr>
<tr ng-repeat="row in models">
<td ng-repeat="(name, value) in row" ng-scope>
<span ng-click="" ng-bind="row[name]"></span>
</td>
<td >
<a target="_self" href="#" ng-click="downlaodId(row)">Downlaod</a>
</td>
<td >
<a target="_self" href="#" ng-click="deleteId(row)" confirmation-needed="Really Delete?">Delete</a>
</td>
</tr>
</table>
</div>
</md-content>
Controller
$scope.deleteId = function (idPassed) {
fileLoadService.delete({ 'id': idPassed.id }, function(successResult) {
alert('Deleted');
}, function (errorResult) {
// do something on error
if (errorResult.status === 404) {
alert('Ooops');
}
});
};
my UI looks like this after click delete
fileLoadservice
app.factory('fileLoadService', ['$resource',
function ($resource) {
return $resource(
"http://jsonplaceholder.typicode.com/todos/:id",
{ id: "#id" },
{ query: { 'method': 'GET', isArray: true }
});
}]);
As you can see from your code:
$scope.deleteId = function (idPassed) {
fileLoadService.delete({ 'id': idPassed.id },function(successResult) {
alert('Deleted');
}, function (errorResult) {
You are doing nothing to the current model, just sending an alert Deleted when you hit the delete button. If you want it to do something else..... you should put that functionality in the code.
For example:
$scope.deleteId = function (idPassed) {
fileLoadService.delete({ 'id': idPassed.id },function(successResult) {
var index = $scope.models.indexOf(idPassed);
$scope.models.splice(index, 1);
alert('Deleted');
}, function (errorResult) {
I have a list of several objects and at the beginning I want to load just some of them. I took a look at the statement ng-repeat, but I need to have a structure like this:
<table class="table table-hover table-hidden">
<thead>
<tr>
...
</tr>
</thead>
<tbody>
<tr ng-repeat-start="object in objects | filter:query | orderBy:predicate:reverse" ng-init="isCollapsed=true">
...
</tr>
<tr ng-repeat-end class="more">
...
</tr>
</tbody>
</table>
I tried to apply the statement limitTo inside ng-repeat-start, in this way:
<tr ng-repeat-start="object in objects | filter:query | orderBy:predicate:reverse| limitTo: limit" ng-init="isCollapsed=true">
and on controller I wrote:
$scope.limit = 10;
$scope.incrementLimit = function () {
$scope.limit += 10;
};
The function incrementLimit is called by a click on hyperlink
<a href ng-click="incrementLimit()">more</a>
The list of objects is instantiated and filled (with all the elements) when the page loads.
With my approach at the beginnig are loaded and showed first 10 elements correctly, and when I click on "more" the variable $scope.limitis incremented, but on the page nothing happens. Anyone can explain me why?
limitTo is working fine inside ng-repeat-start
Take a look at this
var app = angular.module('myApp', []);
app.controller('Controller', function ($scope) {
$scope.limit = 1;
$scope.incrementLimit = function () {
$scope.limit += 1;
};
$scope.data = [{
title: 'Foo',
text: 'Lorem'
}, {
title: 'Bar',
text: 'Iste'
}, {
title: 'Jon',
text: 'Fat'
}, {
title: 'Los',
text: 'Ice'
}]
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
<div ng-app='myApp' ng-controller="Controller">
<table border="2" class="table table-hover table-hidden">
<thead>
<tr>...</tr>
</thead>
<tbody>
<tr ng-repeat-start="object in data | filter:query | orderBy:predicate:reverse| limitTo: limit" ng-init="isCollapsed=true" ng-bind="object.title">...</tr>
<tr ng-repeat-end class="more">...</tr>
</tbody>
</table>
more
</div>
Please check the below code and fiddle it is working fine
<body ng-controller="myController">
<button ng-click="incrementLimit()" >increment</button> <br/>
<table class="table table-hover table-hidden">
<thead>
<tr clospan="3">
Head
</tr>
</thead>
<tbody>
<tr ng-repeat-start="friend in objects|limitTo: limit" ng-init="isCollapsed=true">
<td>{{friend.name}}</td>
<td>{{friend.phone}}</td>
<td>{{friend.age}}</td>
</tr>
<tr ng-repeat-end class="more">
<td colspan="3">Footer</td>
</tr>
</tbody>
</table>
</table>
</body>
js code
app = angular.module("app", []);
app.controller("myController", function($scope) {
$scope.objects =
[{
name: 'John',
phone: '555-1212',
age: 10
}, {
name: 'Mary',
phone: '555-9876',
age: 19
}, {
name: 'Mike',
phone: '555-4321',
age: 21
}, {
name: 'Adam',
phone: '555-5678',
age: 35
}, {
name: 'Julie',
phone: '555-8765',
age: 29
}];
$scope.limit = 2;
$scope.incrementLimit = function () {
$scope.limit += 1;
};
});
Fiddle http://jsbin.com/hoguxexuli/1/edit
I solved my problem. Basically I put the hyperlink in a different div, so the controller and the $scope were also different. It was a stupid carelessness.
I have consulted these related articles, but the presented solutions do not work:
Clickable bootstrap row with angular
Adding parameter to ng-click function inside ng-repeat doesn't seem to work
Angular ng-click not working in div
Here is my plunkr:: http://plnkr.co/edit/kha6mAKDBtrY0XtTc6Wp?p=preview
<body ng-controller="MainCtrl">
<table>
<caption>Troubles with ng-repeat and ng-click</caption>
<thead>
<tr>
<th>Name</th>
<th>Occupation</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="employee in employees" ng-click="alert('hi')">
<td>{{employee.name}}</td>
<td>{{employee.occupation}}</td>
</tr>
</tbody>
</table>
var app = angular.module("plunker", []);
app.controller("MainCtrl", function($scope) {
$scope.employees = [
{
name: "John Doe",
occupation: "Miner"
},
{
name: "Theressa",
occupation: "Construction Worker"
}
]
});
It does work, but alert is not part of your $scope so it won't do anything.
You can add it in your controller:
$scope.alert = function(message) { alert(message); }