Am loading data from database to a table in html with angualar js. am also using interval so as to make the table reload every 10 seconds to get new data that has just been inputed by other users.
Problem:
The table blinks every time it reloads. making the page look funny like it has a glitch.
What am looking for:
Is there a way i can make the new data just slide in from the top of the table and become number one while the rest re adjust underneath it And become number two, three and so on. i was made to believe Angular Js is magical reason why i opted for it instead of using my usual AJAX
Angular Code
var supDetails = angular.module("supDetails", ['datatables']);
supDetails.controller('supportController', function($scope, $http, $interval) {
$scope.names = [];
$scope.isFirst = true;
$scope.loadData = function() {
var httpRequest = $http({
method: 'GET',
url: 'anfil.php?ins=sup'
}).success(function(data, status) {
console.log('loading..');
$scope.names = data;
if(!$scope.isFirst){
angular.forEach(data,function(key,val){
$scope.names[key] = data[key];
});
}
$scope.isFirst = false;
});
};
$scope.loadData();
// Function to replicate setInterval using $timeout service.
$interval(function () {
$scope.loadData();
}, 10000);
});
My HTML
<!-- /.col -->
<div class="col-md-9" ng-app = "supDetails" ng-controller="supportController">
<div class="box box-primary">
<div class="box-header with-border">
<h3 class="box-title">Messages</h3>
<!-- /.box-tools -->
<div class="box-tools pull-right">
<div class="has-feedback">
<button type="button" ng-click="loadData()" class="btn btn-default btn-sm"><i class="fa fa-refresh"></i></button>
</div>
</div>
</div>
<!-- /.box-header -->
<div class="box-body no-padding">
<div class="mailbox-messages">
<table datatable="ng" class="table table-hover table-striped">
<thead>
<tr>
<th>Stat</th>
<th>Name</th>
<th>Problem</th>
<th>Time</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="x in names">
<td class="mailbox-star"><i class="fa fa-circle text-blue"></i></td>
<td class="mailbox-name">{{x.user_id}}</td>
<td class="mailbox-subject"><b>{{x.ticket_title}}</b> - {{x.subject}}
</td>
<td class="mailbox-date">{{x.ticket_open_date}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>Stat</th>
<th>Name</th>
<th>Problem</th>
<th>Time</th>
</tr>
</tfoot>
</table>
<!-- /.table -->
</div>
<!-- /.mail-box-messages -->
</div>
<!-- /.box-body -->
</div>
<!-- /. box -->
</div>
<!-- /.col -->
I think its your css problem which doesn't have a minimum height as you can see in this snippet its not blinking..
If you still want data to appear slide from up to down, You can uncomment the code in the answer, in this way it will remove row one by one from the table and replace it with the new one.
var app = angular.module('myApp', []);
function PeopleCtrl($scope, $http,$interval) {
$scope.people = [];
$scope.isFirst = true;
$scope.loadPeople = function() {
var httpRequest = $http({
method: 'GET',
url: 'https://jsonplaceholder.typicode.com/users'
}).success(function(data, status) {
console.log('loading..');
$scope.people = data;
/* if(!$scope.isFirst){
angular.forEach(data,function(val,key){
$scope.people[key] = data[key];
});
}
$scope.isFirst = false;*/
});
};
$scope.loadPeople();
$interval(function () {
$scope.loadPeople();
}, 10000);
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<div ng-app="myApp">
<div ng-controller="PeopleCtrl">
<table class="table">
<tr>
<th>Id</th>
<th>Name</th>
<th>UserNmae</th>
</tr>
<tr ng-repeat="person in people">
<td>{{person.id}}</td>
<td>{{person.name}}</td>
<td>{{person.username}}</td>
</tr>
</table>
</div>
</div>
There are a few ways to solve your problems:
1) Write algorithm, that load your data then compare it with existing data. If there any diffs you, should add just new records to your table.
2) Use WebSockets, they will give you ability to get from server only new records in real-time.
Related
I have gathered some JSON (dummy) data in a users table.
var root = 'https://jsonplaceholder.typicode.com';
// Create an Angular module named "usersApp"
var app = angular.module("usersApp", []);
// Create controller for the "usersApp" module
app.controller("usersCtrl", ["$scope", "$http", function($scope, $http) {
var url = root + "/users"
$http.get(url)
.then(function(data) {
$scope.users = data.data;
});
}]);
.search-box {
margin: 5px;
}
.panel-heading {
font-weight: bold;
}
.table-container .panel-body {
padding: 0;
}
.table-container table tr th {
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<div class="container" data-ng-app="usersApp">
<div class="panel panel-default table-container">
<div class="panel-heading">Users</div>
<div class="panel-body" data-ng-controller="usersCtrl">
<div class="row">
<div class="col-sm-12">
<div class="form-group search-box">
<input type="text" class="form-control" id="search" placeholder="Search User" data-ng-model="search">
</div>
</div>
<div class="col-sm-12">
<table class="table table-striped" id="dataTable">
<thead>
<tr>
<th>Full name</th>
<th>Email</th>
<th>City</th>
<th>Street</th>
<th>Suite</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="user in users|filter:search">
<td>{{user.name}}</td>
<td>{{user.email}}</td>
<td>{{user.address.city}}</td>
<td>{{user.address.street}}</td>
<td>{{user.address.suite}}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
The table has only 10 rows but, in a real-world app, there is a lot more data to manage so it needs to be paginated. The above one could have 3 rows per page (except the 4th one, which should have one).
Question(s):
Does AngularJS have a built-in, easy way to paginate such a table?
If not, what are the best alternatives?
Angularjs don't have built-in pagination feature. You have to use some third-party modules like angular-ui-grid. OR you can try this <https://codepen.io/khilnani/pen/qEWojX>
You can use ngInfiniteScroll for pagination. https://sroze.github.io/ngInfiniteScroll/
I am using a table and a button inside the table pops up a modal. I want to pass the Id value in that row to the modal controller so that I can use it to pass it to the the rest api call and then subsequently load valus in the modal table.
App.js
var app = angular.module("UiApp", ["ServiceApp"]);
app.service('sharedProperties', function () {
var idValue = 'test string value';
return {
getId: function () {
return idValue;
},
setId: function (value) {
idValue = value;
}
}
});
app.controller("PortFolioController", function ($scope, GetPortfolios,sharedProperties) {
$scope.Portfolios = GetPortfolios.query({ pmid: 2 });
console.log($scope.Portfolios);
$scope.addOrder = function (id) {
sharedProperties.setId(id)
};
});
app.controller("OrderController", function ($scope, GetOrders,sharedProperties) {
$scope.item = sharedProperties.getId();
$scope.Orders = GetOrders.query({ id: item});
});
Service.js
var app = angular.module("ServiceApp", ["ngResource"]);
app.factory('GetPortfolios', function ($resource) {
return $resource("http://localhost:61347/api/PortfolioManager/GetPortfolios/");
});
app.factory('GetOrders', function ($resource) {
return $resource("http://localhost:61347/api/PortfolioManager/GetPortfolioOrders/");
});
HTML
<div >
<table class="table table-striped table-hover table-bordered" id="editable-sample" ng-controller="PortFolioController">
<thead>
<tr>
<th>Portfolio ID</th>
<th>Portfolio Name</th>
<th>Portfolio Type</th>
<th>Portfolio Description</th>
<th>Show Stocks</th>
</tr>
</thead>
<tbody>
<tr class="" ng-repeat="portfolio in Portfolios">
<td>{{portfolio.portfolioId}}</td>
<td>{{portfolio.portfolioName}}</td>
<td>{{portfolio.type}}</td>
<td>{{portfolio.description}}</td>
<td> <button type="button" class="btn btn-primary btn-xs" data-toggle="modal" data-target="#myModal" ng-click="addOrder(portfolio.portfolioId)" >Show <i class="fa fa-info-circle"></i></button></td>
</tr>
</tbody>
</table>
</div>
</div>
<!--Modal start-->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">My Portfolio</h4>
</div>
<div class="modal-body">
<h3>Stock List</h3>
<div class="space15"></div>
<table class="table table-striped table-hover table-bordered" id="editable-sample" ng-controller="OrderController">
<thead>
<tr>
<th>Symbol</th>
<th>Stock Name</th>
<th>Quantity</th>
<th>Market Price</th>
</tr>
</thead>
<tbody>
<tr class="" ng-repeat="order in Orders">
<td>{{order.symbol}}</td>
<td>{{order.executedQuantity}}</td>
<td>{{order.price}}</td>
<td>{{order.createTStamp}}</td>
</tr>
</tbody>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close <i class="fa fa-times"></i></button>
</div>
In PortFolioController Controller, you can do:
$rootScope.$broadcast('eventName', id);
and listen to the event in OrderController Controller:
$scope.$on('eventName', function (event, id) {...});
Also you can use AngularJS Service Passing Data Between Controllers to see some examples
or the simpleset way without any service is to use $rootScope and $broadcast an event from one Controller and listen to it in the other Controller
thus, No need of writing an extra service sharedProperties
Something like this :-
app.controller("PortFolioController", function ($scope, GetPortfolios,$rootScope) {
//Other Codes
$scope.addOrder = function (id) {
$rootScope.$broadcast('ID-Clicked', { Id: id});
};
}
app.controller("OrderController", function ($scope, GetOrders,$rootScope) {
//Other Codes
//Listen for the event
$rootScope.$on('ID-Clicked', function(event, data){
$scope.item = data.Id;// data.Id has the Clicked Id
});
}
This approach can be done using 2 ways.
First Way is to broadcast some events from the parent rootscope instance and capture that on the $scope elements.This format is not considered as a good way of coding.
Secondly, to communicate data between controllers use a service.Yeah you are currently on the right,clean & widely accepted path.
Remember that services are singletons.so once instansiated it is available to all controllers.But the challenge here is as soon as you click on button element your service sets your idValue in the service.Now how does the second controller know that.The answer would be register a $watch service to watch if the idValue in the service is changed as below.
app.controller("OrderController", function ($scope, GetOrders, sharedProperties) {
$scope.$watch(function () {
return sharedProperties.getId()
}, function (newValue, oldValue) {
if (newValue != oldValue) {
$scope.item = newValue;
$scope.Orders = GetOrders.query({ id: item });
}
});
});
I am creating an html page with two tabs. When you click on tab 1, it loads table data 1. When you click on tab 2,
it loads table data 2. Tab 1 is working as expected. However, when I click on tab 2, the data isn't loaded. The controllers
are identical. What is the difference?
Here is the relevant html code. tab with id "tableData" loads with data and tab with id "correlations" doesn't load.
<div>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation">Table Data</li>
<li role="presentation">Correlations</li>
</ul>
<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tableData">
<h2 class="sub-header">Health Data</h2>
<div class="table-responsive" data-ng-app="myApp" data-ng-controller="journalCtrl">
<div data-ng-include="'screens/tablescreen.html'"></div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="correlations">
<h2 class="sub-header">Correlations Data</h2>
<div class="table-responsive" data-ng-app="correlationsApp" data-ng-controller="correlationsCtrl">
<div data-ng-include="'screens/tablescreen.html'"></div>
</div>
</div>
</div>
</div>
Here is my correlationsCtrl. init() is never invoked. Why?:
var correlationsApp = angular.module('correlationsApp', []);
correlationsApp.controller('correlationsCtrl', function ($scope, $http) {
$scope.init = function () {
$http.get("https://localhost:4567/foo/1/correlations")
.then(function (response) {
var json = response.data.records;
$scope.records = json;
$scope.headers = response.data.headers;
});
};
//This is not invoked. Why?
$scope.init();
});
Here is my controller which does get invoked:
var app = angular.module('myApp', []);
app.controller('journalCtrl', function ($scope, $http) {
$scope.init = function () {
$http.get("https://localhost:4567/journal/1")
.then(function (response) {
var json = response.data.records;
$scope.records = json;
$scope.headers = response.data.headers;
});
};
//This is invoked on page load. Why does this work and the other doesn't?
$scope.init();
});
Here is the html table:
<table class="table table-striped">
<thead>
<tr>
<th data-ng-repeat="header in headers">{{header}}</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="record in records track by $index">
<td data-ng-repeat="header in headers">{{ record.data[header] }}</td>
</tr>
</tbody>
</table>
In html you declare data-ng-controller="fooCtrl" but you have no controller fooCtrl. No need to declare two different module for two tabs you can declare two controller for two tabs in same module.
like:
var app = angular.module('myApp',[]);
app.controller('correlationsCtrl', function ($scope, $http) {
$scope.init = function () {
// your code
};
$scope.init();
}).controller('journalCtrl', function ($scope, $http) {
$scope.init = function () {
// your code
};
$scope.init();
});
so you use ng-app = "myApp" in root element like <html ng-app="myApp"> or <body ng-app="myApp"> and use only data-ng-controller in your tab page.
<div class="table-responsive" data-ng-controller="journalCtrl">
<div data-ng-include="'screens/tablescreen.html'"></div>
</div>
and
<div class="table-responsive" data-ng-controller="correlationsCtrl">
<div data-ng-include="'screens/tablescreen.html'"></div>
</div>
See PLUNKER DEMO two tabs show data from two different controllers.
I need make in Angular table which will be generate dynamic numbers of column, but the number of column I need loading form data base and this information will be display number of columns which will be generated, and then will be loading date form another table in data base to this table (in HTML) but I need to load data only from 6 column to number which I was written about it at the beginning of this comment.
I know I need use ng-repeat on tr, td and write custom filter which display range columns on site, but I don't know how this all merge? How transfer from database (API) number which i use like variable and then add to filter where I use in for loop and then add this to view page where will be display beautiful table with data which I want?
Picture of the output you can see here.
My code so far - controller.js:
'use strict';
var pokayokaCtr = angular.module( 'pokayokaCtr' , [ 'ngRoute' ] );
// -------------------------------------------
// DRAWINGS
// -------------------------------------------
pokayokaCtr.controller( 'drawings' , [ '$scope' , '$http', function( $scope, $http ){
$http.get( 'api/admin/drawings/get' ).
success( function( data ){
$scope.drawings = data;
}).error( function(){
console.log( 'Błąd pobrania pliku z bazy danych! Drawings' );
});
}]);
pokayokaCtr.controller( 'drawingCreate' , [ '$scope' , '$http' , '$timeout', function( $scope , $http, $timeout){
$scope.createDrawing = function ( drawing ) {
$http.post('api/admin/drawings/create', {
drawing : drawing
}).success(function(){
$timeout(function(){
$scope.success = false;
$scope.drawing = {};
} , 1500 );
console.log($scope.drawing);
}).error(function(){
console.log('Error database connect!')
});
};
}]);
pokayokaCtr.controller( 'pokayokes' , [ '$scope' , '$http', '$routeParams', function( $scope, $http, $routeParams ){
var pokayokeName = $routeParams.name;
$scope.name = pokayokeName;
$http.get( 'api/admin/pokayokes/get/' + pokayokeName ).
success( function( data ){
$scope.pokayokes = data;
}).error( function(){
console.log( 'Error database connect!' );
});
}]);
// pokayokaCtr.filter('rangeFilter', function() {
// return function(input, total) {
// total = parseInt(total);
// for (var i=6; i<=total; i++)
// input.push(i);
// return input;
// };
// });
View page:
<div id="page-wrapper" ng-controller="pokayokes">
<div class="container-fluid">
<!-- Page Heading -->
<div class="row">
<div class="col-md-12">
<br>
<div class="flat-panel">
<div class="flat-panel-header">
<h2 class="page-header" ng-repeat="pokayoke in pokayokes | limitTo: 1"><i class="fa fa-paint-brush"></i> Drawing number: {{ pokayoke.nazwa_rys }}</span></h2>
</div>
<div class="flat-panel-body">
<button class="btn btn-warning" href="#"><i class="fa fa-pencil-square-o"></i> Edit name</button>
<button class="btn btn-danger pull-right" ng-click="delete(drawing, $index)"><i class="fa fa-times"></i> Delete</button>
</div>
</div>
</div>
</div>
<!-- /.row -->
<!-- /.row -->
<div class="row">
<div class="col-lg-12">
<div class="flat-panel">
<div class="flat-panel-header">
<h2 class="pull-left">Articles in drawing</h2>
<a ng-repeat="pokayoke in pokayokes | limitTo: 1" class="pull-right btn btn-primary" href="#/admin/article/create/part1/{{ pokayoke.nazwa_rys}}" style="margin: 20px 0 15px;"><i class="fa fa-plus"></i> Add new article</a>
</div>
<div class="clearfix"></div>
<div class="flat-panel-body">
<div class="table-responsive">
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>No.</th>
<th>Image</th>
<th>Article name <i class="fa fa-chevron-down"></i> </th>
<th>Colors in article</th>
<th ng-repeat="pokayoke in pokayokes">{{$index}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="pokayoke in pokayokes" >
<td>{{$index + 1}}</td>
<td> <i class="fa fa-picture-o"></i> View</td>
<td>{{pokayoke.nazwa_art}}</i> </td>
<td>{{pokayoke.kolory_art}}</td>
<td ng-repeat="num in pokayoke" >{{ num }}</td>
</tr>
</tbody>
</table>
</div> <!-- responive -->
</div>
</div>
</div>
</div>
<!-- /.row -->
</div>
<!-- /.container-fluid -->
</div>
<!-- /#page-wrapper -->
And output what I have now: here
I want only first 4 columns and columns where are 'x'.
I don't know how write filter.
I'm trying to practice angular and I'm stuck this this.
How do I make ng-click load the displayController? Or am I doing this wrong way?
The Angular
var bible = angular.module('bible', []);
// Load the Books
bible.controller('listController', ['$scope', '$http', function($scope, $http) {
$http.get('books.json').success(function(data) {
$scope.books = data
});
}]);
bible.controller('displayController', function($scope) {
$scope.test = "TEST TEXT";
});
The HTML
<div class="row">
<div class="col-md-12" ng-controller="listController">
<table class="table">
<thead>
<th>Testament</th>
<th>Title</th>
<th>Chapters</th>
</thead>
<tbody>
<tr ng-repeat="book in books">
<td>{{book.testament}}</td>
<td>{{book.title}}</td>
<td>{{book.chapters}}</td>
</tr>
</tbody>
</table>
<div class="display-book" ng-controller="displayController">
{{test}}
</div>
</div>
</div>
You don't need the additional controller there. I guess you want to display additional infos about the clicked book.
Use a reference and ngIf
var bible = angular.module('bible', []);
// Load the Books
bible.controller('listController', ['$scope', '$http', function($scope, $http) {
$scope.selectedBook = null;
$http.get('books.json').success(function(data) {
$scope.books = data
});
}]);
And html:
<div class="row">
<div class="col-md-12" ng-controller="listController">
<!-- will be shown, as long as not book is selected -->
<table data-ng-if="selectedBook == null" class="table">
<thead>
<th>Testament</th>
<th>Title</th>
<th>Chapters</th>
</thead>
<tbody>
<tr ng-repeat="book in books">
<td>{{book.testament}}</td>
<td>{{book.title}}</td>
<td>{{book.chapters}}</td>
</tr>
</tbody>
</table>
<!-- will be shown, when a book got selected -->
<div data-ng-if="selectedBook != null" class="display-book">
<!-- display the selection table again -->
<button data-ng-click="selectedBook = null">Back</button>
{{selectedBook.title}}
</div>
</div>
</div>
Why do you want to call a separate controller cant you implement the functionality in a separate function like below ,
bible.controller('listController', ['$scope', '$http', function($scope, $http) {
$http.get('books.json').success(function(data) {
$scope.books = data
});
$scope.display = function(){
// **YOUR CODE COMES HERE**
}
}]);
<td>{{book.title}}</td>