I would like to swap 2 columns in a table. Finally, I succeeded the change, but only the data. The attributes of the cell (style, id, class) didn't move. I tried to move attributes with jquery (i know, not an elegant method), but it was only symptomatic treatment. After clicking the data reload button, the attributes restored.
How can I change the columns order with all attributes?
my code: https://codepen.io/qwertz_/pen/YxWMBO
<!DOCTYPE html>
<html>
<head>
<title>angT</title>
<script type="text/javascript" src="http://code.angularjs.org/angular-1.0.0rc10.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<style>
th, td{padding: 3px 20px;border: 1px solid red;}
</style>
</head>
<body>
<div ng-controller="MyCtrl" ng-app="myApp">
<button ng-click="swap(0)">first2second</button>
<button ng-click="reload()">reload</button>
<table id="myTable" >
<tr ng-repeat="row in ths">
<th class="oo1">{{col(row, 0)}}</th>
<th class="oo2">{{col(row, 1)}}</th>
<th class="oo3">{{col(row, 2)}}</th>
<th class="oo4">{{col(row, 3)}}</th>
</tr>
<tr ng-repeat="row in rows">
<td class="o1" style="background-color:yellow;">{{col(row, 0)}}</td>
<td class="o2" style="background-color:pink;">{{col(row, 1)}}</td>
<td class="o3" style="background-color:green;">{{col(row, 2)}}</td>
<td class="o4" style="background-color:blue;">{{col(row, 3)}}</td>
</tr>
</table>
</div>
<script type='text/javascript'>
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.mycol = new Array();
$scope.mycol[0] = 'id';
$scope.mycol[1] = 'name';
$scope.mycol[2] = 'db';
$scope.mycol[3] = 'let';
$scope.reload = function()
{
$scope.rows=[{id:parseInt(Math.random()*10000),name:"Liv","db":21,let:"r"},{id:parseInt(Math.random()*10000),name:"Mike",db:30,let:"u"}];
};
$scope.swap = function(i) {
var temp = $scope.mycol[i];
$scope.mycol[i] = $scope.mycol[(i+1)];
$scope.mycol[(i+1)] = temp;
};
$scope.col = function(row, mycol) {
return row[$scope.mycol[mycol]];
};
$scope.reload();
$scope.ths=[{id:"id",name:"name","db":"db",let:"letter"}];
}
</script>
</body>
Thx a lot
Simple way
You can bind colors to header name as:
$scope.styles = {
id: "yellow",
name: "pink"
};
and table will look like:
<tr ng-repeat="row in rows">
<td class="o1" ng-style="{'background-color':styles[mycol[0]]}">{{col(row, 0)}}</td>
<td class="o2" ng-style="{'background-color':styles[mycol[1]]}">{{col(row, 1)}}</td>
<td class="o3" style="background-color:green;">{{col(row, 2)}}</td>
<td class="o4" style="background-color:blue;">{{col(row, 3)}}</td>
</tr>
Once header value changes, colors will change too
Codepen DEMO
More complicated but generic
You can achieve it by replacing all table with directive (headers + data) and by using $compile rebuild all HTML table.
Related
I am extremely new to AngularJS and JavaScript in general so any help would be appreciated!
I have two data sources Users and Pets - both are Array objects and I want them to display in a table on different pages of my site. I have an app.module.js which calls the module petsapp or usersapp Currently the controller only being called is the petspp.
I have tried to use $scope but I don't really know what I'm doing!
I currently have set up an app.module.js, which looks like this (but possibly wrong:
(function(){
'use strict';
angular.module('petsapp',[]);
angular.module('usersapp',[]);
})();
another file called **Pets.controller.js:**
(function () {
'use strict';
angular
.module('petsapp')
.controller('PetsController', function ($scope) {
})
PetsController.$inject = ['$http'];
function PetsController($http) {
var vm = this;
vm.pets = [];
vm.getAll = getAll();
vm.deletePet = deletePet();
init();
function init(){
getAll();
}
and a users.controller.js which looks like this:
(function () {
'use strict';
angular
.module('usersapp')
.controller('UsersController', UsersController)
UsersController.$inject = ['$http'];
function UsersController($http) {
var vm = this;
vm.users = [];
vm.getAll = getAll()
vm.delete = deleteUser()
init();
function init(){
getAll();
}
my pets html (working) is:
<!DOCTYPE html>
<script type="text/javascript"src="/static/angular.min.js" th:src="#{/angular.min.js}"></script>
<script type="text/javascript"src="/static/app/app.module.js" th:src="#{/app/app.module.js}"></script>
<script type="text/javascript"src="/static/app/pets.controller.js" th:src="#{/app/pets.controller.js}"></script></head>
<header th:insert="fragments.html :: nav"></header>
<body ng-app="petsapp" ng-controller="PetsController as vm">
<!-- Page content goes here -->
<div>
<div class="row">
<div class="col-lg-offset-2 col-lg-8">
<!-- Display animals in a table -->
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Type</th>
<th>Gender</th>
<th>Breed</th>
<th>Age</th>
<th>OK with Children?</th>
<th style="width: 100px"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="pet in vm.pets">
<td>{{pet.id}}</td>
<td>{{pet.animalName}}</td>
<td>{{pet.animal}}</td>
<td>{{pet.gender}}</td>
<td>{{pet.breed}}</td>
<td>{{pet.age}}</td>
<td>{{pet.compWithChildren}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>.
my users html (not working as it is only pulling the pets.controllers.js) is:
<head th:insert="fragments.html :: headerfiles">
<script type="text/javascript"src="/static/angular.min.js" th:src="#{/angular.min.js}"></script>
<script type="text/javascript"src="/static/app/app.module.js" th:src="#{/app/app.module.js}"></script>
<script type="text/javascript"src="/static/app/users.controller.js" th:src="#{/app/users.controller.js}"></script>
</head>
<header th:insert="fragments.html :: nav"></header>
<body ng-app="usersapp" ng-controller="UsersController as vm">
<!-- Page content goes here -->
<div>
<div class="row">
<div class="col-lg-offset-2 col-lg-8">
<!-- Display animals in a table -->
<table class="table">
<thead>
<tr>
<th>User Name</th>
<th>Roles</th>
<th>Email</th>
<th>Contact Number</th>
<th style="width: 100px"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="userdetail in vm.users">
<td>{{userdetail.username}}</td>
<td>{{userdetail.roles}}</td>
<td>{{userdetail.email}}</td>
<td>{{userdetail.contactNo}}</td>
<td>
<!--Only Admin can delete rows --->
<button class="btn btn-danger" ng-click="vm.deleteUser(userdetail.id)">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html
I think the problem is in the app.module.js file where I've defined two modules?
do I need to combine both controllers into one file? if so how do I implement that?
I 'm working on my AngularFire project. I've a database something like this https://dinosaur-facts.firebaseio.com/. What I'm doing is first searching the key like the dinosaurs child such as "linhenykus" and storing its keys and values to other $scope variable.
my code in controller
var ref = new Firebase("https://dinosaur-facts.firebaseio.com/dinosaurs" + "/" + $scope.dinoID); //$scope.dinoID is variable containg dino keys
$scope.detRef = $firebaseArray(ref);
I'm getting the output like
[{"$value":-85000000,"$id":"appeared","$priority":null},{"$value":0.6,"$id":"height","$priority":null},{"$value":1,"$id":"length","$priority":null},{"$value":"theropoda","$id":"order","$priority":null},{"$value":-75000000,"$id":"vanished","$priority":null},{"$value":3,"$id":"weight","$priority":null}]
How to fetch the keys and values?
Use ngRepeat directive, as below:
<tr ng-repeat="obj in array track by $index">
To filter the array you can use the filter of Angular:
<tr ng-repeat="obj in array | filter: criteria track by $index">
Here's an example:
(function() {
angular
.module('app', [])
.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope', '$filter'];
function MainCtrl($scope, $filter) {
$scope.criteria = {};
$scope.array = [
{
"$value":-85000000,
"$id":"appeared",
"$priority":null
},
{
"$value":0.6,
"$id":"height",
"$priority":null
},
{
"$value":1,
"$id":"length",
"$priority":null
},
{
"$value":"theropoda",
"$id":"order",
"$priority":null
},
{
"$value":-75000000,
"$id":"vanished",
"$priority":null
},
{
"$value":3,
"$id":"weight",
"$priority":null
}
];
$scope.getObj = function(value, id) {
$scope.obj = $filter('filter')($scope.array, {
"$value": value,
"$id": id
})[0];
}
$scope.getObj("theropoda", "order");
}
})();
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
<!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">
<input type="text" placeholder="Search by value" ng-model="criteria.$value">
<input type="text" placeholder="Search by id" ng-model="criteria.$id">
<!-- Note that this button is just as an example to change the object displayed below -->
<button type="button" ng-click="getObj()">Change the value of object</button>
<hr>
Obj: <span ng-bind-template="Value: {{obj.$value}}, Id: {{obj.$id}}"></span>
<p></p>
<table width="100%">
<thead>
<tr>
<th>Value</th>
<th>Id</th>
<th>Priority</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="obj in array | filter: criteria track by $index">
<td ng-bind="obj.$value"></td>
<td ng-bind="obj.$id"></td>
<td ng-bind="obj.$priority"></td>
</tr>
</tbody>
</table>
</body>
</html>
I am creating a table using ng-repeat that display some tickets info. Currently in the column "Ticket No" I am adding href link (when user click on the "Ticket No" it will open new tab and the URL will take the ticket no as parameter.
This a plunker I've created so it can show functionality as described above http://plnkr.co/edit/GB8WWz?p=preview
The problem I have now is that the href link might vary and it depends on the account column value. So if my "account = foo" set the href link of the Ticket No to "http://myfoopage.foo/ticketid...etc". If my "account = boo" set the href link for the Ticket No to "http://myboopage.boo/ticketid...etc".
Any idea on how to approach that ?
scriptang.js
angular.module('plunker', ['ui.bootstrap']);
function ListCtrl($scope, $dialog) {
$scope.items = [
{ticket: '123', description: 'foo desc',account:'foo'},
{ticket: '111', description: 'boo desc',account:'boo'},
{ticket: '222', description: 'eco desc',account:'eco'}
];
}
// the dialog is injected in the specified controller
function EditCtrl($scope, item, dialog){
$scope.item = item;
$scope.save = function() {
dialog.close($scope.item);
};
$scope.close = function(){
dialog.close(undefined);
};
}
index.html
<!doctype html>
<html ng-app="plunker">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script src="http://angular-ui.github.com/bootstrap/ui-bootstrap-tpls-0.1.0.js"></script>
<script src="scriptang.js"></script>
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.0/css/bootstrap-combined.min.css" rel="stylesheet">
</head>
<body>
<div ng-controller="ListCtrl">
<table class="table table-bordered">
<thead>
<tr>
<th>Ticket No</th>
<th>Description</th>
<th>Account</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td>{{item.ticket}}</td>
<td>{{item.description}}</td>
<td>{{item.account}}</td>
<td><button class="btn btn-primary" ng-click="edit(item)">Edit</button></td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
Updated plnkr here, I've made use of the ng-attr directive in combination with a function that creates an url.
$scope.getUrl = function (item) {
var url = '';
if(item.account === 'foo')
url = 'http://mywebpage.foo';
else
url = 'http://mwebpage.boo';
url += '/ticketid='+item.ticket
return url;
}
I have a table which I'm trying to create from a scope-object that I'm creating in my controller.
I would like the headers to take the value from 'rowHeader', which works fine. But the problem is that I wan't my cell values to be taken from 'cellValue' property.
In my fiddle I've added a "Desired table", thats how I would like the results to be in my first approach. If possible..
As you can see I would like to use a filter on one of the columns as well.
The reason that I would like to use this approach is so that I can use the checkboxlist to hide/show columns, and of course so that I can setup my table easy within the controller
Fiddle: http://jsfiddle.net/HB7LU/21469/
<!doctype html>
<html ng-app="plunker">
<head>
<script data-require="angular.js#*" data-semver="1.2.0" src="http://code.angularjs.org/1.2.0/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<div ng:controller="MainCtrl">
<p>My table</p>
<table border="1">
<thead style="font-weight: bold;">
<tr>
<th class="text-right" ng-repeat="column in columnsTest" ng-if="column.checked" ng-bind="column.rowHeader"></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="row in rows" border="1">
<td ng-repeat="column in columns" ng-if="column.checked" ng-bind="row[column.cellValue]"></td>
</tr>
</tbody>
</table>
<p>Visible Columns:</p>
<br />
<div class="cbxList" ng-repeat="column in columnsTest">
<input type="checkbox" ng-model="column.checked">{{column.rowHeader}}
</div>
</div>
<script>
var app = angular.module('plunker', []);
app.filter('percentage', function () {
return function (changeFraction) {
return (changeFraction * 100).toFixed(2) + "%";
}
});
app.controller('MainCtrl', function($scope) {
$scope.columnsTest = [
{ checked: true, cellValue: 'ModelName', rowHeader: 'Name' },
{ checked: true, cellValue: 'value1', rowHeader: 'PL' },
{ checked: true, cellValue: 'value1 / value2 | percentage', rowHeader: '+/-' }
];
$scope.rows = [
{ value1: 100, value2: 5, ModelName: "This is a cell value" },
{ value1: 15, value2: 5, ModelName: "This is a cell value2" },
{ value1: 38, value2: 2, ModelName: "This is a cell value3" }
];
});
</script>
</body>
</html>
There is a typo in the code cause the problem:
<tr ng-repeat="row in rows" border="1">
<td ng-repeat="column in columns"
ng-if="column.checked" ng-bind="row[column.cellValue]"></td>
</tr>
You don't have a scope variable called columns, change it to columnsTest.
<tr ng-repeat="row in rows" border="1">
<td ng-repeat="column in columnsTest"
ng-if="column.checked" ng-bind="row[column.cellValue]"></td>
</tr>
I am trying to learn AngularJS and i am making a test app.
I have a table that gets populated with data returned from a WebService (list of publishers) via $http.get().
When the user clicks a row (publisher) i want to fill a second table with the list of employees of the selected publisher. By using the F12 tools (Network+Console) i see that the data is returned but the second table is not filled/updated.
html
<!DOCTYPE html>
<html ng-app="myApp">
<head lang="en">
<meta charset="UTF-8">
<link rel="stylesheet" href="css/style.css" type="text/css" />
<script src=""></script>
<script src="js/angular.js"></script>
<script src="js/scripts.js"></script>
<script src="js/app.js"></script>
<title>My SPA</title>
</head>
<body>
<header>
<h1 id="page-title">Header</h1>
<nav>
<ul>
<li>Menu 1</li>
<li>Menu 2</li>
<li>Menu 3</li>
<li>Menu 4</li>
</ul>
</nav>
</header>
<div ng-controller='PublishersController' class="table-wrapper">
<table class="data-table" />
<thead>
<tr>
<th ng-repeat="(key,val) in publishers[0]">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='pub in publishers' ng-click='getPublishersEmployees(pub.pub_id)'>
<td ng-repeat='(key,val) in pub'>{{val}}</td>
</tr>
</tbody>
</table>
</div>
<div ng-controller='PublishersController' class="table-wrapper">
<table class="data-table" />
<thead>
<tr>
<th ng-repeat="(key,val) in employees[0]">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='employee in employees'>
<td ng-repeat='(key,val) in employee'>{{val}}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>
JS
var urlBase = "http://localhost:2041";
var app = angular.module('myApp', []);
app.factory('myFactory', ['$http', function ($http) {
var webAPI = '/api/query';
var webService = urlBase + webAPI;
var myFactory = {};
myFactory.getCategories = function () {
return $http.get(webService + '/getCategories');
};
myFactory.getCategorySalesByMonth = function (id) {
return $http.get(webService + '/getCategorySalesByMonth/' + id);
};
myFactory.getPublishers = function () {
return $http.get(webService + '/getPublishers');
};
myFactory.getPublishersEmployees = function (id) {
return $http.get(webService + '/getPublishersEmployees/' + id);
};
return myFactory;
}]);
app.controller('PublishersController', ['$scope', 'myFactory',
function ($scope, myFactory) {
$scope.status;
$scope.publishers;
$scope.employees;
getPublishers();
function getPublishers() {
myFactory.getPublishers()
.success(function (publishers) {
$scope.publishers = publishers;
})
.error(function (error) {
$scope.status = 'Unable to load publishers data: ' + error.message;
});
}
$scope.getPublishersEmployees = function (id) {
myFactory.getPublishersEmployees(id)
.success(function (employees) {
$scope.employees = employees;
console.log($scope.employees);
})
.error(function (error) {
$scope.status = 'Error retrieving employees! ' + error.message;
});
};
}]);
What am i doing wrong?
The problem is you use separate controllers for PublishersController and EmployeesController. Angular will create separate scopes for your controllers. Therefore, when you assign $scope.employees = employees in your PublishersController, it does not reflect on the scope created by EmployeesController
Try:
<div ng-controller='PublishersController' class="table-wrapper">
<table class="data-table" />
<thead>
<tr>
<th ng-repeat="(key,val) in publishers[0]">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='pub in publishers' ng-click='getPublishersEmployees(pub.pub_id)'>
<td ng-repeat='(key,val) in pub'>{{val}}</td>
</tr>
</tbody>
</table>
<table class="data-table" />
<thead>
<tr>
<th ng-repeat="(key,val) in employees[0]">{{key}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat='employee in employees'>
<td ng-repeat='(key,val) in employee'>{{val}}</td>
</tr>
</tbody>
</table>
</div>
That solution above is just to point out your problem. I don't know your application design, you may not follow this solution but restructure your code to best fit your application design (like storing the employees in a shared service,...).
Here I propose another solution but I'm not sure if it fits with your application. You just use your original HTML code with PublishersController and EmployeesController. In your PublishersController, your could broadcast an event from rootScope:
.success(function (employees) {
$rootScope.$broadcast("employeeLoaded",employees);
})
Don't forget to inject $rootScope to your PublishersController:
app.controller('PublishersController', ['$scope', 'myFactory','$rootScope',
function ($scope, myFactory,$rootScope)
In your EmployeesController, you could subscribe to this event:
$scope.$on("employeeLoaded",function (event,employees){
$scope.employees = employees;
});
For more information about event in angular, check out Working with $scope.$emit and $scope.$on