AngularJS ~ Refresh pagination after Ajax request - angularjs

I 'm a beginner in AngularJS. I have created a page that retrieves records from database along with total records using an Ajax call. After populating the grid with the records, I wanted to refresh the pager control based on values received from the Ajax call such as the total records and the current page number as 1. I'm seeing the pager but is not refreshed. Can you please verify and let me know what I'm missing here?
var angularPersonModule = angular.module("angularPersonModule", ['ui.bootstrap']);
angularPersonModule.controller("AngularPersonController", AngularPersonController);
angularPersonModule.controller("PaginationController", PaginationController);
angularPersonModule.factory("PaginationService", PaginationService);
PaginationController.$inject = ['$scope', '$timeout', '$rootScope', 'PaginationService'];
function PaginationController($scope, $timeout, $rootScope, PaginationService) {
$scope.setPage = function(pageNo) {
if ($scope.currentPage === pageNo) {
return;
}
$scope.currentPage = pageNo;
$rootScope.$broadcast("personPageChanged", $scope.currentPage);
alert("call from setPage");
};
$scope.pageChanged = function() {
var i = 0;
};
$scope.$on('personRefreshPagerControls', function(event, args) {
//the solution:
setTimeout(function() {
//setTimeout is a deffered call (after 1000 miliseconds)
$timeout(function() {
$scope.totalItems = PaginationService.getTotalRecords();
$scope.currentPage = PaginationService.getPageNumber();
$scope.itemsPerPage = PaginationService.getPageSize();
$scope.numPages = PaginationService.getPageCount();
alert("totalItems = " + $scope.totalItems);
alert("currentPage = " + $scope.currentPage);
alert("itemsPerPage = " + $scope.itemsPerPage);
alert("pageCount = " + $scope.numPages);
});
}, 900);
});
}
AngularPersonController.$inject = ['$scope', '$rootScope', 'AngularPersonService', 'PaginationService'];
function AngularPersonController($scope, $rootScope, AngularPersonService, PaginationService) {
$scope.getAll = function() {
$scope.persons = AngularPersonService.search();
PaginationService.setTotalRecords(3);
PaginationService.setPageNumber(1);
PaginationService.setPageSize(2);
PaginationService.setPageCount(2);
$rootScope.$broadcast("personRefreshPagerControls", 3);
}
$scope.$on('personPageChanged', function(event, args) {
alert("pageChanged Event fired");
alert("Received args = " + args);
$scope.getAll();
});
$scope.getAll();
}
function PaginationService() {
var currentPage = 1;
var pageCount = 2;
var pageSize = 2;
var totalRecords = 3;
return {
getPageNumber: function() {
return currentPage;
},
setPageNumber: function(pageNumber) {
currentPage = pageNumber;
},
getPageSize: function() {
return pageSize;
},
setPageSize: function(newPageSize) {
pageSize = newPageSize;
},
getTotalRecords: function() {
return totalRecords;
},
setTotalRecords: function(newTotalRecords) {
totalRecords = newTotalRecords;
},
getPageCount: function() {
return pageCount;
},
setPageCount: function(newPageCount) {
pageCount = newPageCount;
}
}
}
angularPersonModule.factory("AngularPersonService", function($http) {
return {
search: function() {
return [{
"Name": "Hemant"
}, {
"Name": "Ashok"
}, {
"Name": "Murugan"
}];
}
}
});
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-route.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-resource.min.js"></script>
<script src="https://raw.github.com/angular-ui/bootstrap/gh-pages/ui-bootstrap-0.14.3.js"></script>
<script src="https://raw.githubusercontent.com/angular-ui/bootstrap/gh-pages/ui-bootstrap-tpls-0.14.3.js"></script>
<div ng-app="angularPersonModule">
<div class="panel panel-default">
<div class="panel-body" ng-controller="AngularPersonController">
<table class="table table-striped table-hover">
<thead>
<tr>
<th class="col-md-3">
Name
</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="person in persons">
<td>
<span>{{person.Name}}</span>
</td>
</tbody>
</table>
</div>
</div>
<div ng-controller="PaginationController">
<uib-pagination total-items="totalItems" ng-model="currentPage" ng-change="pageChanged()"></uib-pagination>
</div>
</div>
Update
Now I have updated the snippet so that you can execute and see the result manually.

Related

Angularjs: pass variable between controlers and reloading data

In my application the user can do a search. When the search field is filled, a query is executed and a loading message appears until the complete execution of the request. This part is working perfectly.
I'm trying to pass the search string to another controller in order to come back on the main part with the previous results. This is working too but I don't know if I have used the best way...
MY PROBLEM: when I come back on the main part (search section), during the data reloading, the loading message is not displayed anymore, could you please help me to solve and update the code ?
Here my controller:
var app=angular.module('ContactsApp', ['ngRoute', 'ui.bootstrap', 'ngDialog']);
app.config(function($routeProvider, $httpProvider, ngDialogProvider){
$httpProvider.defaults.cache = false;
if (!$httpProvider.defaults.headers.get) {
$httpProvider.defaults.headers.get = {};
}
// disable IE ajax request caching
$httpProvider.defaults.headers.get['If-Modified-Since'] = '0';
ngDialogProvider.setDefaults({
className: 'ngdialog-theme-default',
plain: false,
showClose: true,
closeByDocument: true,
closeByEscape: true,
appendTo: false,
preCloseCallback: function () {
console.log('default pre-close callback');
}
});
//$httpProvider.requestInterceptors.push('httpRequestInterceptorCacheBuster');
// Add the interceptor to the $httpProvider to intercept http calls
$httpProvider.interceptors.push('HttpInterceptor');
$routeProvider.when('/all-contacts',
{
templateUrl: 'template/allContacts.html',
controller: 'ctrlContacts',
})
.when('/view-contacts/:contactId',
{
templateUrl: 'template/viewContact.html',
controller: 'ctrlViewContacts'
})
.otherwise({redirectTo:'/all-contacts'});
});
app.factory('httpInterceptor', function ($q, $rootScope, $log) {
var numLoadings = 0;
return {
request: function (config) {
numLoadings++;
// Show loader
$rootScope.$broadcast("loader_show");
return config || $q.when(config)
},
response: function (response) {
if ((--numLoadings) === 0) {
// Hide loader
$rootScope.$broadcast("loader_hide");
}
return response || $q.when(response);
},
responseError: function (response) {
if (!(--numLoadings)) {
// Hide loader
$rootScope.$broadcast("loader_hide");
}
return $q.reject(response);
}
};
})
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpInterceptor');
});
//LOADING ICON DURING LOADING DATA
app.directive("loader", function ($rootScope) {
return function ($scope, element, attrs) {
$scope.$on("loader_show", function () {
return element.show();
});
return $scope.$on("loader_hide", function () {
return element.hide();
});
};
}
)
//DIRECTIVE FOR PASSING A VARIABLE BETWEEN CONTROLER
app.factory('MyTextSearch', function() {
// private
var value = '';
// public
return {
getValue: function() {
return value;
},
setValue: function(val) {
value = val;
}
};
})
app.controller('ctrlContacts', function ($scope, MyTextSearch, ContactService){
$scope.searchText = "Search Name...";
console.log("INIT SEARCH:" + MyTextSearch.getValue() );
$scope.contacts=null;
$scope.searchButtonText = "Search";
$scope.test = false;
$scope.reSearch = function () {
// Do your searching here
// simulate search
$timeout(function () {
// search is complete
}, 2000);
}
function searchContact(searchText) {
// GET THE VALUE OF THE VARIABLE PASS TO THE CONTROLERS
MyTextSearch.setValue(searchText);
console.log("NEW SEARCH:" + searchText);
if (!searchText.length) {
$scope.stringToSearch="Search Name...";
}
if (searchText.length>2) {
$scope.loading = true;
$scope.test = true;
$scope.searchButtonText = "Loading...";
ContactService.fastSearch(searchText).success(function(contacts){
var length = contacts.length;
$scope.loading = false;
if (length == 0) {
$scope.searchButtonText = "No result";
}else {
$scope.searchButtonText = length + " results found";
}
// For the orderby date
for (var i=0; i<length; i++) {
if(contacts[i].REQUESTTRUEDATE!=""){
contacts[i].REQUESTTRUEDATE = new Date(contacts[i].REQUESTTRUEDATE.replace(/-/g,"/"));
}else{
contacts[i].REQUESTTRUEDATE=null;
}
}
$scope.contacts = contacts;
$scope.selIdx= -1;
$scope.selContact=function(contact,idx){
$scope.selectedContact=contact;
$scope.selIdx=idx;
window.location="#/view-contacts/" + idx;
}
$scope.isSelContact=function(contact){
return $scope.selectedContact===contact;
}
});
}else{
$scope.contacts=null;
}
}
if(MyTextSearch.getValue().length!=0){
// When come back on the result lists
var stringToSearch = MyTextSearch.getValue();
$scope.search = searchContact(stringToSearch);
//Usefull for reloading query if stringToSearch is updated
$scope.search = function(stringToSearch){
searchContact(stringToSearch);
}
}else{
// New search
$scope.search = function(searchText){
searchContact(searchText);
}
}
// recherche
$scope.searchText = null;
$scope.razRecherche = function() {
$scope.searchText = null;
console.log("RAZ");
MyTextSearch.setValue('');
$scope.contacts=null;
}
});
app.controller('ctrlViewContacts', function ($scope, $routeParams, MyTextSearch, ContactService, RequestService, ReportService){
// GET THE VALUE OF THE PREVIOUS SEARCH
$scope.searchText = MyTextSearch.getValue();
console.log("SEARCHTEXT: " + $scope.searchText );
$scope.contact = null;
ContactService.loadPersonById($routeParams.contactId).success(function(contact){
$scope.contact = contact;
});
});
Here my view:
<h3>View all contacts</h3>
<div class="spacer input-group">
<div class="input-group-addon">
<span class="glyphicon glyphicon-search"></span>
</div>
<input type="text" ng-model="searchText" class="form-control" placeholder="Search name..." ng-change="search(searchText)"/>
<div class="input-group-btn">
<button class="btn btn-default" ng-click="razRecherche()">
<span class="glyphicon glyphicon-remove"></span>
</button>
</div>
</div>
<div ng-show="(!searchText || (searchText.length)<3) && contacts==null && !searchButtonText" id="least3Characters">
<p class="spacer center"><strong>Please enter at least 3 characters</strong></p>
</div>
<div>
<p class="spacer center" ng-show="searchText && (searchText.length)>2" >
<img src="../img/loading.gif" class="ajax-loader" ng-show="loading==true"/>
<strong>{{ searchButtonText }}</strong>
</p>
</div>
<div class="table-responsive" id="allContacts">
<table ng-show="contacts.length" class="table table-striped table-hover spacer">
<thead>
<tr>
<th class="colPerson">
Person
<span class="hSpacer" ng-class="cssChevronsTri('PERSON')"></span>
</th>
<th class="colCompany">
Company
<span class="hSpacer" ng-class="cssChevronsTri('COMPANY')"></span>
</th>
<th class="colAction">Action</th>
</tr>
</thead>
<tbody ng-repeat="contact in contacts | filter:searchText | orderBy:champTri:triDescendant"
>
<tr class="clickable">
<td class="colPerson" ng-click="selContact(contact,contact.ID)" ng-class="{sel:selIdx==$index}">{{contact.PERSON}}</td>
<td class="colCompany" ng-click="selContact(contact,contact.ID)">{{contact.COMPANY}}</td>
<td class="colAction">
<span class="glyphicon glyphicon-pencil"></span>
<button class="inline btn btn-default" data-ng-click="confirmDelPerson(contact.ID, contact.NBREQUEST)">
<span class="glyphicon glyphicon-remove"></span>
</button>
</td>
</tr>
</tbody>
</table>
</div>
Many Thanks in advance for your help.

Add, Remove & Update specific data In JSON in AngularJS

I have pulled data from json file. Now its displayed over DOM.
On HTML Page, I have three option 1) Edit Data 2) Delete Particular Data & 3) Add New Data.
How to perform this using AngularJS Code? i.e. on editing name, it should update my JSON object. On Deleting row, it should delete that row in JSON data. and also If I click on Add New, then entered data will be added to JSON.
My Code is as below.
Importing data through json file and displaying on DOM
.controller('MainCtrl', function ($scope, $http) {
$http.get('data/home.json').
success(function(data, status, headers, config) {
$scope.details = data;
}).
error(function(data, status, headers, config) {
// log error
});
});
Output of this code is correct as below image.
JSON Object as below.
{
"status":"success",
"adformat":[
{
"adformat_id":1,
"name":"Format 1",
"size":"300x250"
},
{
"adformat_id":2,
"name":"Format 2",
"size":"320x250"
},
{
"adformat_id":3,
"name":"Format 3",
"size":"320x480"
}
]
}
I would do it like this:
MainCtrl.js
(function () {
'use strict';
angular
.module('app')
.controller('MainCtrl', MainCtrl);
MainCtrl.$inject = ['$scope', 'MainFactory'];
function MainCtrl($scope, MainFactory) {
$scope.details = MainFactory.details;
function init() {
MainFactory.get();
}
init();
$scope.detailsModel = {
"adformat_id": 1,
"name": "Format 1",
"size": "300x250"
};
$scope.add = function () {
$scope.details.push($scope.detailsModel);
};
$scope.delete = function (index) {
$scope.details.splice(index, 1);
};
$scope.edited = -1;
$scope.editedModel = {
"adformat_id": 0,
"name": "",
"size": ""
};
$scope.edit = function (index) {
$scope.edited = index;
};
$scope.finishEdit = function (index) {
$scope.details[index] = $scope.editedModel;
$scope.edited = -1;
};
}
})();
MainFactory.js
(function () {
'use strict';
angular
.module('app')
.factory('MainFactory', MainFactory);
MainFactory.$inject = [];
function MainFactory() {
var self = this;
self.details = [];
self.get = $http.get('data/home.json')
.then(function (response) {
self.details = response.data;
}).catch(function (error) {
// log error
});
return self;
}
})();
index.html
<div ng-app="app">
<div ng-controller="MainCtrl">
<table>
<tbody>
<tr ng-repeat="details in detail">
<!-- show-->
<td ng-hide="edited === $index">{{detail.adformat_id}}</td>
<td ng-hide="edited === $index">{{detail.name}}</td>
<td ng-hide="edited === $index">{{detail.size}}</td>
<td ng-hide="edited === $index">
<button ng-click="edit($index)">Edit</button>
<button ng-click="delete($index)">Detele</button>
</td>
<!-- Edit-->
<td ng-show="edited === $index">{{detail.adformat_id}}</td>
<td ng-show="edited === $index"><input type="text" ng-model="editedModel.name"></td>
<td ng-show="edited === $index"><input type="number" ng-model="editedModel.size"></td>
<td ng-show="edited === $index">
<button ng-click="finishEdit($index, editedModel)">Save</button>
<button ng-click="delete($index)">Detele</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<button ng-click="add()">Add</button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
It is just prototype, not tested, but it should help you to understand idea o two way binding in angular.
Here is my approach to this requirement. Let me know if any further improvement can be added. The entire code can be found at the below URL:
Angular Save, Update and Delete
The sample screenshots from the code can be found here...
controller:
'use strict';
function MainController($scope, SharedService, ngDialog) {
$scope.account_type_selected = "Savings";
$scope.sharedService = SharedService;
$scope.savingsMain = [];
$scope.checkingsMain = [];
$scope.addToCheckingsAccounts = {};
$scope.addToSavingsAccounts = {};
$scope.setAccountType = function (type) {
if (type === "allAccounts") {
$scope.showSavings = true;
$scope.showCheckings = true;
} else if (type === "savingsAccounts") {
$scope.showSavings = true;
$scope.showCheckings = false;
} else if (type === "checkingAccounts") {
$scope.showSavings = false;
$scope.showCheckings = true;
}
$scope.account_type_selected = type;
};
$scope.$watch('savingsMain', function ($scope) {
return $scope.savingsMain;
});
$scope.selectedAccountType = function (showAccount) {
console.log(showAccount);
if (showAccount === "Savings") {
$scope.sharedService.accountType = "Savings";
} else {
$scope.sharedService.accountType = "Checkings";
}
};
$scope.saveAccounts = function () {
if ($scope.sharedService.accountType === "Savings") {
$scope.addToSavingsAccounts = {
"account_type": $scope.sharedService.accountType,
"amount": $scope.sharedService.amount,
"date": $scope.sharedService.date,
"maturity": $scope.sharedService.maturity
};
$scope.showSavings = true;
$scope.savingsMain.push($scope.addToSavingsAccounts);
} else {
$scope.addToCheckingsAccounts = {
"account_type": $scope.sharedService.accountType,
"amount": $scope.sharedService.amount,
"bic": $scope.sharedService.BIC,
"iban": $scope.sharedService.IBAN
};
$scope.showCheckings = true;
$scope.checkingsMain.push($scope.addToCheckingsAccounts);
}
ngDialog.close();
};
$scope.deleteDataFromSharedService = function (accountType, item) {
if (accountType === "Savings") {
$scope.savingsMain = _.without($scope.savingsMain, _.findWhere($scope.savingsMain, { date: item }));
} else if (accountType === "Checkings") {
$scope.checkingsMain = _.without($scope.checkingsMain, _.findWhere($scope.checkingsMain, { bic: item }));
}
};
$scope.closeDialog = function () {
ngDialog.close();
};
$scope.accountTypeModel = [];
$scope.prop = {
"type": "select",
"name": "account_type",
"value": $scope.sharedService.accountType,
"accountTypeData": ["Savings", "Checkings"]
};
}
<form ng-controller="MainController">
<div class="page-header">
<h1>Angular-Save-Update-Delete</h1>
</div>
<div class="content-wrapper">
<div class="sidebar">
<table>
<tbody>
<tr>
<td>
<button ng-click="setAccountType('allAccounts')" ng-model="allAccounts" class="ng-pristine ng-untouched ng-valid ng-empty">All</button>
</td>
</tr>
<tr>
<td>
<button ng-click="setAccountType('savingsAccounts')" ng-model="savingsMain" class="ng-pristine ng-valid ng-not-empty ng-touched">Savings</button>
</td>
</tr>
<tr>
<td>
<button ng-click="setAccountType('checkingAccounts')" ng-model="checkingsMain" class="ng-pristine ng-untouched ng-valid ng-not-empty">Checkings</button>
</td>
</tr>
<tr>
<td>
<button class="create-account-btn-class"
type="button"
ng-dialog="app/views/create-account-template.html"
ng-dialog-data=""
ng-dialog-class="ngdialog-theme-default"
ng-dialog-scope="this"
plain=false
showClose=true
closeByDocument=true
closeByEscape=true
ng-dialog-show-close="false">New Account</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="right-content">
<div id="savingsTemplate" templateurl="app/views/savings.html" ng-show="showSavings" include-template=""></div>
<div id="checkingsTemplate" templateurl="app/views/checkings.html" ng-show="showCheckings" include-template=""></div>
</div>
</div>
</form>

Factory not providing proper values to controller

In my angular js project factory is not providing values to the controller as needed. I always get empty result in view. When i logged in browser using console.log() all i can see in console is :
[object Object],[object Object],[object Object]. I am stuck at this. Tried many things but nothing worked.
This is my controller code:
var controllers = {};
controllers.ProductController = function ($scope, $route, $routeParams, $location, ProductFactory) {
$scope.products = [];
var init = function () {
$scope.products = ProductFactory.getProducts();
console.log('got products in controller');
console.log($scope.products)
};
var initProductEdit = function () {
var code = $routeParams.code;
if (code = undefined) {
$scope.currentProduct = {};
}
else
{
$scope.currentProduct = ProductFactory.loadProductByCode(code);
}
};
$scope.$on('$viewContentLoaded', function () {
var templateUrl = $route.current.templateUrl;
if (templateUrl == '/Partials/ProductEdit.html') {
initProductEdit();
}
else if (templateUrl == '/Partials/ProductList.html')
{
var code = $routeParams.code;
if(code!=undefined)
{
$scope.deleteProduct(code);
}
}
});
init();
$scope.saveProduct = function () {
ProductFactory.saveProduct($scope.currentProduct);
$location.search('code', null);
$location.path('/');
};
$scope.deleteProduct = function (code) {
ProductFactory.deleteProduct(code);
$location.search('code', null);
$location.path('/');
};
};
angSPA.controller(controllers);
This is my factory code:
angSPA.factory('ProductFactory', function () {
var products = [
{ code: 1, name: 'Game of Thrones', description: 'Series' }
{ code: 2, name: 'DmC', description: 'Game' },
{ code: 3, name: 'Matrix', description: 'Movie' },
{ code: 4, name: 'Linkin Park', description: 'Music Band' }];
var factory = {};
console.log('initializing factory');
factory.getProducts = function () {
console.log('factory now providing products');
return products;
};
factory.loadProductByCode = function (code) {
var product;
for (var i = 0; i < products.length; i++) {
if (products[i].code == code) {
product = products[i];
return product;
}
}
};
factory.saveProduct = function (product) {
products.push(product);
console.log('factory saved product');
};
factory.deleteProduct = function (code) {
var product = factory.loadProductByCode(code);
if (product != null) {
products.remove(product);
console.log('factory deleted product');
}
};
console.log('returning factory');
return factory;
});
This is my view:
<div class="container">
<h2 class="page-title">Product Listing</h2>
<div class="searchbar">
<ul class="entity-tabular-fields">
<li>
<label>Search: </label>
<span class="field-control">
<input type="text" data-ng-model="filter.productName" />
</span>
<label></label>
</li>
</ul>
</div>
<h2>Add New Product</h2>
<table class="items-listing">
<thead>
<tr>
<th>Code</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td data-ng-repeat="product in products|filter:filter.productName"></td>
<td>{{product.code}}</td>
<td>{{product.name}}</td>
<td>{{product.description}}</td>
<td>Delete</td>
</tr>
</tbody>
</table>
</div>
My routing function:
angSPA.config(function ($routeProvider) {
$routeProvider
.when(
'/',
{
controller: 'ProductController',
templateUrl: 'Partials/ProductList.html'
})
.when(
'/ProductEdit',
{
controller: 'ProductController',
templateUrl: 'Partials/ProductEdit.html'
})
.otherwise({
redirectTo: '/'
});
console.log('routing done');
});
Change your htmt given
var angSPA = angular.module('angSPA', []);
angSPA.controller("ProductController", function($scope, ProductFactory) {
$scope.products = [];
var init = function() {
$scope.products = ProductFactory.getProducts();
console.log('got products in controller');
console.log($scope.products + "")
};
init();
});
angSPA.factory('ProductFactory', function() {
var products = [
{code: 1, name: 'Game of Thrones', description: 'Series'},
{code: 2, name: 'DmC', description: 'Game'},
{code: 3, name: 'Matrix', description: 'Movie'},
{code: 4, name: 'Linkin Park', description: 'Music Band'}];
var factory = {};
console.log('initializing factory');
factory.getProducts = function() {
console.log('factory now providing products');
return products;
};
factory.loadProductByCode = function(code) {
var product;
for (var i = 0; i < products.length; i++) {
if (products[i].code == code) {
product = products[i];
return product;
}
}
};
factory.saveProduct = function(product) {
products.push(product);
console.log('factory saved product');
};
factory.deleteProduct = function(code) {
var product = factory.loadProductByCode(code);
if (product != null) {
products.remove(product);
console.log('factory deleted product');
}
};
console.log('returning factory');
return factory;
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
<body ng-app="angSPA" ng-controller="ProductController">
<div class="container">
<h2 class="page-title">Product Listing</h2>
<div class="searchbar">
<ul class="entity-tabular-fields">
<li>
<label>Search: </label>
<span class="field-control">
<input type="text" data-ng-model="filter.productName" />
</span>
<label></label>
</li>
</ul>
</div>
<h2>Add New Product</h2>
<table class="items-listing">
<thead>
<tr>
<th>Code</th>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="prod in products|filter:filter.productName">
<td ></td>
<td>{{prod.code}}</td>
<td>{{prod.name}}</td>
<td>{{prod.description}}</td>
<td>Delete</td>
</tr>
</tbody>
</table>
</div>
Your ng-repeat directive should be on the tr element and not the td.
<tr data-ng-repeat="product in products|filter:filter.productName">
Not the cause of your problem, but to log in a service or controller, you can use the $log service and stringify to serialize your objects.
$log.debug(JSON.stringify($scope.products));
Looking at your code, you do $scope.products = [] right at the beginning. This will make angular watch the empty array.
In your init function you assign the products array to $scope.products. But as angular is still watching the initial array it will not be aware of the change.
The solution is to delete the initial assignment $scope.products = [] and make sure to alter the original array but never set it to a new array.
BTW: you could do console.log(JSON.stringify($scope.products)) to get better log information.

AngularUI router issue "TypeError: Cannot read property 'name' of undefined"

I have a set of DIV's that contain A's and use AngularUI to load Angular templates within a ui-view DIV. I'm implementing a set of tabs that switch between the view templates based on which one a user clicks. I have several of these within the application and all work as designed. However, on one of my pages I keep getting a "TypeError: Cannot read property 'name' of undefined" that blows up in the angular-ui-router isMatch() call in the $StateRefActiveDirective($state, $stateParams, $interpolate) function on the line 'return $state.includes(state.name) && matchesParams();' because state is not defined. I've stepped through the calls to this code and it processes all of the ui-srefs in my markup successfully. Then after those are processed it gags.
The only real difference between other pages with these tabs on them is that I have the other pages with no other markup on them except the tabs and their ui-views. On this one I have 2 bootstrap columns, a col-md-5 and col-md-7. The col-md-5 contains a table of objects. When the user clicks on one of the rows the col-md-7 is shown, the $state is changed to one of its tabs and the data for the object is loaded for the tab by its controller.
On the other pages the tabs are always displayed and clicking them takes you to different ui-views the same as the my problem child. One real difference between them is a directive I wrote to 'disable' the links based on a Boolean. The uiSrefIf directive is at the bottom of the JavaScript listing. The idea is that when the File tab is shown the other tabs are visible but disabled.
Here is the JavaScript and markup:
angular.module('meritApp.screens.importUsers', [
'ui.router', 'ngSanitize', 'ui.select', 'ui.bootstrap', 'meritApp.global.services.profile',
'meritApp.global.services.common', 'angularFileUpload', 'meritApp.global.services.managedFiles'
])
.config(function($stateProvider) {
$stateProvider
.state('importUsers', {
url: "/admin/importUsers",
templateUrl: "app/screens/admin/importUsers/importUsers.html?v=" + APP_VERSION
});
$stateProvider
.state('importUsers.file', {
url: "/file",
templateUrl: "app/screens/admin/importUsers/file.html?v=" + APP_VERSION
});
$stateProvider
.state('importUsers.inserted', {
url: "/inserted",
templateUrl: "app/screens/admin/importUsers/inserted.html?v=" + APP_VERSION
});
$stateProvider
.state('importUsers.insertError', {
url: "/insertError",
templateUrl: "app/screens/admin/importUsers/insertError.html?v=" + APP_VERSION
});
$stateProvider
.state('importUsers.skipped', {
url: "/skipped",
templateUrl: "app/screens/admin/importUsers/skipped.html?v=" + APP_VERSION
});
$stateProvider
.state('importUsers.updated', {
url: "/updated",
templateUrl: "app/screens/admin/importUsers/updated.html?v=" + APP_VERSION
});
})
.controller('importUsersController', [
'$scope', '$state', '$log', '$rootScope', '$filter', 'appConfig', '$http', 'roleSvc',
function($scope, $state, $log, $rootScope, $filter, appConfig, $http, roleSvc) {
$rootScope.$broadcast("SET_BREADCRUMB", []);
$scope.itemsPerPage = 10;
$scope.currentPage = 1;
$rootScope.importing = false;
$rootScope.roleChanged = function(user, role) {
// todo - set the user's role
};
$scope.newImport = function() {
$rootScope.importing = true;
$rootScope.savedLocation = $rootScope.selectedLocation;
$rootScope.selectedLocation = null;
};
$rootScope.defaultRole = {
name: "Associate"
};
roleSvc.listAllActive(0, 40).then(
function(response) {
$rootScope.roles = $filter('orderBy')(response.data.results, "name");
angular.forEach($rootScope.roles, function(role) {
if (role.name == "Associate") {
$rootScope.defaultRole = role;
}
});
},
function(err) {
console.log("roleSvc.listAllActive Error: " + err.status + " " + err.statusText);
});
var init = function() {
$scope.loading = true;
$scope.locations = [];
var skip = ($scope.currentPage - 1) * $scope.itemsPerPage;
var userImportQueryPath = "queries/Merit.Components.UserImport.Queries/UserImportQueries";
$http.get(appConfig.urlRoot + userImportQueryPath + "/GetImportSummaries/results").then(
function(response) {
$scope.totalItems = response.data.results.length;
angular.forEach(response.data.results, function(location) {
if (skip-- <= 0 && $scope.locations.length < $scope.itemsPerPage) {
$scope.locations.push(location);
}
});
$scope.loading = false;
}, function(err) {
alert("GetImportList Error: " + err.status + " - " + err.statusText);
});
$http.get(appConfig.urlRoot + userImportQueryPath + "/GetAuditRecords/results").then(
function(response) {
$rootScope.importData = [];
angular.forEach(response.data.results, function(record) {
record["isInvited"] = false;
record["selectedRole"] = $rootScope.defaultRole;
record.errorText = JSON.parse(record.errorText);
$rootScope.importData.push(record);
});
$scope.users = _.sortBy($rootScope.importData, 'employeeId');
}, function(err) {
alert("GetImportList Error: " + err.status + " - " + err.statusText);
});
};
init();
$scope.refresh = function() {
init();
};
$scope.viewImports = function(location) {
$rootScope.selectedLocation = location;
$state.go('importUsers.inserted', {}, {
reload: true
});
};
$rootScope.closeView = function() {
$rootScope.importing = false;
if ($rootScope.savedLocation) {
$rootScope.selectedLocation = $rootScope.savedLocation;
$rootScope.savedLocation = null;
} else {
$rootScope.selectedLocation = null;
}
};
$scope.inviteUsers = function() {
angular.forEach($scope.users, function(userArray) {
if (userArray) {
angular.forEach(userArray, function(user) {
if (user.isInvited) {
// todo - send email to invited user
console.log("Sending email to " + user.name);
user.isInvited = false;
}
});
}
});
};
}
])
.controller('iuInsertedController', [
'$scope', '$state', '$log', '$rootScope',
function($scope, $state, $log, $rootScope) {
$rootScope.$broadcast("SET_BREADCRUMB", []);
$scope.itemsPerPage = 10;
$scope.selectedTab = "Inserted";
$scope.currentPage = 1;
$scope.inviteCount = 0;
var init = function() {
$scope.users = [];
$scope.totalItems = 0;
if (!$rootScope.selectedLocation) return;
var skip = ($scope.currentPage - 1) * $scope.itemsPerPage;
angular.forEach($rootScope.importData, function(user) {
if (user.isInserted && !user.hasErrors && user.locationCode == $rootScope.selectedLocation.code && user.timestampUtc == $rootScope.selectedLocation.timeStampUtc) {
if (skip-- <= 0 && $scope.users.length < $scope.itemsPerPage)
$scope.users.push(user);
$scope.totalItems++;
}
});
};
init();
$scope.refresh = function() {
init();
};
$scope.invite = function(user) {
$scope.inviteCount = (user.isInvited ? $scope.inviteCount + 1 : $scope.inviteCount - 1);
};
$scope.inviteUsers = function() {
alert("todo - send email to invited users");
angular.forEach($scope.users, function(user) {
if (user.isInvited) {
// todo - send email to invited user
console.log("Sending email to " + user.name);
user.isInvited = false;
}
});
};
}
])
.controller('iuInsertErrorController', [
'$scope', '$state', '$log', '$rootScope',
function($scope, $state, $log, $rootScope) {
$rootScope.$broadcast("SET_BREADCRUMB", []);
$scope.itemsPerPage = 10;
$scope.currentPage = 1;
$scope.selectedTab = "Inserted with Errors";
var importData = $rootScope.importData;
var init = function() {
$scope.users = [];
$scope.totalItems = 0;
if (!$rootScope.selectedLocation) return;
var skip = ($scope.currentPage - 1) * $scope.itemsPerPage;
angular.forEach(importData, function(user) {
if (user.isInserted && user.hasErrors && user.locationCode == $rootScope.selectedLocation.code && user.timestampUtc == $rootScope.selectedLocation.timeStampUtc) {
if (skip-- <= 0 && $scope.users.length < $scope.itemsPerPage)
$scope.users.push(user);
$scope.totalItems++;
}
});
};
init();
$scope.refresh = function() {
init();
};
$scope.inviteUsers = function() {
angular.forEach($scope.users, function(userArray) {
if (userArray) {
angular.forEach(userArray, function(user) {
if (user.isInvited) {
// todo - send email to invited user
console.log("Sending email to " + user.name);
user.isInvited = false;
}
});
}
});
};
}
])
.controller('iuUpdatedController', [
'$scope', '$state', '$log', '$rootScope',
function($scope, $state, $log, $rootScope) {
$rootScope.$broadcast("SET_BREADCRUMB", []);
$scope.itemsPerPage = 10;
$scope.currentPage = 1;
$scope.selectedTab = "Updated";
var init = function() {
$scope.users = [];
$scope.totalItems = 0;
if (!$rootScope.selectedLocation) return;
var skip = ($scope.currentPage - 1) * $scope.itemsPerPage;
angular.forEach($rootScope.importData, function(user) {
if (user.isUpdated && user.locationCode == $rootScope.selectedLocation.code && user.timestampUtc == $rootScope.selectedLocation.timeStampUtc) {
if (skip-- <= 0 && $scope.users.length < $scope.itemsPerPage)
$scope.users.push(user);
$scope.totalItems++;
}
});
};
init();
$scope.refresh = function() {
init();
};
$scope.inviteUsers = function() {
angular.forEach($scope.users, function(userArray) {
if (userArray) {
angular.forEach(userArray, function(user) {
if (user.isInvited) {
// todo - send email to invited user
console.log("Sending email to " + user.name);
user.isInvited = false;
}
});
}
});
};
}
])
.controller('iuSkippedController', [
'$scope', '$state', '$log', '$rootScope',
function($scope, $state, $log, $rootScope) {
$rootScope.$broadcast("SET_BREADCRUMB", []);
$scope.itemsPerPage = 10;
$scope.currentPage = 1;
$scope.selectedTab = "Skipped";
var init = function() {
$scope.users = [];
$scope.totalItems = 0;
if (!$rootScope.selectedLocation) return;
var skip = ($scope.currentPage - 1) * $scope.itemsPerPage;
angular.forEach($rootScope.importData, function(user) {
if (user.wasSkipped && user.locationCode == $rootScope.selectedLocation.code && user.timestampUtc == $rootScope.selectedLocation.timeStampUtc) {
if (skip-- <= 0 && $scope.users.length < $scope.itemsPerPage)
$scope.users.push(user);
$scope.totalItems++;
}
});
};
init();
$scope.refresh = function() {
init();
};
$scope.inviteUsers = function() {
angular.forEach($scope.users, function(userArray) {
if (userArray) {
angular.forEach(userArray, function(user) {
if (user.isInvited) {
// todo - send email to invited user
console.log("Sending email to " + user.name);
user.isInvited = false;
}
});
}
});
};
}
])
.controller('iuFileController', [
'$scope', '$state', '$log', '$rootScope', 'managedFileSvc', 'commandSvc', 'appConfig', '$http', 'modalMsgSvc',
function($scope, $state, $log, $rootScope, managedFileSvc, commandSvc, appConfig, $http, modalMsgSvc) {
$rootScope.$broadcast("SET_BREADCRUMB", []);
$scope.locations = mockExtraLocations;
$scope.importLocation = undefined;
$scope.importFile = undefined;
$scope.buttonText = "Browse...";
var locationsQueryPath = "queries/Merit.Components.Locations.Queries/LocationQueries";
$http.get(appConfig.urlRoot + locationsQueryPath + "/FindAllActive/results?skip=" + 0 + "&pageSize=" + 20).then(
function(response) {
$scope.locations = response.data.results;
}, function(err) {
console.log("LocationQueries.FindAllActive Error: " + err.status + " - " + err.statusText);
});
$scope.doImport = function() {
managedFileSvc.uploadFile($scope.importFile, function(evt) {
console.log(evt);
$scope.uploadProgress = evt;
}, function(response) {
console.log('upload response :: File ID: ', response[0].QueryReferences[0].QueryParameter);
var command = {
ImportFileId: response[0].QueryReferences[0].QueryParameter,
LocationCode: $scope.importLocation.code,
LocationName: $scope.importLocation.name
};
modalMsgSvc.showLoading("Importing...");
commandSvc.publish('Merit.Components.User.Commands', 'ImportHumanicUsers', command)
.then(function(record) {
modalMsgSvc.hideLoading();
console.log("ImportHumanicUsers Published: " + record.status);
$scope.importFile = undefined;
$rootScope.closeView();
$state.go("importUsers", {}, {
reload: true
});
}, function(err) {
modalMsgSvc.hideLoading();
if (err.errors)
console.log("ImportHumanicUsers ERROR: " + err.errors[0]);
else if (err.errorHeadline)
console.log("ImportHumanicUsers ERROR: " + err.errorHeadline);
else
console.log("ImportHumanicUsers ERROR: unknown");
// TODO?
});
});
};
$scope.fileSelected = function(files) {
// even though ng-multiple is false, we still get an array
if (files != null) {
$scope.importFile = files[0];
}
};
$scope.cancelImport = function() {
$scope.importFile = undefined;
$rootScope.closeView();
if ($rootScope.selectedLocation)
$state.go("importUsers.inserted");
};
}
])
.directive('uiSrefIf', function($compile) {
return {
scope: {
val: '#uiSrefVal',
if : '=uiSrefIf'
},
link: function($scope, $element, $attrs) {
$element.removeAttr('ui-sref-if');
$compile($element)($scope);
$scope.$watch('if', function(bool) {
if (bool) {
$element.attr('ui-sref', $scope.val);
} else {
$element.removeAttr('ui-sref');
$element.removeAttr('href');
}
$compile($element)($scope);
});
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="importUsersController">
<div class="row">
<div class="col-md-5">
<div class="table importLocationsCol">
<div class="row headerRow titleBar">
<div class="col-md-9"><i class="icon-users"></i>Import Users</div>
<div class="col-md-3 importNewBtnDiv">
<div class="btn btn-cancel importNewButton" ng-click="newImport()" ui-sref-opts="{reload: true}">
<a ui-sref="importUsers.file" style="text-decoration: none !important; color: #585858;">New</a>
</div>
</div>
</div>
<div class="row">
<h4>Past Imports</h4>
</div>
<div class="row">
<table class="table table-striped deptTable importTable">
<thead>
<tr>
<th class="importNameCol">Location</th>
<th class="importCountsCol">Update / New / Skip</th>
<th class="importDateCol">Imported</th>
</tr>
</thead>
<tbody>
<tr ng-show="loading && locations && locations.length == 0">
<td colspan="3">
<br />
<br />
<img class="spinner" src="content/images/ajax-loader.gif" alt="Loading..." />
</td>
</tr>
<tr ng-hide="true">
<td>
<!-- trick angular into making the next row white -->
</td>
</tr>
<tr ng-repeat=" location in locations" ng-class="{selected: location.code == selectedLocation.code}" ng-show="locations && locations.length > 0" ng-click="viewImports(location)">
<td class="importNameCol">{{location.name}} - {{location.city}}, {{location.state}}</td>
<td class="importCountsCol">{{location.updated}} / {{location.inserted}} / {{location.skipped}}</td>
<td class="importDateCol">{{location.timeStampUtc | date:'MM/dd/yyyy'}}</td>
</tr>
<tr ng-hide="loading || (locations && locations.length > 0)">
<td colspan="3" class="text-center">No Imports Found.</td>
</tr>
</tbody>
</table>
</div>
<div class="row">
<div class="col-md-12 paginationRow">
<pagination total-items="totalItems" items-per-page="itemsPerPage" ng-model="currentPage" max-size="5" ng-show="totalItems > itemsPerPage || true" direction-links="false" boundary-links="false" rotate="false" ng-change="refresh()" class="pagination-sm pull-right"></pagination>
</div>
</div>
</div>
</div>
<div class="col-md-7">
<div class="table importViewCol" ng-show="selectedLocation != null || importing">
<div class="row headerRow titleBar">
<div class="col-md-9">
<i class="icon-users"></i><span ng-show="importing">New</span><span ng-hide="importing">View</span> Import
</div>
<div class="col-md-3 text-right" ng-click="closeView()"><i class="icon-close"></i>
</div>
</div>
<div class="editWorkOrder" style="padding-bottom: 0; border: 0;">
<div class="tabBox">
<div class="tabStrip">
<div class="tab" ng-show="importing" ui-sref-opts="{reload: true}" ui-sref-active="thisTab">
<a ui-sref="importUsers.file">File</a>
</div>
<div class="tab" ui-sref-opts="{reload: true}" ui-sref-active="thisTab" ng-disabled="importing">
<a ui-sref-if="!importing" ui-sref-val="importUsers.inserted">Inserted</a>
</div>
<div class="tab" ui-sref-opts="{reload: true}" ui-sref-active="thisTab" ng-disabled="importing">
<a ui-sref-if="!importing" ui-sref="importUsers.insertError">Inserted with Errors</a>
</div>
<div class="tab" ui-sref-opts="{reload: true}" ui-sref-active="thisTab" ng-disabled="importing">
<a ui-sref-if="!importing" ui-sref="importUsers.updated">Updated</a>
</div>
<div class="tab" ui-sref-opts="{reload: true}" ui-sref-active="thisTab" ng-disabled="importing">
<a ui-sref-if="!importing" ui-sref="importUsers.skipped">Skipped</a>
</div>
</div>
</div>
</div>
<div class="importUsersDisplay" ui-view></div>
</div>
</div>
</div>
</div>
Because we use so many service calls I haven't tried to get this working in Plunker. It's not a show stopper since the page behaves as expected. It is an annoyance that I'd like to understand and eliminate. Also, my QA folks can then stop complaining to me about it :)
Thanks, Mike

Angularjs ui bootstrap - Don't know how to cycle through table data with Pagination

I currently have a page that has clickable data. When clicked, a modal comes up that has a table built with customer data received from a service. I have included Angularjs ui boostrap plugin and have implemented the pagination directive. I have the pagination working in the sense that the links are able to switch back and forth as well as the previous and next buttons. What I do not know how to do is cycle through the table data displaying the amount specified in the controller. Code is below:
Drilldown Directive:
var drilldownDirective = function () {
return {
restrict: 'E',
scope: {
tableData: '='
},
controller: function ($rootScope, $scope, DashboardFactory) {
var tableData = $scope.tableData;
var dashboardreportid = tableData.dashboardreportid;
var companyid = tableData.companyid;
var companybrandid = tableData.companybrandid;
var startdate = tableData.startdate;
var enddate = tableData.enddate;
var clientdb = tableData.clientdb;
var calltype = tableData.calltype;
var secondarycallval = tableData.secondarycallval;
var onSuccess = function (response) {
var d, t, dt, dtobj, obj;
var dtData = [];
$scope.repdata = [];
$scope.titles = [];
for (d in response.repdata) {
var dtArray = [];
obj = response.repdata[d];
$scope.repdata.push(obj);
//Create data packages for dataTables
for (dt in obj.data) {
dtobj = obj.data[dt];
dtArray.push(dtobj);
};
//Push data package to dtData array for injecting in dataTable
dtData.push(dtArray);
//Dynamically save field name for table headers
if (obj.ID == 0) {
var tlt = obj.data;
for (t in tlt) {
$scope.titles.push(t);
};
$scope.titles.sort();
};
};
//Pagination controls
$scope.totalItems = $scope.repdata.length;
$scope.currentPage = 1;
$scope.maxSize = 5;
$scope.setPage = function (pageNo) {
$scope.currentPage = pageNo;
};
$scope.pageChanged = function() {
console.log('Page changed to: ' + $scope.currentPage);
};
$scope.bigTotalItems = 175;
$scope.bigCurrentPage = 1;
};
var onError = function (response) {
console.log("error");
console.log(data);
};
DashboardFactory.getDashboardReportData(dashboardreportid, companyid, companybrandid, startdate, enddate, clientdb, calltype, secondarycallval).then(onSuccess, onError);
},
templateUrl: "dashboard/drilldownTable.html",
}
}
(directive template) drilldownTable.html
<input type='text' data-ng-model='searchbox' placeholder='search rows'></input>
<div class="table-responsive">
<table id="drilldownTable" class="table table-bordered table-condensed">
<thead>
<th data-ng-repeat="title in titles">{{title}}</th>
</thead>
<tbody>
<!-- <tr data-ng-repeat='rd in repdata | filter:searchbox | limitTo:50'> -->
<tr data-ng-repeat='rd in repdata | filter:searchbox | limitTo:bigTotalItems'>
<td data-ng-repeat='val in rd.data track by $index'>{{val}}</td>
</tr>
</tbody>
</table>
</div>
<pagination total-items="totalItems" data-ng-model="currentPage" data-ng-change="pageChanged()"></pagination>
<pre>Page: {{currentPage}} / {{maxSize}}</pre>
All help is appreciated. Thanks.

Resources