JQGrid load data on another grid with OnSelectRow - php

I have been tearing my hair out over the last couple of days. Just as a quick outline of the problem. I am using JqGrid 4.2.0 (latest version at the time of writing). In a single page, I have two grids. One on the left, looking to act as the navigator. I want to load the data on the right-hand grid with data determined by the row ID of the item clicked on the left hand side.
My problem is that the first selected row ID gets "stuck" and all ajax calls in future are the same identical rowid (for example: if first selected row was 514, every other selected row will output 514 on the ajax call to load the other grid, if first selected was 513, all others 513, etc)
I suspect it might be some kind of variables crossing or somesuch as I placed alert calls for testing throughout the execution and they all alert the correct ID number until the point where the next grid is loaded, at which point the row ID becomes the erroneous one.
Here is my code below:
First segment is the initial list on the left with the OnSelectRow call, and the second section of code is for the data grid on the right hand side which actuall holds the data)
renderImportsList = function(url, data, firstrow) {
var cnames = data.names;
var cmodel = data.model;
currentrow = firstrow;
$("#imports_grid").jqGrid({
url: url + "&type=list",
//caption: "Imports",
datatype: "json",
colNames: cnames,
colModel: cmodel,
recordtext: "<b>Imports: {1}</b>",
autowidth: true,
rowNum: 10000,
toolbar: [true,"top"],
pager: "#imports_grid_pager",
pgbuttons: false,
pginput: false,
viewrecords: true,
multiselect: false,
sortorder: "desc",
sortable: true,
onSelectRow: function(rowid) {
if (rowid != firstrow) {
if ($("#" + firstrow).hasClass("ui-state-highlight"))
$("#" + firstrow).removeClass("ui-state-highlight")
}
setTimeout(function() {
// Display import items
var itype = "checkpoint";
alert(rowid); // This returns the right row ID so far
renderImportItems(url, rowid, itype);
}, 500);
},
loadComplete: function() {
$("#imports_grid tr").css("border-color", "#666");
$("tr.jqgroup").css("background", "#e9efff");
$("tr.jqfoot").css("background", "#ced5e9");
$("#imports_grid tr.jqfoot td").css("border-right", "none");
$("#t_imports_grid").css("padding-bottom", "3px");
$("#imports_grid").setSelection(firstrow, true);
$("#imports_grid").trigger("reloadGrid"); // Call to fix client-side sorting
}
});
$("#imports_grid").jqGrid('navGrid','#imports_grid_pager',{edit:false,add:false,del:false,search:false});
$("#imports_grid").trigger("reloadGrid"); // Call to fix client-side sorting
sizeGrid("imports_grid");
}
This part executes fine, the rowid at this stage is what I clicked on, according to the alert placed above. Below is the second function which is called from inside OnSelectRow in the function above.
renderImportItems = function(url, rowid, itype) {
$.ajax({
url: srvrname + "applications/PMS/views/view/imports/" + itype + ".php",
success: function(data) {
var cnames = data.names;
var cmodel = data.model;
alert(rowid); // Here, the code still executes the right row ID
$("#checkpoint_grid").jqGrid({
url: url + "&rid=" + rowid + "&type=" + itype,
// This is where it breaks. No matter what, I keep getting rowid to equal whichever row was selected the very first time the grid was clicked (or loaded programatically onload)
datatype: "json",
colNames: cnames,
colModel: cmodel,
recordtext: "<b>Total: {1}</b>",
autowidth: true,
rowNum: 500,
pager: "#" + itype + "_grid_pager",
pgbuttons: false,
pginput: false,
viewrecords: true,
multiselect: false,
sortorder: "desc",
sortable: true,
loadComplete: function() {
$("#" + itype + "_grid tr").css("border-color", "#666");
$("tr.jqgroup").css("background", "#e9efff");
$("tr.jqfoot").css("background", "#ced5e9");
$("#" + itype + "_grid tr.jqfoot td").css("border-right", "none");
$("#" + itype + "_grid").trigger("reloadGrid"); // Call to fix client-side sorting
}
});
$("#" + itype + "_grid").jqGrid('navGrid','#' + itype + 'grid_pager',{edit:false,add:false,del:false,search:false});
$("#" + itype + "_grid").trigger("reloadGrid"); // Call to fix client-side sorting
sizeGrid(itype + "_grid");
}
});
}
As you can see above: at the point at which the first alert is called; it is still outputting the correct ID number, but as soon as the second grid is initialized; the ID returns to whatever it was inintially set on the very first call.
Any help provided would be greatly appreciated. If it helps, here are some firebug outputs to demonstrate the issue...
(Domain name removed for privacy)
(First load: programmatic: firstrow selected = 514)
Response: //mydomain.com/views/view/grid.php?rid=514&type=checkpoint&_search=false&nd=1321336809180&rows=500&page=1&sidx=&sord=desc
(Clicked row: selected row = 503)
Response: //mydomain.com/views/view/grid.php?rid=514&type=checkpoint&_search=false&nd=1321336863994&rows=500&page=1&sidx=&sord=desc
(Clicked row: selected row = 510)
Response: //mydomain.com/views/view/grid.php?rid=514&type=checkpoint&_search=false&nd=1321336864848&rows=500&page=1&sidx=&sord=desc

I've experienced the same problem myself. I recommend you define your grid outside the onSelectRow function with datatype set to "local" and only change the parts that change between each load within onSelectRow:
$("#checkpoint_grid").jqGrid('setGridParam', {
url: null
}).jqGrid('setGridParam', {
url: url + "&rid=" + rowid + "&type=" + itype,
datatype: "json"
}).trigger("reloadGrid");
I usually do this with postData: null, but I think the underlying problem is that jqGrid caches some grid params.

You should include GridUnload for the $("#checkpoint_grid") inside of renderImportItems (for example after var cmodel = data.model;):
$("#checkpoint_grid").jqGrid('GridUnload');
The problem is that the code which create grid should be executed once. The code create for example grid headers, pager and some other areas excepting the grid body. Then the Ajax request will be made to get the data for the grid and to fill the body. If the user click on the column header to sort the data by the column or if the user click on the "Next page" button only the data will be refreshed in the grid. So one should create grid only once. If the next call will be done to already existing grid the call will be just ignored. It's the line of code (the internal property grid will be set here).
Additionally I would be included cache: false parameter at least in the second $.ajax call (the call inside of inside of renderImportItems).
Here you will find a demo which uses GridUnload.

I think the following steps should work:
Call the onRowSelect function. Set async: false for your ajax call (optional) and rowid should be kept as a global var
Reload the 2nd grid based on the primary key data from the 1st grid using This

Related

jQuery doesn't work on secondary pages (DataTables)

I have a simple table (created with DataTables), with a final column filled with 2 buttons. These buttons are connected to jquery. The problem is next: If I'm on first page of table and I press one of the buttons, everything works fine. If I press same button on second / third /etc page, function doesn't work anymore... Can you explain me why ? It's first time when I meet this problem. Thank you !
Buttons call jQuery with class, not Id (just a little note)
EDIT:
$('.generare_diploma').click(function(){
var user_id = $(this).attr('id').split('-');
if(user_id[1] != ''){
$.ajax ({
url: "./genereaza.php",
type: "POST",
data: {user_id:user_id[1],todo:'generare_diploma_admin'},
cache: false,
success: function(){
$('#diploma-'+user_id[1]).attr('onclick',location.href = './genereaza.php?user_id='+user_id[1]+'&todo=download_diploma_admin');
},
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert(err.Message);
}
});
}
});
And this is how my anchor looks like:
<a id="diploma-'.$user['user_id'].'" class="btn btn-sm btn-success generare_diploma" data-toggle="tooltip" title="Genereaza diploma !"><i class="fa fa-calendar-check-o"></i></a>
$(document).on('click', '.generare_diploma',function(){
var user_id = $(this).attr('id').split('-');
if(user_id[1] != ''){
$.ajax ({
url: "./genereaza.php",
type: "POST",
data: {user_id:user_id[1],todo:'generare_diploma_admin'},
cache: false,
success: function(){
$('#diploma-'+user_id[1]).attr('onclick',location.href = './genereaza.php?user_id='+user_id[1]+'&todo=download_diploma_admin');
},
error: function(xhr, status, error) {
var err = eval("(" + xhr.responseText + ")");
alert(err.Message);
}
});
}
});
EDIT: jQuery is only aware of the elements in the page at the time it runs, so new elements added to the DOM are unrecognized by jQuery. To combat the problem use event delegation, bubbling events from newly added items up to a point in the DOM which was there when jQuery ran on page load. Many people use document as the place to catch the bubbled event, but it isn't necessary to go all the way up the DOM tree. Ideally you should delegate to the nearest parent existing at the time of page load.
You use .click event on element who are not yet on the dom when you init it.
So you have to init that fonction each time you get new lines in your DataTable or to add a listener with .on(
Since newest jQuery version .on( event has change. Now your principal element have to be present in your DOM when you init the fonction, you can add listener on new elements who gonna be made with DataTable (when you change page with a pagination for example).
so your code : $('.generare_diploma').click(function(){
has to be : $(document|'body'|selector).on('click','.generare_diploma',function(){
But in case that you have to init more than one time , often better to had a .off before your .on( like : $(document|'body'|selector).off('click','.generare_diploma').on('click','.generare_diploma',function(){

jQuery full calendar $.ajax call issue ( using static events on page open )

So I am using Yii and full calendar as a widget which is called in a view of CalendarController. Uppon call for a widget, the widget retrives existing events from the DB and puts them inside the full calendar to display. Now I have also made a simple filter for filtering out events by category they are in ( dropdown with a submit ), so I want to send request to a calendarController method called actionEvents() which then takes what is passed to it ( the category of events for which we want to retrieve events ), gets them back to the jQuery which then calls the calendar again passing it a json_encode(d) array of needed properties to correctly render events under the selected category in the dropdown. The problem I have is that it seems fullcalendar is doing my wanted call ( POST ) as well as one another GET call along with it for some reason so it does return properly formatted json to the jQuery from the method of controller, but just shows an empty calendar without events in it on return. This is how the console looks like after the returned data.
This is the code that calls ajax call
$(document).ready(function() {
var date = new Date(),
d = date.getDate(),
m = date.getMonth(),
y = date.getFullYear();
$('form.eventFilter').submit(function() {
var selectedOption = $('form.eventFilter select').val(),
eventContainer = $('.fc-event-container');
var objectToSend = { "categories" : [selectedOption],"datefrom" : "september2013"/*month + "" + year*/ , "dateto" : "september2013"/*month + "" + year*/};
$.ajax({
url: '<?php echo Yii::app()->createUrl('calendar/events'); ?>',
type: "POST",
async:false,
data: {data : JSON.stringify(objectToSend)},
success: function(data) {
$('#fc_calendar').html('');
$('#fc_calendar').fullCalendar({
events: data
});
console.log(data);
},
error: function() {
console.log(data);
}
});
return false;
})
})
The code that renders initial calendar events on first page load ( open ) is this
<div id="fc_calendar"></div>
<script class="fc_calendar_script">
// gets calendar and its events working and shown
var date = new Date();
var d = date.getDate();
var m = date.getMonth();
var y = date.getFullYear();
$('#fc_calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
editable: true,
events: [
<?php foreach ($eventItems as $event): ?>
{
title: '<?php echo htmlentities($event['eventItems']['title']); ?>',
start: new Date(y,m,d + <?php echo $event['eventItems']['startdate_day_difference']; ?>),
end: new Date(y,m,d + <?php echo $event['eventItems']['enddate_day_difference']; ?>),
url: '<?php echo $event['eventItems']['url']; ?>',
className: [
<?php foreach($event['eventCategories'] as $category) { echo ''.json_encode($category['slug']).','; }?> // and categories slugs as classnames, same purpose
]
},
<?php endforeach; ?>
]
});
</script>
The code in controller is not that important since you can see what it returns in the screenshot :) If someone has an idea of how to get around this I would really be grateful :) Tried everything I know
Ok so bounty goes to whoever answers this question :)
I am having problems with full calendar month rendering when ajax data is returned and events populated. Since I have checkboxes for each category ( events have MANY_MANY relation with categories ) and each time a checkbox is checked or unchecked, JSON array of chosen categories of events is passed on to PHP method which queries DB for all events that go under chose categories and returns all events in a jquery encoded array to the view which then takes that events array and rerenders the calendar like shown in the upper code.
Problem is that when a checkbox is checked or unchecked and ajax returned the calendar always renders on the current month ( so right now it would always rerender itself to show events for september, untill the end of the month, then always for Ocbober and so on ), but what if a user was on lets say November 2013 when he checked event category for which he wanted to filter the events? The calendar would rerender on September still. How could I make it rerender on the month the user was on when he checked / unchecked a checkbox ?
The code that I have which keeps track ( or at least it should ) of the current month when prev or next month buttons are clicked is this
$('.fc-button-next span').click(function(){
start = $('#fc_calendar').fullCalendar('getView').visEnd;
console.log(start);
});
$('.fc-button-prev span').click(function(){
start = $('#fc_calendar').fullCalendar('getView').visStart;
console.log(start);
});
However this code is not tracking properly, sometimes it skips a month, sometimes it stays on the month without change and sometimes it returns propper month, which is bugging me so I cant call this function of the calendar properly which should set calendar to propper month on rerender.
$('#fc_calendar').fullCalendar('gotoDate', start);
I think what you might be looking for is something like
jQuery(function($){
$('form.eventFilter').submit(function() {
$('#fc_calendar').fullCalendar( 'refetchEvents' );
return false;
});
$('#fc_calendar').fullCalendar({
header: {
left: 'prev,next today',
center: 'title',
right: 'month,basicWeek,basicDay'
},
editable: true,
events: function(start, end, callback) {
var selectedOption = $('form.eventFilter select').val(),
eventContainer = $('.fc-event-container');
//create the data to be sent
var objectToSend = {
"categories": [selectedOption],
"datefrom": start.getDate() + '-' + start.getMonth() + '-' + start.getYear(),
"dateto": end.getDate() + '-' + end.getMonth() + '-' + end.getYear()
};
//use jsonp based jQuery request
$.ajax({
url: 'events.json',
data: objectToSend,
cache: false
}).done(function(data){
//on success call `callback` with the data
callback(data)
})
}
});
});
Demo: Plunker
Note: The date param formatting and jsonp is not used here, you will have to change it to match your requirements
I see that you use JSON.stringify(data); this is what i tought your error was
maybe you need a jsonp, and below you have my example
$.ajax({
'url': 'http://domain.com/index.php/api/news?callback=?',
'data': {'data': JSON.stringify(data), callback: 'jsonPCallback'},
'success': function(data) {
// console.log(data);
},
jsonpCallback: jsonPCallback,
dataType: 'jsonp'
});
function jsonPCallback(cbdata){
console.log('callback2')
// console.log(cbdata);
return false;
}
now, do you also use something like
echo $_GET['callback'].'('.CJSON::encode(array('status_live' => 1, 'data' => $data_decoded)).')';
in the controller to return the results ?
also, createUrl might be wrong, because you need a absolute path
Actualy the problem solution is as weird as the problem itself and it is the following. You must use designated way of doing an ajax call to fetch json that is in the plugin documentation, any other way you send your own call ( GET or POST ) and the calendar after that makes yet another call ( hence the another GET call ) if you are using just a "regular" $.ajax, $.post or $.get call using jQueries native functionality
This should really be posted somewhere on the website in some section so that people do not get confused why their calendar is not making ajax calls and I wonder how noone else had similar problem before . So this is the "correct" documentation way of calling it with full calendar which you can find HERE
$('#fc_calendar').html('');
$('#fc_calendar').fullCalendar({
eventSources: [
// your event source
{
url: '?r=calendar/events',
type: 'POST',
data: { data : JSON.stringify(objectToSend)},
error: function(data) {
alert(data);
},
}
// any other sources...
]
});
So it will automaticly fetch any returned ( properly formatted data ) and use it to rerender new calendar with those events. It is very weird way of doing it, but the only way that will work.
I can't comment so, you have an assignment to variable:"nothing" in your last query parameter
double check if you have looked for ajax request in your controller(important!),
and also if this is this a 404 by the apache, you have url rewriting problems,
and it looks like index.php is missing from url?!

datePicker need to click twice to show the unavailable dates

I've created a code which disable certain dates retrieved from database.
Within getDates script I just retrieve dates from database, return them and assign them to array unavailableDates.
<script>
var unavailableDates;
function unavailable(date) {
dmy = date.getDate() + "-" + (date.getMonth() + 1) + "-" + date.getFullYear();
if ($.inArray(dmy, unavailableDates) == -1) {
return [true, ""];
} else {
return [false, "", "Unavailable"];
}
}
$(document).ready(function()
{
$("#datepicker").datepicker({
dateFormat: 'yy-mm-dd',
beforeShowDay: unavailable,
minDate: 0,
firstDay: 1, // rows starts on Monday
changeMonth: true,
changeYear: true,
showOtherMonths: true,
selectOtherMonths: true,
altField: '#date_due',
altFormat: 'yy-mm-dd'
});
$('#datepicker').focus(function(){
//alert($('#name').html());
$.ajax({
url: 'getDates.php',
data: "artist_id="+$('#name').html(),
dataType: 'json',
success: function(data)
{
unavailableDates = data;
}
});
})
});
</script>
It works fine but only when I click in datepicker twice. When I first click it shows all dates (no matter if they are available or not). When I click again, then it shows the unavailable dates.
Does anyone know why? Thanks
Add async: false into your ajax call so the app will wait for the response before continuing, like so
$('#datepicker').focus(function(){
//alert($('#name').html());
$.ajax({
url: 'getDates.php',
data: "artist_id="+$('#name').html(),
dataType: 'json',
async: false,
success: function(data)
{
unavailableDates = data;
}
});
Another thought, you could possibly add this ajax call right into the unavailable function rather then having two things that run first, onFocus and beforeShowDay (although I'm not terribly familiar with the beforeShowDay function)
This may slow down the opening of the date picker though, as it will have to wait for the service so it depends on how fast your service is and what performance requirements you have. Other options if this can be to slow would be to pop up a "getting dates" message or pull the server every X seconds while the page it up (although that could add a lot of extra service calls...)
EDIT: After this comment...
"basically when user selects an option (here they want to book artists so \
when user selects an artist), the unavailable dates of datepicker are
updated automatically."
it seems like loading the list when the artist is selected would make more sense, unless your concerned about changes while the page is open. In that case I would do something like...
On Artist Changed
-Disable date picker, possibly add a small note next to it / under it /
over it that it is loading
-Start ajax call with async true
-In ajax success function, re-enable the picker and remove the message.
This will allow the UI to stay active, allow the user to enter other information while the dates load, and if the service is fast enough, the won't even hardly know it was disabled for a second. Your dates won't be quite a "live" as the other way, but it doesn't sound like they need to be that live. You will need to recheck the dates when the form is submitted anyway.
Because you start the request for getting the unavailable dates when the datepicker is displayed. You have to do this in advance. In the callback of the backend request you can display the datepicker.
var data = $.getJSON($url, function (data) {
//your logic
}).success(function (data) {
//Trigger the first click
$('.datepicker').trigger('click');
});
$(".div_fader").on('click','.datepicker', function () {
$(this).datepicker();
});

jQuery Rating System Modification

I have built a jQuery 5 star rating system, ratings are inserted/stored in database along with no of hits, I am having a problem in inserting rating into database when any star is clicked repeatedly.
I.e., if a star is continuously clicked the rating does not get inserted but hits get inserted which then effect the new resulting rating.
I need to add some delay or stop the click function to fire again, it would be better if a delay can be added to click function.
I am trying stop click function to fire again this way but its not working.
jQuery:
$('.u-rating').click(function (e){
var id = $(this).parent().attr('id');
var rating = ($(this).index()+1)/2;
$.ajax({
type: "POST",
url:"rating.php",
data: {rating:rating, id:id},
cache: false,
success: function(data1)
{
get_rating();
$('#u-rating p').html('Rating Submitted');
}
});
e.preventDefault();
e.stopImmediatePropagation();
return false;
});
How do I stop people from rating multiple times?
I would suggest that your real issue that your backend is registering just the hits but not the ratings - and you should probably focus on fixing the issue, not covering it with a band-aid.
Nevertheless, to address your question: You can use one() to bind the click handler just one, and then re-bind on every success (and error). See this jsfiddle for an example. Here is the code:
HTML:
<button id="button">Vote!</button>​
JS:
var postClick = function () {
console.log('click fired!!');
el = $(this);
el.prop('disabled', true);
//var id = $(this).parent().attr('id');
//var rating = ($(this).index()+1)/2;
$.ajax({
type: "POST",
url:"/echo/json/",
//data: {rating:rating, id:id},
cache: false,
success: function(data1){
//get_rating();
//$('#u-rating p').html('Rating Submitted');
console.log('ajax success, starting timeout peridod. Clicks will not register now, for the next 5 seconds!');
setTimeout(function() {
$('#button').one('click', postClick);
el.prop('disabled', false);
console.log('Clicks are re-enabled!');
}, 5000);
}
});
}
$('#button').one('click', postClick);
​
If your voters are logged-in users, store all ratings made by these users in a table with their user_id, then there's absolutely no problem keeping track of votes. If not, store them in a table with a date and an ip-address.
Since ip's can renew and point to a different user after an approximate interval, you can set a timeout date of about at day/week or so. This would have the drawback that users can keep voting once a day/week (if they haven't changed ip's), I don't know if that's acceptable in your project.
Then you can just (pseudo-code)
if (not exists sql("select rating from voteditems
where ipaddress = #ip_adress // Switch to "user_id" if that's what you're using
and item_id = #item_id
and datevoted > getdate()-1")) // Or -7 or whatever interval you choose
{
insert_rating();
}
The hits can be counted as
select count(rating) from voteditems where item_id = #item_id

jQuery, need help with 'sortreceive' ajax call and POST vars

I have a dilemma that just seems beyond my abilities at the moment!
I have a group of connected sortables using the class 'biglist'.
What I want to do is bind #biglist 's sortreceive callback (which is made whenever a list receives an element from another) to take the 'boxnum' value of the element (which signifies which list its coming from) and perform an UPDATE query changing the id's boxnum value from say 5(list it came from) to 7 (list its been dragged to) so that the state persists.
So the exchange would happen like so (roughly)
$( "#biglist" ).bind( "sortreceive", function(event, ui) {
ajax call to boxchange.php
create vars to represent elements 'boxnum' value and 'box moved to' value
});
Then inside boxchange.php ->
$id = $_POST['id']
$box = $_POST['boxnum']
->update query SET boxid to new boxid WHERE id = posted ID of element
I hope this makes sense. It seems like a pretty slick way to make my program work!
Any help is greatly appreciated.
EDIT:
Just cleaned up the function to see if there are any changes that need to be made to it (which I know there are, because it looks sloppy) This function would need to be copied/altered for each sortable separately but it'd totally make the program work at least!
function ReceiveTwo()
{
$('#sortable2').bind('sortreceive', function(event, ui)
{
boxnum = $(this).attr('boxnum');
id = $(this).attr('id');
$.ajax
({
url: "boxchange.php",
type: "POST",
data: boxnum, id,
success : function(feedback)
{
$('#data').html(feedback)
}
})
});
$('#sortable2').sortable("refresh");
});
$('#sortable2').bind('sortreceive', function(event, ui) {
$.ajax({
url: "boxchange.php",
type: "POST",
beforesend: function(){
boxnum = $(this).attr('boxnum');
id = $(this).attr('id');
},
data: {'boxnum': boxnum, 'id': id},
success : function(feedback) {
$('#data').html(feedback),
}
});
});
beforesend is the event that fires before the ajax call. I believe here you could set your properties to accomplish what you want.
I think the way you want to send your Javascript data to your server-side PHP script is using a Javascript associative array, like so:
$.ajax({
url: "boxchange.php",
type: "POST",
data: {'boxnum': boxnum, 'id': id},
success: function(data,status) { ... }
Your "boxchange.php" script would then be able to access those variables via $_POST['boxnum'] and $_POST['id'].
I think that was your goal, but I'm not entirely sure...

Categories