ng-grid with manually handle page index changed - angularjs

I have an example of ng-grid server side pagination from here : http://ddeloy.com/angular-ng-grid-example/server-side-page/index.html
However as the original purpose of pagination.. i do NOT want to load the entire records from the server.. I am passing the page size and index to the server code so I need to be able to handle the click event of page index change (previous and next page button).. how can i do this with ng-grid?

in the same link that you have provided you can see that the pageSize and index are handled in a watch, so you can call your server side function from there, something like this:
$scope.$watch('pagingOptions', function () {
$http.post('/get_records', {"page_size": $scope.pagingOptions.pageSize,
"page_index": $scope.pagingOptions.currentPage}
).success(function (serverPagedData) {
$scope.myData = serverpagedData;
$scope.pagingOptions.totalServerItems = serverPagedData.length;
if (!$scope.$$phase) {
$scope.$apply();
}
});
}, true);
Cheers!

Related

Server side pagination of AngularJS ng-grid

I am trying to implement this server side pagination example of ng-grid mentioned here http://angular-ui.github.io/ng-grid/ . Unfortunately, I do not quite understand the code.
Here is my situation:
1. Say I have a page which has 2 text boxes and a button. I would like to post the values of these two text boxes to a web service on ng-click of the button. Returned json should be displayed as grid. But the code in the plunker http://plnkr.co/edit/50vJrs?p=preview
$scope.getPagedDataAsync = function (pageSize, page, searchText) {
setTimeout(function () {
var data;
if (searchText) {
var ft = searchText.toLowerCase();
$http.get('largeLoad.json').success(function (largeLoad) {
data = largeLoad.filter(function(item) {
return JSON.stringify(item).toLowerCase().indexOf(ft) != -1;
});
$scope.setPagingData(data,page,pageSize);
});
} else {
$http.get('largeLoad.json').success(function (largeLoad) {
$scope.setPagingData(largeLoad,page,pageSize);
});
}
}, 100);
};
will render the grid on page load (which I do not want). What I dont understand is how to associate the $scope.getPagedDataAsync function with a ng-click?
The html code doesnt have any textbox for searching through the grid even though in the controller they have $scope.filterOptions. How is the search happening the in plunker code?
Wish there was more documentation on the site.
Thank you
In the plunker, the function quoted in your question is immediately invoked:
$scope.getPagedDataAsync($scope.pagingOptions.pageSize, $scope.pagingOptions.currentPage);
Does commenting out that line have the desired effect?
As for the filter, it's probably there as a convenience so you can add a filter text field yourself. It is defined in an object so you can use a custom directive or ng-include block.

AngularJS $location replace() replacing last history entry also

On my AngularJS application I need to save only state changes in the browser history. That's why when I'm changing parameters of $location, I'm using replace() method.
For example, When I'm accessing /page1, it is save in the history. 'centre' parameter is added automatically with replace() so it doesn't add a new history entry:
$location.search('centre', hash).replace();
Every time I move a map, 'centre' changes.
When I go to /page2, the new entry in the history is created. When I move map, 'centre' changes.
The thing is that when I press BACK button, I'm going to /page1 but I need to keep 'centre' the same as it was before, but it changes to what was saved together with history entry of /page1.
How would I fix this issue?
I tried to add:
$window.history.replaceState({}, '', $location.absUrl());
After I do replace(), but didn't work.
I found calling the search & replace inside a 0ms timeout ensures it happens in a separate digest cycle from the main state change and prevents the previous state being replaced.
Something like:
$timeout(function() {
$location.search('centre', hash).replace();
}, 0);
This is how I solved this.
First, we need to save search result as previous and current:
$rootScope.$on('$locationChangeStart', function (event, toURL, fromURL) {
if ($rootScope.search.current) {
$rootScope.search.previous = $rootScope.search.current;
}
$rootScope.search.current = $location.search();
});
Then we need to always change the actual location we are in at the moment.
$rootScope.$on('$locationChangeSuccess', function (event, toURL, fromURL) {
$rootScope.actualLocation = $location.path();
});
And if back of forward button was pressed, center must be changed in the URL (using previous search results) without pushing a new history entry.
$rootScope.$watch(function () { return $location.path() }, function (newLocation, oldLocation) {
if ($rootScope.actualLocation === newLocation) {
$location.search('center', $rootScope.search.previous.center).replace();
}
});
I had the same problem and could only get it working by using the native history api, like so:
window.history.replaceState(hash, null, $location.absUrl());

Backbonejs - Back button doesn't work if page transition on same page

Short description of my program and finally the problem:
I have got two pages. The first page list products in rows with a short description. If you click on one you will land on a detail page.
The detail page lists the product details and underneath a couple of related products. If you click on one of the releated products the same page is rendered again with the new information fetched from a REST interface.
If I want to use the browser-back-button or the own back-button to get to the previous product-detail-page a blank page appears. This only happens on my iPad. Using Chrome on a desktop browser works fine. I debugged the application and I figured out, that the backbonejs route is never called. I have no idea why.
Here is my code of the details page:
define([
"jquery",
"lib/backbone",
"lib/text!/de/productDetails.html"
],
function(
$,
Backbone,
ContentTemplate
){
var PageView = Backbone.View.extend({
// product details template
template: _.template(ContentTemplate),
// back-button clicked
events:{
'click a#ac-back-button':'backInHistory',
},
// init
initialize: function(options){
this.options=options;
// bind functions
_.bindAll(this,
'render',
'renderRelatedSeriePlainproduct',
'backInHistory'
);
// listen for collection
this.listenTo(this.options.relatedCollectionPlainproduct, 'reset',this.renderRelatedSeriePlainproduct);
},
// back button
backInHistory: function(e){
e.preventDefault();
window.history.back();
},
// render template
render: function(){
// render template
this.$el.html(this.template(this.model.models[0].attributes));
return this;
},
// render related products
renderRelatedSeriePlainproduct: function (){
var models = this.options.relatedCollectionPlainproduct.models;
if(models.length==0){
$('.ac-plainproduct').hide();
} else{
var elem = $('#ac-related-listing-plainproduct');
var ct="";
ct+='<ul id="ac-list-related-plainproduct">';
$.each(models, function(key, value){
ct+='<li>';
ct+='<a href="index.html?article_id='+value.get('article_id')+'&type='+value.get('type')+'&serie='+value.get('series')+'#product-detail">Link';
ct+='</a>';
ct+='</li>';
});
ct+='</ul>';
elem.append(ct);
}
}
});
// Returns the View class
return PageView;
});
I follow one of the links from renderRelatedSeriePlainproduct.If I click on the back button on the new page the backInHistory function is called, but the window.history.back(); does not call the backbone router.
Maybe the problem is the #hash in the URL, that is not changed during page transition. But this would not explain, why it works perfectly with my Chrome on my desktop machine. For me it seemed to be a problem of asynchronous calls but even there I could not find a problem.
Maybe it helps to list my router code as well. First of all I was thinking it is an zombie issue in backbone, but I remove all events and views while making the transition.
// function called by the route
// details page
productdetail: function() {
$.mobile.loading("show");
_self = this;
// lazy loading
require([
'collection/ProductDetailCollection',
'collection/RelatedCollection',
'view/ProductDetailView'
],
function(ProductDetailCollection, RelatedCollection, ProductDetailView){
// get URL parameters
var articleID = _self.URLParameter('article_id');
var type = _self.URLParameter('type');
var serie = _self.URLParameter('serie');
// product - details
var productDetail = new ProductDetailCollection.ProductDetail({id: articleID});
// related products
_self.relatedCollectionPlainproduct = new RelatedCollection({serie:serie, type:"Electronics", article_id:articleID});
// assign binded context
productDetail.fetch({
// data fetched
success: function (data) {
// page transition
_self.changePage(new ProductDetailView({
model:data,
relatedCollectionPlainproduct:_self.relatedCollectionPlainproduct
}));
// fetch data
_self.relatedCollectionPlainproduct.fetch({reset:true});
}
});
});
},
// page transition
changePage:function (page) {
// remove previous page from DOM
this.page && this.page.remove() && this.page.unbind();
// assign
this.page = page;
// assign page tag to DOM
$(page.el).attr('data-role', 'page');
// render template
page.render();
// append template to dom
$('body').append($(page.el));
// set transition
var transition = "fade";
// we want to slide the first page different
if (this.firstPage) {
transition = "fade";
this.firstPage = false;
}
// make transition by jquery mobile
$.mobile.changePage($(page.el), {changeHash:true, transition: transition});
// page was rendered - trigger event
page.trigger('render');
$.mobile.loading("hide");
},
I tried to use allowSamePageTransition but with no success. Maybe someone could give me a hint. Thanks!
Looks like jQuery Mobile and Backbone's routers are conflicting. Take a look here:
http://coenraets.org/blog/2012/03/using-backbone-js-with-jquery-mobile/
Thats not the reason. I disabled the routing of jquery mobile.
// Prevents all anchor click handling
$.mobile.linkBindingEnabled = false;
// Disabling this will prevent jQuery Mobile from handling hash changes
$.mobile.hashListeningEnabled = false;

AngularJS ngTable not updated

I am using Angular routing in my application as well as ngTable. One of my pages contains a ngTable, and a search form, where data is coming from database using GET method (MongoDB) every time I search, so every time I search the ngTable (table) should be updated, and my problem is that the Table is updated only one time, after loading the page for the first time.
The contoller used for the partial page :
app.controller('SearchController',function($scope,ngTableParams,$http,$filter, $sce){
$scope.searching=function(){
var str = $scope.search.tags;
var TagsArry = str.split(",");
$http.get('/api/GetDoc',{params:{title:$scope.search.title,tags:$scope.search.tags}})
.success(function(data)
{
if(data.notExist!=-1){
$scope.tableParams = new ngTableParams({
page: 1, // show first page
count: 10 // count per page
}, {
total: data.length, // length of data
getData: function($defer, params) {
$defer.resolve(data.slice((params.page() - 1) * params.count(), params.page() * params.count()));
}
});
}
})
.error(function(err){
});
}
});
I was having the same issue. You need to reload $scope.tableParams every time a new search occurs, so every time the search button is clicked. A simple way to do this is to wrap $scope.tableParams.reload() in a function, and then call that function when your search button is clicked.
controller code:
$scope.doSearch = function () {
$scope.tableParams.reload();
}
html code:
<button ng-click="doSearch()">Search</button>
I was also having the similar issue. It is a problem with the ngTable directive. It updates only when data.length changes. I had finally solved this issue, simply add this line before your $http request:
$scope['tableParams'] = {reload:function(){},settings:function(){return {}}};
$http.get('/api/GetDoc',{params:{title:$scope.search.title,tags:$scope.search.tags}})
.success(function(data){
/***** Your Code *********/
});
What it does is, it resets the ng-table settings then it initilize like it does for the first time.

CakePHP and AJAX to update Database without page refresh

I'm working with CakePHP 1.3.7 and I'm trying to do the following:
On a given page, the user can click a link (or image, or button, doesn't matter) that passes a parameter which is saved into a database. BUT, all this, without refreshing the page.
I've been doing some research and I believe I need to use AJAX as well to acomplish this. However, I can't find the a good example/explanation on how to do it.
I think that the idea is to create the link using AJAX, which calls the controller/action that would receive the variable as a parameter and performs the operation to save it in its corresponding field/table of the DB.
Does anyone have a small example of what I want to do? Or maybe point me to some tutorial that explains it... Thanks so much in advance!
EDIT
Well, thank you guys for your replies. THey're not working directly, but I think I'm getting closer to what I want. Here's what i'm doing now:
I have this code in my view:
<div id="prev"><a>click me</a></div>
<div id="message_board"> </div>
I call this JS file:
$(document).ready(function () {
$("#prev").click(function(event) {
$.ajax({data:{name:"John",id:"100"}, dataType:"html", success:function (data, textStatus) {$("#message_board").html(data);}, type:"post", url:"\/galleries\/add"});
return false;
});
});
And my add action in my galleries controller looks like:
function add() {
$this->autoRender = false;
if($this->RequestHandler->isAjax()) {
echo "<h2>Hello</h2>";
print_r($this->data);
$this->layout = 'ajax';
if(!empty($this->data)) {
$fields = array('phone' => 8, 'modified' => false);
$this->User->id = 6;
$this->User->save($fields, false, array('phone'));
}
}
}
When clicking on the '#prev' element, I get a response from the add action, I know because the text 'Hello' is printed inside #message_board. And it does this without refreshing the page, which is why I need. My problem is that I can't make the $.ajax() function to send any data, when it gets to the controller the $this->data is empty, so it never goes inside the if that saves the info to the database (right now it's saving just an easy thing, but I will want it to save the data that comes from the view).
Can anyone see what am I doing wrong? How can I send the data to the controller?
CakePHP does not matter, most of the code you would need for this would be at clientside. Implementing AJAX by yourself is a pain in the $, so you really want to use a library; currently the most popular is probably jQuery. There's a bunch of examples on their AJAX page: http://api.jquery.com/jQuery.ajax/
So, assuming you have something like this in the document:
<form id="s">
<input id="q"/>
<input type="submit" href="Search!"/>
</form>
<div id="r"/>
you can put this in the JavaScript:
$('#s').submit(function(evt) {
evt.preventDefault();
$.ajax({
url: 'foo.php',
data: {
query: $('#q').val()
},
success: function(data) {
$('#r').html(data);
}
});
return false;
});
Then your foo.php only needs to return the fragment HTML that would go into the div#r.
EDIT: I forgot to stop the submit :( Thanks to #Leo for the correction.
EDIT: I can see what your confusion is about. You will not get a data. I haven't worked with CakePHP, but I assume $this->data is what you'd get from $_REQUEST['data']? You don't get that on the server. data is a hash of what is getting submitted; you will directly get the $_REQUEST['name'] and $_REQUEST['id'] (which, I assume, translate into CakePHP as $this->name and $this->id).
You need to add
$('#s').submit(function(evt) {
evt.preventDefault();
To prevent a page refresh, as in Amadans answer just refer to your controller/ action in the url variable
$('#s').submit(function(evt) {
$.ajax({
url: '/patients/search/',
data: {
query: $('#q').val()
},
success: function(data) {
$('#r').html(data);
}
In the patients/add controller action make sure you return a valid result ( in json is good )

Resources