Link to home
Start Free TrialLog in
Avatar of MFredin
MFredinFlag for United States of America

asked on

Keeping track of checked check boxes from page to page on multi-page results

Using Coldfusion 9.  I've got a results page that dynamically breaks up into pages with 30 records on each page.  I want my users to be able to select records on each page via a checkbox and submit to an INSERT function when they have selected the records they want.  The problem is, I need some way to keep track of which records have been checked when the user navigates from page to page of the results.  I was thinking I could somehow keep submitting the form to itself and appending the values from page to page.  Is this the best way to do this?
Avatar of gdemaria
gdemaria
Flag of United States of America image

> I was thinking I could somehow keep submitting the form to itself and appending the values from page to page

I think that is a good approach.  I like submitting a page to itself for a simple, yet powerful approach.

You may also want to consider storing the values in the database.  Not sure if there is any longer term use for the values or if by the end of the session the values can be removed, but the database can also provide you with some good control and it will not slow things down.
>  breaks up into pages with 30 records on each page

Every page looks the same, correct?  It's just a listing with page 1, 2, 3, etc...

If so, I would definitely use just one page with a paging algorithm.  You can easily keep track of the checked records using a simple hidden form field.

The database is still a good option if you are eventually going to use the results, you can store them earlier than you may have been planning.



have you tried using sessions? that is a good way to store variables.
hidden form fields are vulnerable to cross browser scripting

Avatar of MFredin

ASKER

Cool.  I think submitting to the same page with a hidden form field is going to work.  The only problem I'm running into is I'm getting a bunch of duplicates in my list when I go back to a page that I have checked boxes and then submit to another page.... basically it adds duplicates to the hidden form field.  What is the easiest way to keep the duplicates out of my list?
Store the items that are already checked on that page in a second hidden field.   This allow your update logic to know that the item doesn't need to be added again, it also gives you the added benefit of knowing which fields have been unchecked.  That is in case the user navigates back to a previous page and unchecks some boxes.  It's an easy way to see what needs to be removed from the list as well as added to the list.

So to recap, one hidden field for all currently checked items
Another hidden field for only the items already checked on the page being drawn

Avatar of MFredin

ASKER

gdemaria, sounds like this is what I want to do but I'm having a tough time wrapping my head around it.  

The second hidden input is confusing.  How will I know which items have already been checked on that page?  Compare my carrier_id list to the carrier_ids returned from the query for that page?  I'm confused here.  I'm not actually adding anything to my database until the user has checked all the boxes they wanted and selected the insert button.  Until then, I'm just keeping a running list of which boxes they have checked.  But you are right, I need to be able to account for times when they go back to a page and uncheck boxes.  
I understand, give me a few minutes..
let me know if this outline make sense...


<!---- this happens only the very first time the page is loaded, not on any form posts ---->
<cfif NOT isDefined("form.hiddenIDs")>
  <!---- initally populate your hiddenIDs form field will all IDs currently checked in the database ---->
  <cfquery name="getAllChecked" datasource="#request.datasource#">
     select ID
      from table...
  </cfquery>
  <cfset form.hiddenIDs = valueList(getAllChecked.ID)>
</cfif>


<!---- this code will fetch your page full of data ---->
<cfquery name="getPageList" datasource="#request.datasource#">
  select ID, Name, etc..
   from table
  where ... for items of this page...
</cfquery>

<!---- show the items with a checkbox ----->

<cfloop query="getPageList">
 <cfif listFind(form.hiddenIDs,getpageList.ID)> <!--- is it currently checked? ---->
   <input type="Hidden" name="saveIDs" value="#getPageList.ID#"> <!--- remember that it is checked for use in post action ---->
   <cfset status="checked='checked'">
 <cfelse>
   <cfset status=""> <!--- not checked ---->
 </cfif>
 <input type="checkbox" name="pageIDs" value="#getPageList.ID#" #status#> #getPageList.itemName# <br>
</cfloop>

<input type="Hidden" name="hiddenIDs" value="#form.hiddenIDs#">





The action...  

<cfparam name="form.saveIDs" default=""> <!--- this page's items that were checked when the page was drawn ---->
<cfparam name="form.pageIDs" default=""> <!--- this page's items, that are checked when the page was SUBMITTED ---->
<cfparam name="form.hiddenIDs" default=""> <!--- master list of all items checked from all pages ---->

<!--- newly checked IDs to add ---->
<cfloop index="anID" list="#form.pageIDs#">
  <cfif listFind(form.hiddenIDs,anID) eq 0>
    <cfset form.hiddenIDs = listAppend(form.hiddenIDs,anID)>
  </cfif>
</cfloop>

<!--- items that were UNchecked on this submit ---->
<cfloop index="anID" list="#form.saveIDs#">
  <cfif listFind(form.pageIDs,anID)> <!---- it used to be checked, not anymore ---->
     <cfset pos = listFind(form.hiddenIDs,anID)> <!--- find it on the master list ---->
     <cfif pos> <!---- make sure it's not on the master list, it shouldn't be ---->
        <cfset form.hiddenIDs = listDeleteAt(form.hiddenIDs,pos,anID)>
     </cfif>
  </cfif>
</cfloop>

Open in new window

Avatar of MFredin

ASKER

Here is what I have.... might help understand what I'm doing.  I'm still unclear how to integrate your thought into this.


<cfparam name="country" default="US">
<cfparam name="state" default="MN">
<cfparam name="city" default="Springfield">
<cfparam name="distance" default="5">
<cfparam name="carrier_id" default="">

<cfinvoke component="CFC.loads" method="getCoordinates" state="#state#" city="#city#" returnvariable="coordinates" >

<cfquery name="fmcsa">
SELECT census_num
FROM fmcsa LEFT JOIN fmcsa_licensed_link ON fmcsa.CENSUS_NUM = fmcsa_licensed_link.dot_id 
WHERE PHY_NATN = '#country#'
AND PHY_ST = '#state#'
AND 3963.191 * ACOS((SIN(PI() * #coordinates.latitude# / 180) * SIN(PI() * fmcsa.latitude / 180)) + (COS(PI() * #coordinates.latitude# /180) * cos(PI() * fmcsa.latitude / 180) * COS(PI() * fmcsa.longitude / 180 - PI() * #coordinates.longitude# / 180)) ) <= #distance#
GROUP BY CENSUS_NUM
</cfquery>

<!--- Break into Pages --->
<cfparam name="PageIndex" default="0">
<cfset RecordsPerPage = 20>
<cfset TotalPages = ROUND((fmcsa.Recordcount/RecordsPerPage)-1)>
<cfset StartRow = (PageIndex*RecordsPerPage)+1> 
<cfset EndRow = StartRow+RecordsPerPage-1> 

<cfform action="test2.cfm" method="post">

<table>
	<tr>
      <td>
      <!--- Change Pages --->
      <cfloop index="Pages" from="0" to="#TotalPages#">
      <cfoutput>
         <cfset DisplayPgNo = Pages>
         <cfif PageIndex eq pages>
            <input type="submit" name="PageIndex" value="#DisplaypgNo#" style="color:white;background-color:blue;">
         <cfelse>
            <input type="submit" name="PageIndex" value="#DisplaypgNo#">
         </cfif>
        <cfif #pages# neq #totalpages#>|</cfif>
      </cfoutput>
      </cfloop>
      </td>
   </tr>	
<cfoutput>

<!--- Hidden Form Fields --->
<cfinput type="hidden" name="country" value="#country#">
<cfinput type="hidden" name="state" value="#state#">
<cfinput type="hidden" name="city" value="#city#">
<cfinput type="hidden" name="carrier_id" value="#carrier_id#">

<cfloop query="fmcsa">	
<cfif CurrentRow gte StartRow >

	<tr>
		<td>
		<input type="checkbox" name="carrier_id" value="#census_num#" <cfif listcontainsnocase(#carrier_id#, #census_num#)>checked="checked"</cfif>> #fmcsa.CurrentRow#</td>
	</tr>
</cfif>
<cfif CurrentRow eq EndRow>
      <cfbreak>
   </cfif>	
</cfloop>

	<tr>
	<td> 
	<input type="submit" name="submit" value="Save Now" />	
	</td>
	</tr>	
	
   </cfoutput>
</table>
</cfform>

Open in new window

Avatar of MFredin

ASKER

My plan was then to insert the Insert code when <isdefined("FORM.submit")> which means the user has clicked the Save Now button at the bottom.
and why not use sessions variables to store which form fields are checked on every page? :)
Avatar of MFredin

ASKER

dwkd, would you happen to have an example of how I could make this work with session variables?  
SOLUTION
Avatar of dwkd
dwkd
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
oh, i forgot
make sure you have sessions enabled inside the nearest application.cfm
it should only be a few lines:

<cfapplication name="GIVE_IT_A_NAME"
  SessionManagement="Yes"
  SessionTimeout="#CreateTimeSpan(0,0,30,0)#">
and at the end
you'll find all the checked fields results in these variables:

for page 0
session.chkbtns.storeChkd_Page0

for page 1
session.chkbtns.storeChkd_Page1
.
.
.
.
for page n
session.chkbtns.storeChkd_Pagen



I don't understand what value your checkbox is supposed to have.    In this line, you are setting a value of census_num for a checkbox named carrier_id and you're display just the row counter 1,2,3..  

<input type="checkbox" name="carrier_id" value="#census_num#" <cfif listcontainsnocase(#carrier_id#, #census_num#)>checked="checked"</cfif>> #fmcsa.CurrentRow#

I would think they should all be consistent?

<input type="checkbox" name="census_num" value="#fmcsa.census_num#" <cfif listcontainsnocase(mastListOfCensusNumbers, #fmcsa.census_num#)>checked="checked"</cfif>> #fmcsa.census_num#


currently you have the carrier_id in a hidden field (second line below) and within the loop for the checkboxes, so it repeats..  

What value and name should the checkbox really have?

<cfinput type="hidden" name="city" value="#city#">
<cfinput type="hidden" name="carrier_id" value="#carrier_id#">

<cfloop query="fmcsa">  
<cfif CurrentRow gte StartRow >

        <tr>
          <td>
          <input type="checkbox" name="carrier_id" value="#census_num#" <cfif listcontainsnocase(#carrier_id#, #census_num#)>checked="checked"</cfif>> #fmcsa.CurrentRow#
          </td>
        </tr>
</cfif>

Open in new window

Avatar of MFredin

ASKER

dwkd,

Thanks, I'm going to try your solution later today.


gdmaria,  

I just named that field carrier_id for no real reason.  I guess it just made more sense in my head at the time.  I will rename it to census_num to be consistent.  So assume census_num where carrier_id is.
Avatar of MFredin

ASKER

dwkd, is there any way I can check if the current form name is in the session.chkbtns.storeChkd_Page#PageIndex#, and if so, check the check box.  This is in the cases when a user goes back to a page instead of forward, so the check boxes he has already previously selected will remain checked.  

Here is what i have and isn't working but can hopefully give you and idea of what I mean:

<input type="checkbox" name="#census_num#" value="#census_num#" class="carriers" <cfif listcontainsnocase('session.chkbtns.storeChkd_Page#PageIndex#', '#census_num#')>checked="checked"</cfif> >


I changed the check box name to #census_num#.  Could I just use the session variables with my id's and dump them all into a list I could submit to the action page when I click the "Save now" button?  If so, how would I do that?  This way I can use session variables to keep track of which id's are checked on each page and get the list of the checked values to use when inserting on the action page.  Is this possible?  
I would not try to store your values using a session variable for each page.   I believe it would become confusing quickly.   If you change your page size from 30 records on a page to 25, then the items that were on each page are not all shifted around and you will have to look in multiple session variables for your census_num.

I also think you should keep the name for all checkboxes the same.  That way the browser will be responsible for collecting the values and putting them in a nice list for you.   If you have 500 records and 25 of them are checked off, how can you easily find which records are checked if all the form names are different?

ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of MFredin

ASKER

Wow, gdemara, you went way above and beyond on this one.  THANK YOU SO MUCH!  I wish I could award you 10,000 points for this.  Your solution works perfectly!
Super, glad to hear it !