I am displaying a list of elements inside a ng-include.
The list of elements comes from the server using $resource query service.
The list is paginated with the ui-bootstrap pagination directive. the server send the pagination informations inside the Json header (properties are named X-MyApp-…) and are intercepted by the query callback function.
here is the html :
<table ng-include src="'partials/tplList.html'" ng-init="listInit = {'type': collec.type, 'offset': 1}" ng-controller="ListCtrl" >
</table>
the tplList.html :
<tbody ng-init="loadList(listInit)"><tr ng-repeat="elm in list">
<td>{{elm.prop1}}</td><td>{{elm.prop2}}</td><td>{{elm.prop3}}</td>
</tr></tbody>
<tfoot><tr><td colspan="4">
<span ng-show="pageCount>1">
<pagination num-pages="pageCount" current-page="currentPage" max-size="10" on-select-page="loadList(collect(listInit, {offset: page}))">
</pagination>
</span>
</td></tr></tfoot>
and the controller:
controller('ListCtrl', ['$scope', 'List', function($scope, List) {
// collect: concatenate the objects before to send it to loadList()
$scope.collect = function (a,b){
var c = {};
for (var att in a) { c[att] = a[att]; }
for (var att in b) { c[att] = b[att]; }
return c;
}
$scope.loadList = function (param) {
$scope.list = List.query(p, function(list, response) {
$scope.currentPage = response("X-MyApp-currentPage");
$scope.pageCount = response("X-MyApp-pagesCount");
console.log($scope.currentPage); // returns 1 when the page loads.
});
}
}])
and the service :
factory('List', function($resource){
return $resource('url/to/the/json/:type', {type:'#type'});
})
everything is working fine except one thing : when the page loads, the first page button ("1") inside the pagination component is not disabled like it should (and the "previous" and "first" buttons are not either). It's not disabled until i click on another page number (which is disabled correctly when selected) and then click back on the first page button.
any idea ?
This happens because ng-include creates a new scope and the model is not modified in your $parent scope.
Try the following code or create a controller that communicates with the parent one.
<pagination num-pages="pageCount" current-page="$parent.currentPage" max-size="10" on-select-page="loadList(collect(listInit, {offset: page}))">
</pagination>
i found a way to make it work:
removed this line from the controller :
$scope.currentPage = response("X-MyApp-currentPage");
and added this one :
$scope.currentPage = 1;
which gives :
controller('ListCtrl', ['$scope', 'List', function($scope, List) {
// collect: concatenate the objects before to send it to loadList()
$scope.collect = function (a,b){
var c = {};
for (var att in a) { c[att] = a[att]; }
for (var att in b) { c[att] = b[att]; }
return c;
}
$scope.currentPage = 1;
$scope.loadList = function (param) {
$scope.list = List.query(p, function(list, response) {
$scope.pageCount = response("X-MyApp-pagesCount");
});
}
}])
apparently the pagination component doesn't need the X-MyApp-currentPage information from the server (and i'm not sure to understand why).
Related
I am using ui-bootstrap pagination, getting the data from server based on the page clicked. every time it will send the request to server like this. 'apiURL?skip='+0 ,If i click on back button, it will update the url, not the view and also the page number will stay active in previous page. and also i want to be worked when i directly place the url in browser with some page number.can anyone please help me how to do with page url.
mainEvents: function() {
var self = this;
var currentItem =0;
return $http.get(UrlService.baseUrl + '/event/upcoming?skip='+ currentItem ).then(function(response) {
var events = response.data.events;
var eventsLen = events.length;
for (var i = 0; i < eventsLen; i++) {
self.prepareForRendering(events[i]);
}
var totalItems = response.data.events.length;
angular.copy(response.data.events, upEvents);
return events;
}, function(response) {
return $q.reject(response.data.error)
});
},
$scope.pageChanged = function() {
mainEvents(currentItem);
var currentItem = ($scope.currentNumber - 1) * 10;
$location.search('page', $scope.currentNumber); //$scope.currentNumber is pageNumber
};
html
<pagination total-items="totalItems" ng-model="currentNumber" ng-change="pageChanged()" items-per-page="itemsPerPage"></pagination>
I'm having trouble with services in AngularJS.
Being a newbie it's probably something crucial I'm missing here.
The title {{p01g.visiteTitel}} isn't magically refreshing but keeps displaying "sometitle".
The ng-repeat is working as expected.
(dataFactory is a service that connects to a remote server using $resource)
My service :
myApp.service('p00Service', ['dataFactory', function(dataFactory) {
var service = this;
service.visites = [];
service.visiteAantal = 0;
service.visiteTitel = "sometitle";
service.findVisites = function (datum) {
dataFactory.get({verb: "search", q: datum}, function (data) {
angular.copy(data.visites, service.visites);
service.visiteAantal = service.visites.length;
if (service.visiteAantal === 0) {
service.visiteTitel = "geen visites op " + datum
} else if (service.visiteAantal === 1) {
service.visiteTitel = "1 visite op " + datum
} else {
service.visiteTitel = service.visiteAantal + " visites op " + datum
}
});
};
}]);
My controller :
myApp.controller('p01gCtrl', ['p00Service', function (p00Service) {
var vm = this;
var datum = moment(); //I'm using moment.js -> moment() is date of today
p00Service.findVisites(datum);
vm.visites = p00Service.visites;
vm.visiteTitel = p00Service.visiteTitel;
}]);
My HTML :
<div class="p01g" ng-controller="p01gCtrl as p01g">
<div class="well_grey" style="min-height:40px;max-height:40px;max-width:330px">
<p style="font-size:20px;text-align:center;cursor:pointer;">
{{p01g.visiteTitel}}
</p>
</div>
<div class="well" style="min-height:190px;max-height:190px;max-width:330px">
<table style="width:100%;line-height:40px">
<tbody ng-repeat="visite in p01g.visites">
<tr>
<td style="width:20%;line-height:40px;padding-left:7px"><span style="font-size:16px">{{visite.t133datum | date:"dd/MM/yy"}}</span></td>
<td style="width:60%;line-height:40px;text-align:center"><span style="font-size:16px">{{visite.t133achternaam}}</span></td>
<td style="width:20%;line-height:40px;padding-left:30px"><span style="font-size:16px">{{visite.t133classificatie}}</span></td>
</tr>
</tbody>
</table>
</div>
</div>
the dataFactory looks like this :
myApp.factory("dataFactory", ['$resource', function ($resource) {
return $resource("/vf/rest/visites/:verb", {}, {
get: {method: "GET", isArray: false, cache: false}
});
}]);
I copied your code exactly and created a plunkr and added my own dataFactory to return sample data and there are no errors and the data is getting bound fine, so I believe the issue is in your implementation of dataFactory, or the way you are calling it (make sure it's expecting a callback function, since that is what you are passing it).
Edit: Here is a new plunkr with updated code that I believe reproduces your issue. So the reason why the title is not getting updated is because
vm.visiteTitel = p00Service.visiteTitel;
is setting vm.visiteTitel to the value of the string in p00Service.visiteTitel, but it is NOT getting a reference to p00Service.visiteTitel, so if you update visiteTitel in your p00Service after this assignment (which is happening in this case because the $resource callback is async), then it has no effect on vm.visiteTitel.
One way to make this work would be to pass a callback to p00Service to update your controller values like so:
p00Service.findVisites(datum, function(visites, visiteTitel) {
vm.visites = visites;
vm.visiteTitel = visiteTitel;
});
and then update your service to call this callback after the data is loaded:
service.visites = [];
service.visiteAantal = 0;
service.visiteTitel = "sometitle";
service.findVisites = function (datum, callback) {
dataFactory.get({}, function (data) {
...
if(callback) {
callback(service.visites, service.visiteTitel);
}
});
};
This code can be cleaned up a bit, but here is a workable plunkr demonstrating vm.visites and vm.visiteTitel getting updated correctly.
This is my first html page where I need to populate my recently added data:
<div>
<!--I have binded busdomain through controller -->
<swt-tree tree-data="busdomain"</swt-tree>
</div>
This is my child html page which is called under first page and I want to pass the values entered on this page to my parent page. But not getting recent values until I reload the page.
<span ng-show="true"</span>Name</label>
<div class="col-sm-9">
<input focus="" id="name" placeholder="Name" ng-model="busdomain.name" ng-change="domainNameChanged()" required="true">
</div>
<button type="submit" ng-click="addSubTree(createdomain.$valid)" id="btnData">OK</button>
This is my controller, I have called service through controller:
controller('domainController', ['$scope', '$state', 'DomainNameService', function($scope, $state, DomainNameService) {
$scope.activeTab = 1;
$scope.currentBDStatement=[];
$scope.statements=[];
$scope.childBD =[];
$scope.busdomain=[];
<!--It is used when I navigate from parent to child for the first time -->
$scope.busdomain = DomainNameService.getBusDomainName();
$scope.addSubTree = function(val){
//Done some code here
//In $scope.statements I am getting the values which I need to pass on html page
//I am setting the value in service which I got from my child html page
DomainNameService.setBusDomain($scope.statements);
//Here I am calling the get method of my service and able to get the values which i have set.
$scope.busdomain = DomainNameService.getBusDomainName();
//Redirecting to my parent page here I want to show the values which i have set in $scope.busdomain but I am not getting recent added values..
$state.go('BusDomainTree');
}
This is my service.js:
Here I have used getter and setter:
app.factory('DomainNameService', function() {
var busDomain = undefined;
var busDomainValue=[];
setBusDomain:function(busDomName){
this.busDomainValue=busDomName;
},
getBusDomainName: function(){
<!--I am getting the values here which I need to pass to html page -->
return this.busDomainValue;
}
})
Full controller code:
controller('domainController', ['$scope', '$state', 'DomainNameService', function($scope, $state, DomainNameService) {
$scope.activeTab = 1;
$scope.currentDomain = {};
$scope.currentBDStatement=[];
$scope.statements=[];
$scope.childBD =[];
var statementTree = {};
$scope.busdomain=[];
$scope.domain = DomainNameService.getDomainName();//Getting parent name here
$scope.busdomain = DomainNameService.getBusDomainName();
//$scope.busDom = DomainNameService.getBusDomainModel($scope.statements);
$scope.addTree = function(isValid) {
if(isValid) {
var stType = $scope.domain.name;//Getting value from html page of parent
$scope.currentDomain = $scope.getNewDomain(stType,varType);
$scope.statements.push($scope.currentDomain);
//Adding parent name to tree code $scope.statementTree.setNewInput($scope.statements);
$scope.isAdd = false;
DomainNameService.addDomain($scope.domain.name);
$scope.domain.domainName = DomainNameService.getDomainName()[0];
$state.go('DomainTree');
}
}
$scope.getNewDomain = function(stType,varType) {
//passing parent name as json
return {domainNode:[{name:stType}],name:stType, varName:varType};
}
$scope.addbusinessDomain = function() {
$state.go('DomainTree.businessDomain');
}
//This method is called for child
$scope.addSubTree = function(val){
var varType = "busDomain";
var domain=[];
var busDomainName=$scope.busdomain.name;
var parent = DomainNameService.getDomainName()[0];
DomainNameService.addChildBD(busDomainName);
$scope.childBD=DomainNameService.getChildBD();
$scope.currentStatement = $scope.busdomain.name;
$scope.currentBDStatement.push($scope.busdomain.name); $scope.currentDomainName=$scope.getBusDomain($scope.childBD,parent,varType);
$scope.statements.push($scope.currentDomainName);
$scope.statementTree.setNewInput($scope.statements);
DomainNameService.setBusDomain($scope.statements);
$scope.busdomain = DomainNameService.getBusDomainName();
$state.go('BusDomainTree');
}
$scope.getBusDomain = function(stType,parent,varType) {
return {node:[{name:parent}],name:parent, childNode:stType, refType: varType};
}
I am able to fetch values from service but I am not able to populate the recently added value to html page. For that I need to reload the page. Please some one help me out in resolving this issue. Thanks in advance
I'm developing a mini-basket in angular for an ecommerce application but have a problem with a scoped variable not updating via a service.
When i click on an add to basket button in the product grid it fires the upDateMiniBasket function in the product grid controller which has the UpdateMiniBasket service injected into it.
The controller:
whiskyControllers.controller('whiskyListCtrlr', ['$scope', 'UpdateMiniBasket', '$http',
function($scope, UpdateMiniBasket, $http){
$http.get('json/whiskies.json').success(function(data){
$scope.whiskies = data;
})
$scope.updateMiniBasket = function(e){
var targetObj = e.target.getAttribute('data-item');
UpdateMiniBasket.getUpdate(targetObj);
}
}
])
Here is the service:
whiskyrumApp.factory('UpdateMiniBasket', [function(){
var miniBasketTotal = 0,
itemCount = 0;
var miniBasketItems = [{
imageUrl : '',
name : 'There are currently no items in your basket',
price: 0
}]
var getUpdate = function(obj){
miniBasketTotal = 0;
if(obj) {
if(miniBasketItems[0].price === 0) miniBasketItems.pop();
obj = jQuery.parseJSON(obj);
miniBasketItems.push(obj);
}
for(var i = 0, j = miniBasketItems.length; i < j; i++){
miniBasketTotal += parseFloat(miniBasketItems[i].price);
}
itemCount = miniBasketItems[0].price === 0 ? 0 : miniBasketItems.length;
return {
miniBasketItems : miniBasketItems,
miniBasketTotal : miniBasketTotal,
itemCount : itemCount
}
}
return {
getUpdate : getUpdate
}
}]);
The problem is that when I add a product, the function fires and calls the service ok, but a scoped variable that should update the amount of items in the basket is not updating. This variable lives in another controller for the minibasket that also has teh UpdateMiniBasket service injected.
whiskyControllers.controller('miniBasketCtrlr', ['$scope', 'UpdateMiniBasket',
function($scope, UpdateMiniBasket){
var mbItems = UpdateMiniBasket.getUpdate();
$scope.miniBasketItems = mbItems.miniBasketItems;
$scope.itemCount = mbItems.itemCount;
}])
And this is html:
<div class="mini-basket grey-box" ng-controller="miniBasketCtrlr">
<a href="#" data-toggle="dropdown" class="btn dropdown-toggle">
{{itemCount}} Items
</a>
<!-- the ng-repeat code for the mini basket which works fine -->
I just assumed that when the variables in the service are updated, that would feed through to the scoped var in the other controller as they are both linked to the same service. I thought maybe I need to add a $watch as I cant see why this {{itemCount}} is not updating.
Any help would be greatly appreciated.
If you change the return object of your UpdateMiniBasket factory to instead of returning the primitive value for the count of items but to a function like below:
return {
miniBasketItems : miniBasketItems,
miniBasketTotal : miniBasketTotal,
itemCount : function () {
return itemCount;
}
}
And then in your controller change the binding to $scope to this:
$scope.itemCount = function () {
return mbItems.itemCount();
};
You should then just have to change the binding in the html to {{ itemCount() }} and this value should then successfully update when the values in the factory update.
I have a simplified solution to this on jsbin here: http://jsbin.com/guxexowedi/2/edit?html,js,output
I am trying to make ng-table work by example 6 (ajax data loading) but instead of using mock backend I use actual DreamFactory backend connected to MongoDB. My relevant code looks like this now:
MainApp.factory('Servant', function ($resource) {
"use strict";
console.log('loading');
return $resource('https://dsp-mydspname.cloud.dreamfactory.com:443/rest/mongodb/tablename/:id/?app_name=appname&fields=*', {}, { update: { method: 'PUT' }, query: {
method: 'GET',
isArray: false
} });
});
var MainCtrl = function ($scope, $timeout, $resource, Servant, ngTableParams) {
"use strict";
$scope.action="Add";
var Api = Servant;
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10, // count per page
}, {
total: 0, // length of data
getData: function($defer, params) {
// ajax request to api
Api.get(params.url(), function(data) {
$timeout(function() {
// update table params
params.total(data.record.length);
// set new data
$defer.resolve(data.record);
}, 500);
});
}
});
}
The table is displying data but it displays all data on one page, I cant figure out how to pass "count" and "offset" parameters into my api call. Any help would be appreciated.
Sorry for the delayed response. I played a little with ng-table and found that I was spending a lot of time trying to make it work and couldn't get it to. So..I thought it would be more helpful to show you how to build your own table with pagination so you can adapt it for any situation that may arise using DreamFactory. Here's the code. You should be able to copy and paste. Just make sure to add your table fields to the table row for data. The table headers will populate automatically.
Here is the controller and the service with comments:
.controller('TableCtrl', ['$scope', 'Servant', function($scope, Servant) {
// function to get records for building the table
var _getRecords = function(fieldsStr, limitInt, offsetInt, schemaBool) {
Servant.get({fields: fieldsStr, limit: limitInt, offset: offsetInt, include_schema: schemaBool},
function(data) {
$scope.table = data;
}
)
};
// Get the total records on load
Servant.get({fields: 'id'}, function(data) {
// Get the total number of records
$scope.totalRecords = data.record.length;
});
// Options for rest call
$scope.fields = '*';
$scope.currentOffset = 0;
$scope.limit = 4;
// Used to do pagination
// store total records
$scope.totalRecords = 0;
// store page objects
$scope.pageObjs = [];
// Get initial data
_getRecords($scope.fields, $scope.limit, $scope.currentOffset, true);
// Pagination
$scope.next = function() {
//check if we are on the last page
if ($scope.currentOffset == $scope.pageObjs[$scope.pageObjs.length - 1].pageOffset) {
return false;
}
// we are not
// advance the page
else {
$scope.currentOffset = $scope.currentOffset + $scope.limit;
_getRecords($scope.fields, $scope.limit, $scope.currentOffset, true);
}
};
// change page directly
$scope.changePage = function (offsetInt) {
$scope.currentOffset = offsetInt;
_getRecords($scope.fields, $scope.limit, $scope.currentOffset, true);
};
$scope.back = function() {
// are we on the first page
if ($scope.currentOffset == 0) {
return false
}
// we are not
// go previous page
else {
$scope.currentOffset = $scope.currentOffset - $scope.limit;
_getRecords($scope.fields, $scope.limit, $scope.currentOffset, true);
}
};
// watch for total records to be populated. When we have this number
// we can generate our page objects that will help build our pagination
$scope.$watch('totalRecords', function(newValue, oldValue) {
var numPages = Math.ceil(newValue / $scope.limit);
for(var i = 0; i < numPages; i++) {
$scope.pageObjs.push({pageNumber: i, pageOffset: i*$scope.limit})
}
});
}])
.service('Servant', ['$resource', function($resource) {
// define and return our $resource
// replace /rest/db/TheTable with your mongodb/tablename
// you don't need the port either
return $resource('http://localhost:8081/rest/db/TheTable',
{
// set params to bind too
app_name: APP_NAME
fields: '#fields',
limit: '#limit',
offset: '#offset'
},
{
// set update method to 'PUT'
update: {
method: 'PUT'
}
}
)
}]);
Here is the template i used:
<table class="table">
<!-- this will build the table headers dynamically -->
<!-- they will populate in order of the table's schema -->
<tr>
<th data-ng-repeat="field in table.meta.schema.field">
{{field.name}}
</th>
</tr>
<!-- replace these fields with your field names -->
<!-- for example: {{row.YOUR_FIELD_NAME}} -->
<tr data-ng-repeat="row in table.record">
<td>
{{row.id}}
</td>
<td>
{{row.first_name}}
</td>
<td>
{{row.last_name}}
</td>
</tr>
</table>
<!-- this will build dynamically as well-->
<ul class="pagination">
<li data-ng-click="back()"><a>«</a></li>
<li data-ng-click="changePage(page.pageOffset)" data-ng-repeat="page in pageObjs"><a>{{page.pageNumber + 1}}</a>
</li>
<li data-ng-click="next()"><a>»</a></li>
</ul>