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); }
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
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)
I want to make a custom directive with the jquery plugin timepicker. I'm not getting the input value in the console, it says undefined.
here's a plunkr
<table class="table table-bordered">
<thead>
<tr>
<th>Time From</th>
<th>Time To</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<input type="text" ng-model="row1" size=6/ disabled>
</td>
<td>
<input type="text" ng-model="dup_row1 " size=6 timepicki/>
{{dup_row1}}
</td>
</tr>
</tbody>
</table>
var app = angular.module('myApp', []);
app.directive('timepicki', [
function() {
var link;
link = function(scope, element, attr, ngModel) {
element.timepicki();
};
return {
restrict: 'A',
link: link,
require: 'ngModel'
};
}
])
app.controller('ctrl', function($scope) {
$scope.row1 = "00:00"
$scope.submit=function(){
console.log($scope.dup_row1)
}
});
The code you've posted is not the same as the code in your plunker.
The AngularJS Developer Guide says;
Use controllers to:
Set up the initial state of the $scope object.
In your example above, you log the value of $scope.dup_row1 on submit, but your controller never sets that value, and as such it is undefined.
The following will print "hello" to the console;
app.controller('ctrl', function($scope) {
$scope.row1 = "00:00"
$scope.dup_row1 = "hello"
$scope.submit=function(){
console.log($scope.dup_row1)
}
});
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'm starting to learn some AngularJS and am trying to determine its practicality when working along side ASP.NET MVC.
Let's say I have a view which displays beers from a repository in a table. I could output the information in two ways.
1.Using MVC's Razor Engine
Here, the model containing the beers is processed on the server and the html page rendered.
<h3>Rendered using Razor!</h3>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Colour</th>
<th>Tasted?</th>
</tr>
</thead>
<tbody>
#foreach (var beer in Model)
{
<tr>
<td>#beer.Name</td>
<td>#beer.Colour</td>
<td>#beer.Tried</td>
</tr>
}
</tbody>
</table>
2.Using Angular repeat
Here, the HTML is returned straight away and angular performs a AJAX call to the controller to retrieve its model. After it has that data it outputs it into the table.
<h3>Rendered using Angular!</h3>
<table class="table table-condensed table-striped">
<thead>
<tr>
<th>Name</th>
<th>Colour</th>
<th>Tasted?</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="beer in model">
<td>{{ beer.Name }}</td>
<td>{{ beer.Colour }}</td>
<td>{{ beer.Tried }}</td>
</tr>
</tbody>
</table>
Controller
angular.module('BeerController', [])
.controller('BeerCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.model = {};
$http.get('/Beer/GetBeers').success(function (data) {
$scope.model = data;
});
}]);
My Question
Is there a way to use the Razor engine for the initial load of the data and Angular for everything else (paging calls, searching etc.)? In other words, how do I bind existing html to a controllers model in AngularJS?
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Colour</th>
<th>Tasted?</th>
</tr>
</thead>
<tbody>
<tr>
<td>Fosters</td>
<td>Gold</td>
<td>True</td>
</tr>
<tr>
<td>Becks</td>
<td>Amber</td>
<td>False</td>
</tr>
<tr>
<td>Cobra</td>
<td>Gold</td>
<td>True</td>
</tr>
</tbody>
</table>
In your MVC Controller
public ActionResult Index()
{
var model =.....
//optional
JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() };
ViewBag.data = JsonConvert.SerializeObject(model, Formatting.Indented, jsonSerializerSettings);
return View()
}
In your view Index.cshtml
...
#section Scripts {
//make sure that all anular scripts are loaded before that
<script>
angular.module('BeerController').service('dataService', function () {
var data= #Html.Raw(ViewBag.data);
return {
data:data
}
});
...
</script>
}
Angular Part:
angular.module('BeerController', [])
.controller('BeerCtrl', ['$scope', '$http','dataService', function ($scope, $http,dataService) {
// now you can get data from your dataService without extra trip to your server
$scope.model = dataService.data
....
}]);