I have an api that gets called on page load. The data from the api is loaded into a table via angular ng-repeat. I also have a javascript function that gets called every 10 seconds that calls the same api for the same dataset. I Would like to know how i can apply the new dataset to the table and replace the old if the dataset changes and how to visually show this change with animation. The code is below.
Table code
<body ng-app="myApp" ng-controller="ScansController">
<div class="bs-example" id="scan-table">
<table id="scansTable" class="table table-striped">
<thead>
<tr>
<th>ScanId</th>
<th>First Name</th>
<th>Last Name</th>
<th>Time Stamp</th>
</tr>
<tr ng-repeat="scan in Scans">
<td>
{{scan.scanId}}
</td>
<td>
{{scan.firstName}}
</td>
<td>
{{scan.lastName}}
</td>
<td>
{{scan.timeStamp}}
</td>
</tr>
</thead>
</table>
</div>
Javascipt interval code
<script>
window.setInterval(function () {
$.ajax({
url: 'api/scans/',
type: 'Get',
dataType: 'json',
success: function (data) {
//Something here
},
error: function () {
alert("something failed");
}
});
}, 10000);
</script>
Angular Code
var myApp = angular.module('myApp', []);
myApp.service('dataService', function ($http) {
this.getData = function () {
return $http({
method: 'GET',
url: '/api/scans/'
});
}
});
myApp.controller('ScansController', function ($scope, dataService) {
$scope.Scans = [];
dataService.getData().then(function (result) {
$scope.Scans = result.data;
console.log(result.data);
});
});
You need to stay inside the current scope.
Setting an interval on a $http call is poison. Use a $timeout inside the success callback to recursively call the next interval.
myApp.controller('ScansController', function ($scope, $timeout, dataService) {
$scope.Scans = [];
function fetchData(){
dataService.getData().then(function (result) {
$scope.Scans = result.data;
$timeout(function(){ fetchData(); },10000);
});
}
fetchData();
});
As far as the table refresh that didnt get addressed, this is how i was able to make it work. I downloaded and applied the animate.css. I then gave the table a starting class to animate it on class load. I then have a function that fetches the array of data on page load and then another that fetches every .5 seconds and compares. If anything has changed, then the class is reapplied and it shows animation.
Angular Ng-Repeat Table
<link href="~/Content/animate.min.css" rel="stylesheet" />
<h1>
Scans
</h1>
<body ng-app="myApp" ng-controller="ScansController" >
<table id="scansTable" class="table table-striped">
<thead>
<tr>
<th>ScanId</th>
<th>First Name</th>
<th>Last Name</th>
<th>Time Stamp</th>
</tr>
<tr ng-repeat="scan in Scans" ng-class-odd="'odd'" ng-class-even="'even'" class="animated bounceIn">
<td>
{{scan.scanId}}
</td>
<td>
{{scan.firstName}}
</td>
<td>
{{scan.lastName}}
</td>
<td>
{{scan.timeStamp}}
</td>
</tr>
</thead>
</table>
Angular Controller
var myApp = angular.module('myApp', []);
myApp.service('dataService', function ($http) {
this.getData = function () {
return $http({
method: 'GET',
url: '/api/scans/'
});
}
});
myApp.controller('ScansController', function ($scope, dataService, $timeout) {
$scope.Scans = [];
$scope.NewScans = [];
function fetchData() {
dataService.getData().then(function (result) {
$scope.Scans = result.data;
$("#scansTable").removeClass('animated bounceIn');
});
}
function fetchNewData() {
dataService.getData().then(function (result) {
$scope.NewScans = result.data;
if ($scope.Scans.length != $scope.NewScans.length)
{
$("#scansTable").addClass('animated bounceIn');
$scope.Scans = $scope.NewScans
}
$timeout(function () { fetchNewData(); }, 500);
});
}
fetchData();
fetchNewData();
});
Related
I am trying to write an event handler for page change in a datatable. following is the existing code.. the libraries are included in a baselayout for following code..
DefaultView.cshtml
<div class="row">
<div class="col-lg-6 col-md-6 col-sm-6 col-xs-6 pageheading">
<h1>
<small>AMS Default</small>
</h1>
</div>
</div>
<hr />
<br />
<div class="row">
<div class="col-lg-12">
<table dt-options="dtOptions" datatable dt-columns="dtColumns"
class="table table-striped table-bordered dt-responsive">
<thead>
<tr>
<th></th>
<th></th>
<th></th>
<th></th>
</tr>
</thead>
</table>
</div>
</div>
#section CommonScripts{
<script src="~/Angular/Areas/Common/Controllers/DefaultController.js"></script>
<script src="~/Angular/Areas/Common/Services/DefaultService.js"></script>
}
Defaultcontroller.js
AMSApp.controller('DefaultController', ['$rootScope', 'DefaultService', 'DTOptionsBuilder', 'DTColumnBuilder',
function ($rootScope, DefaultService, DTOptionsBuilder, DTColumnBuilder) {
var self = this;
this.Users = {};
this.GetAllUsers = function () {
$rootScope.CloseAlerts();
DefaultService.GetAllUsers().success(function (result) {
self.Users = result;
self.loadd();
}).catch(function (error) {
$rootScope.ErrorMsg = "OOPS some thing went wrong. Please try again.";
});
}
this.GetAllUsers();
this.loadd = function () {
$rootScope.dtColumns = [
DTColumnBuilder.newColumn('DisplayName').withTitle('UserName'),
DTColumnBuilder.newColumn('IsSNA').withTitle('IsSNA'),
DTColumnBuilder.newColumn('IsAdmin').withTitle('IsAdmin'),
DTColumnBuilder.newColumn('IsDownloadPermitted').withTitle('DownloadPermitted')
];
$rootScope.dtOptions = DTOptionsBuilder.newOptions()
.withOption('data', self.Users)
.withDisplayLength(10);
}
}]);
/*
Button Click handler:
$("#customerSearchButton").on("click", function (event) {
$.ajax({
url: "",
type: "post",
data: { searchText: searchText }
}).done(function (result) {
Table.clear().draw();
Table.rows.add(result).draw();
}).fail(function (jqXHR, textStatus, errorThrown) {
// needs to implement if it fails
});
}
*/
DefaultService.js
AMSApp.service('DefaultService', function ($http) {
this.GetAllUsers = function () {
return $http.get('/Common/User/GetAllUsers');
}
});
I tried several versions like in the above-commented code.. but I need something like following in the controller.
/*need something like this*/
DTOptionsBuilder.on('page.dt', function () {
var info = table.page.info();
console.log("hey i got eexecuted");
$('#pageInfo').html('Showing page: ' + info.page + ' of ' + info.pages);
});
firstly is it possible? - if not what are other alternatives?
Note: I prefer not to give an id to the table.
When the below form is submitted, and additional entry is created into the database. But the ng-repeat is not getting refreshed.
Any ideas?
html code:
<table class="redTable">
<thead>
<tr>
<th> Domain</th>
<th> Username</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="eachuserconfigdata in userconfigdata track by $index">
<td>
<input type="text" ng-model="eachuserconfigdata.Domain" value="{{ eachuserconfigdata.Domain }}" ng-readonly='!($index == eEditable)' ng-dblclick="eEditable = $index" style="background-color: transparent ; width:80px;border: 0;" />
</td>
<td>
<input type="text" ng-model="eachuserconfigdata.UserName" value="{{ eachuserconfigdata.UserName }}" ng-readonly='!($index == eEditable)' ng-dblclick="eEditable = $index" style="background-color: transparent ; width:80px;border: 0;" />
</td>
</tr>
</tbody>
</table>
<br />
</div>
Javascript
var myApp = angular.module("mymodule", ['ngMaterial']);
var myController = function ($scope, $http, $log) {
$scope.username = "";
$scope.ps = "";
$scope.submit = function () {
//alert($scope.username);
//alert($scope.ps);
$scope.myStyle = { color: 'red' };
var data = {
Domain: $scope.domainname,
UserName: $scope.domainusername,
Password: $scope.domainps
};
$http({
method: 'POST',
//url: 'Login/LoginUser?user=' + $scope.username + '&password=' + $scope.ps,
url: 'Login/UpdateDomainConfiguration',
data: data,
headers: { "Content-Type": "application/json" }
})
.then(function successCallback(response) {
var userid = 0;
$scope.message = response.data;
//$log.info(response);
$scope.GetUserConfigDetails();
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
alert(response.data);
});
}
What you did based on your code is you just saved it to db but never fetched it (not sure about this $scope.GetUserConfigDetails(); though).
What you need to do is after saving it to db, fetch the data again and assign it to your ng-repeat array. Or you can just simply insert the data you've saved to the db into your existing array so that you don't have to fetch again.
I want to populate the data into the datatable but no data is getting populated into the table.
Error I'm getting on debugging is:
Uncaught TypeError: Cannot read property 'getContext' of null
html:
<table class="display table table-bordered table-striped" id="example">
<thead>
<tr>
<th>User Name</th>
<th>Email Id</th>
<th>Group Name</th>
<th>Created Date</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="item in items">
<td>{{item.user}}</td>
<td>{{item.email}}</td>
<td>{{item.groupName}}</td>
<td>{{item.createdAt}}</td>
</tr>
</tbody>
</table>
controller:
(function () {
"use strict";
angular.module('app').controller('superAdminController', function ($scope, AuthenticationService, $timeout, $location, $http, myConfig) {
AuthenticationService.loadSuperAdmin(function (response) {
if (response.data.success) {
$scope.populateTable(response.data);
console.log(response.data);
} else {
$scope.items = [];
}
});
$scope.populateTable = function (data) {
$scope.items = data.loadSuperAdminData;
$timeout(function () {
$("#example").dataTable();
}, 200)
};
});
}());
In controller, you can populate your server response like this.
$.post(MY_CONSTANT.url + '/api_name',{
access_token: accessToken
}).then(
function(data) {
var dataArray = [];
data = JSON.parse(data);
var lst = data.list;
lst.forEach(function (column){
var d = {user: "", email: "", group: "", created: ""};
d.user = column.user;
d.email = column.email;
d.groupName = column.group;
d.createdAt = column.created;
dataArray.push(d);
});
$scope.$apply(function () {
$scope.list = dataArray;
// Define global instance we'll use to destroy later
var dtInstance;
$timeout(function () {
if (!$.fn.dataTable) return;
dtInstance = $('#datatable4').dataTable({
'paging': true, // Table pagination
'ordering': true, // Column ordering
'info': true, // Bottom left status text
// Text translation options
// Note the required keywords between underscores (e.g _MENU_)
oLanguage: {
sSearch: 'Search all columns:',
sLengthMenu: '_MENU_ records per page',
info: 'Showing page _PAGE_ of _PAGES_',
zeroRecords: 'Nothing found - sorry',
infoEmpty: 'No records available',
infoFiltered: '(filtered from _MAX_ total records)'
}
});
var inputSearchClass = 'datatable_input_col_search';
var columnInputs = $('tfoot .' + inputSearchClass);
// On input keyup trigger filtering
columnInputs
.keyup(function () {
dtInstance.fnFilter(this.value, columnInputs.index(this));
});
});
// When scope is destroyed we unload all DT instances
// Also ColVis requires special attention since it attaches
// elements to body and will not be removed after unload DT
$scope.$on('$destroy', function () {
dtInstance.fnDestroy();
$('[class*=ColVis]').remove();
});
});
});
I'm currently learning new MVC 6 and stucked completely with simple action - table data update on item selection change.The desired behaviour is to load questions that belong selected question block
I have angularJS factory:
(function () {
'use strict';
angular
.module('questionBlockApp')
.factory('questionBlockService', questionBlockService);
var questionBlockService = angular.module('questionBlockService', ['ngResource']);
questionBlockService.factory('Blocks', ['$resource',
function ($resource) {
return $resource('/api/blocks/', {}, {
query: { method: 'GET', params: {}, isArray: true }
});
}]);
questionBlockService.factory('Questions', ['$resource',
function ($resource) {
return $resource('/api/blocks/:blockId', {blockId : '#blockId'}, {
query: { method: 'GET', params: {}, isArray: true }
});
}]);
})();
Controller, which has refresh func (loadQuestions) built inside selection change function:
(function () {
'use strict';
angular
.module('questionBlockApp')
.controller('questionBlockController', questionBlockController);
//.controller('questionController', questionController);
questionBlockController.$inject = ['$scope', 'Blocks', 'Questions'];
//questionController.$inject = ['$scope', 'Questions'];
function questionBlockController($scope, Blocks, Questions) {
$scope.selectedBlock = 2;
if ($scope.Blocks == undefined | $scope.Blocks == null) {
$scope.Blocks = Blocks.query();
}
$scope.setSelected = function (blockId) {
$scope.selectedBlock = blockId;
$scope.loadQuestions();
}
$scope.loadQuestions = function () {
$scope.data = Questions.query({ blockId: $scope.selectedBlock });
$scope.data.$promise.then(function (data) {
$scope.Questions = data;
});
};
$scope.loadQuestions();
}
})();
And views:
View from which setSelected is called:
<table class="table table-striped table-condensed" ng-cloak ng-controller="questionBlockController">
<thead>
...
</thead>
<tbody>
<tr ng-repeat="block in Blocks" ng-click="setSelected(block.Id)" ng-class="{'selected': block.Id == selectedBlock}">
<td>{{block.Id}}</td>
<td>{{block.Name}}</td>
<td>{{block.Created}}</td>
</tr>
</tbody>
</table>
<table id="test" ng-controller="questionBlockController">
<thead>
<tr>
...
</tr>
</thead>
<tbody>
<tr ng-repeat="question in Questions">
<td>{{question.Id}}</td>
<td>{{question.Text}}</td>
<td>{{question.TimeLimit}}</td>
<td>{{question.Updated}}</td>
</tr>
</tbody>
</table>
When I click on different items in QuestionBlock table, $scope.Questions is updated properly, but the table does not reflect changes, as if no binding exists.
Okay, I am just a bit damaged.
There are two questionBlockController controllers defined, leading to intialization of different scopes => two $scope.Questions objects existence => refresh occured in Blocks scope, which was undesired behaviour.
I want to render a table adding row per each objects in an array.
I got a Controller like:
app.controller('SignUpController',function ($scope, $http) {
var that = this
that.users = []
that.queryUsers = function() {
console.log("I'm being triggered")
$http.get("/existingUsers").
success(function (data,status,headers,config) {
console.log(data)
that.users = data
console.log(that.users)
}).
error(function (data,status, headers, config) {
console.log(status)
})
}
})
And the table markup:
<table class="table table-bordered">
<th ng-repeat="th in ['mail','Administrador','Miembro desde']">{{th}}</th>
<tr ng-repeat="p in signup.users">
<td>{{p._id}}</td>
<td>{{p.mail}}</td>
<td>{{p.admin}}</td>
</tr>
</table>
Ttable is within a div with ng-controller="SignUpController as signup". When I click a button I trigger queryUsers actually seein results in browser console:
[Object, Object, Object, Object, Object, Object, Object, Object, Object, Object]
Both mail and _id are existing attributes per each object.
So the AJAX is being done and the array I should be iterating and rendering to HTML rows actually exists and is populated, but no rows are shown.
Why?
Edit
I tried not modifying the scope:
app.controller('SignUpController', function ($scope,$http) {
$scope.users = []
$scope.queryUsers = function() {
console.log("I'm being triggered")
$http.get("/existingUsers").
success(function (data,status,headers,config) {
console.log(data)
$scope.users = data
console.log($scope.users)
}).
error(function (data,status, headers, config) {
console.log(status)
})
}
})
<div class="tab-pane" id="usecase11" ng-controller="SignUpController">
<h3>Colaboradores</h3>
<div class="row">
<div class="col-sm-6">
<table class="table table-bordered">
<th ng-repeat="th in ['mail','Administrador','Miembro desde']">{{th}}</th>
<tr ng-repeat="p in users">
<td>{{p._id}}</td>
<td>{{p.mail}}</td>
<td>{{p.admin}}</td>
<td style="border:none;"><a class="close" ng-click="">$</a></td>
<td style="border:none;"><a class="close" ng-click="">*</a></td>
</tr>
</table>
</div>
</div>
</div>
However, again I can see such array printed at browser console but nothing rendered to HTML
Here is the evidence that queryUsers is being called and that $scope.users is getting something after it.
Something interesting is that I got: {{users}} right after the table and it's displaying an empty array.
Just in case this is the GET handling server code:
app.get('/existingUsers',function (request, response) {
membersCollection.find({},{"password":0}, function (err, data) {
if (err) response.send(404)
else {
data.toArray(function (err, docs) {
if (err) {
console.log(error)
response.send("Error")
}
response.send(JSON.stringify(docs, null, 4))
})
}
})
}
You don't modify the $scope. Here is the corrected code:
app.controller('SignUpController',function ($scope, $http) {
$scope.users = []
$scope.queryUsers = function() {
console.log("I'm being triggered")
$http.get("/existingUsers").
success(function (data,status,headers,config) {
console.log(data)
$scope.users = data
console.log($scope.users)
}).
error(function (data,status, headers, config) {
console.log(status)
})
}
})
HTML:
<table class="table table-bordered">
<th ng-repeat="th in ['mail','Administrador','Miembro desde']">{{th}}</th>
<tr ng-repeat="p in users">
<td>{{p._id}}</td>
<td>{{p.mail}}</td>
<td>{{p.admin}}</td>
</tr>
</table>