Checkboxes don't stay checked after pagination - javascript

Whenever I check a checkbox on a listing page, save it then go to page eg 2 (using pagination) and check something there and save it the checkbox on my first page is unchecked. I thought about using AJAX to save checked checkboxes to grails session but don't know how to do that - I'm beginner with JS and using views. Could someone help me out?
Here is the part with listing all companies and checkboxes in my gsp:
<g:form name="company-list-form" action="listCompany">
<div>
<g:textField id="search-field" name="query" value="${params.query}"/>
<span>
<g:checkBox id="only-blockades-box" name="onlyBlockades" class="submit-on-change" value="${params.onlyBlockades}" title="Pokaż tylko blokady"/>
<label for="only-blockades-box">Tylko blokady</label>
</span>
<g:actionSubmit value="${message(code: 'default.buttons.search', default: 'Szukaj')}" action="listCompany" class="button_orange"/>
<g:link action="listCompany" class="button_gray"><g:message code="default.buttons.clean" default="Wyczyść"/></g:link>
</div>
<div class="padding-top">
<table class="table_td company-list-table">
<tbody>
<tr class="gray2">
<th class="first">Id</th>
<th style="max-width: 100px;">Nazwa</th>
<th>Id Kontrahenta</th>
<th title="Dostęp do TPO">TPO</th>
<th style="width: 20px;" title="Dostawa bezpośrednio do magazynu">Dostawa bezpośrednio</th>
<th style="width: 20px;" title="Możliwość potwierdzania zamówień">Potwierdzanie zamówień</th>
<th style="width: 20px;" title="Możliwość importowania awizacji z XLS">Import z Excel</th>
<th style="width: 20px;" title="Możliwość awizowania zamówionych indeksów">Awizacja zam. indeksów</th>
<th style="width: 20px;" title="Możliwość awizowania tygodniowego">Awizacja tyg.</th>
<th style="width: 20px;" title="Dostęp jedynie do awizowania tygodniowego">Tylko awizacja tyg.</th>
<th title="Limit AGD przypadający na każdą kratkę okna prywatnego">AGD</th>
<th title="Limit rowerów przypadający na każdą kratkę okna prywatnego">Rowery</th>
<th>Blokady</th>
<th class="is-blocked-th">Zablokowany?</th>
</tr>
<g:each in="${companyInstanceList}" var="company" status="i">
<tr class="${(i % 2) == 0 ? 'even' : 'odd'} table_td_gray2 ${i + 1 == companyInstanceList?.size() ? 'last' : ''}">
<td class="first" style="text-decoration: underline;">
<g:link action="editCompany" id="${company?.id}">${company?.id}</g:link>
</td>
<td>
${company?.name}
</td>
<td>
${company?.idKontrahenta}
</td>
<td>
<g:checkBox name="tpoAccess.${company?.id}" id="tpo-access-${company?.id}"
checked="${company?.tpoAccess}"/>
</td>
<td>
<g:checkBox name="directDeliveryAvailable.${company?.id}"
id="direct-delivery-available-${company?.id}"
checked="${company?.directDeliveryAvailable}"/>
</td>
<td>
<g:checkBox name="accessToOrderConfirmation.${company?.id}"
id="access-to-order-confirmation-${company?.id}"
checked="${company?.accessToOrderConfirmation}"/>
</td>
<td>
<g:checkBox name="accessToXlsImport.${company?.id}"
id="access-to-xls-import-${company?.id}"
checked="${company?.accessToXlsImport}"/>
</td>
<td>
<g:checkBox name="accessToOrderedProductsAvisation.${company?.id}"
id="access-to-ordered-products-confirmation-${company?.id}"
checked="${company?.accessToOrderedProductsAvisation}"/>
</td>
<td>
<g:checkBox name="accessToLimitedAvisation.${company?.id}"
id="access-to-limited-avisation-${company?.id}"
checked="${company?.accessToLimitedAvisation}"/>
</td>
<td>
<g:checkBox name="accessOnlyToLimitedAvisation.${company?.id}"
id="access-only-to-limited-avisation-${company?.id}"
checked="${company?.accessOnlyToLimitedAvisation}"/>
</td>
<td>
<input type="text" name="agdPrivateWindowLimit.${company?.id}"
value="${company?.agdPrivateWindowLimit}"
class="shortText" id="agd-private-window-limit-${company?.id}"
onchange="validateLimits('agdPrivateWindowLimit.${company?.id}')">
</td>
<td>
<input type="text" name="bicyclePrivateWindowLimit.${company?.id}"
value="${company?.bicyclePrivateWindowLimit}"
class="shortText" id="bicycle-private-window-limit-${company?.id}"
onchange="validateLimits('bicyclePrivateWindowLimit.${company.id}')">
</td>
<td>
<g:link class="button_gray" controller="productGroup" action="list" params="[companyId: company?.id, query: params.query ?: '']">
Blokady
</g:link>
</td>
<td>
<g:if test="${company?.findBlockades()}">
<span title="Dostawca ma aktywne blokady grup towarowych." class="bold large">
✓
</span>
</g:if>
</td>
</tr>
</g:each>
</tbody>
</table>
</div>
<div class="paginateButtons">
<g:paginate controller="company" action="listCompany" total="${companyInstanceTotal}"
params="[query: params.query ?: '']"/>
</div>
<div style="float:right;">
<g:link action="createCompany" class="button_orange">
<g:message code="default.button.create.label" default="Utwórz"/>
</g:link>
<g:actionSubmit action="updateCompanies" name="companyListSubmit" class="button_orange" value="Zapisz"/>
</div>
</g:form>
Here is my javascript file associated with that view:
function validateLimits(name) {
document.getElementsByName(name)[0].value = document.getElementsByName(name)[0].value.replace(/[A-Za-z!##$%^&*" "]/g, "");
var quantity = document.getElementsByName(name)[0].value;
var toBeAvised = 9999;
if (quantity.indexOf(',') > -1 || quantity.indexOf('.') > -1 || /*quantity == "" ||*/ isNaN(quantity)) {
alert("Limit musi być liczbą całkowitą");
document.getElementsByName(name)[0].value = '';
} else if (parseInt(quantity) > toBeAvised) {
alert("Podana liczba jest większa niż maksymalny limit równy " +toBeAvised + ".");
document.getElementsByName(name)[0].value = '';
} else if (parseInt(quantity) < 0) {
alert("Limit musi być liczbą dodatnią!");
document.getElementsByName(name)[0].value = '';
}
}
And here is controller method (listCompany):
def listCompany(Integer max) {
Person person = Person.read(springSecurityService.principal.id)
Company comp = person?.company
params.max = Math.min(max ?: 25, 100)
params.offset = params.offset ?: 0
params.readOnly = true
String q = (params.query as String)?.toLowerCase() ?: ""
def query = Company.where {
id != comp?.id
name =~ "%$q%" || idKontrahenta as String =~ "%$q%"
if (params.onlyBlockades == "on") {
id in ProductGroupBlockade.findAllByCompanyIsNotNullAndEnabled(true)*.companyId
}
}
List<Company> companyInstanceList = query.list([max: params.int("max"), offset: params.int("offset"), sort: "name"])
Integer count = query.count()
if (flash.message) {
params.errors = flash.message
}
[companyInstanceList: companyInstanceList, companyInstanceTotal: count, companySaved: params.companySaved, errors: params.errors]
}
How I could fix that so my checkboxes stay checked after saving? Right now they become unchecked whenever I go to next page and save some checkboxes there.

I tend to use DataTables for situations like this but it depends on the amount of data you're dealing with to how you go about it.
If you have a relatively small data set, say 1000 rows or fewer you can use a plain DataTable, if you have more than this then you may want to use a server side processing DataTable.
Using a DataTable you would do away with all the Grails pagination, give your table an ID and just create the table in javascript like:
<script type="text/javascript">
$(document).ready( function() {
$( '#companyListTable' ).DataTable();
} );
</script>
All the pagination is handled in javascript and check boxes are preserved when navigating through the table pagination.

The reason is that you need to build your own search parameters to be sent with pagination:
<g:paginate total="${instanceTotal}" params="${search}" />
a similar post can be found here with more details of how you build this search params included as links as a form of comment within it.
Edited to add if you wantd to actually ammend pagination yourself by checking additional stuff through jquery i.e.
var something = $('#somFIeld').val()
and adding something through javascript to current pagination instead then take a read of this answer

Related

How to write sort function for List.js?

I use list.js to make a simple sorting of my table's data. Sorting functionality works fine but I want to modify it's initial behaviour. When an user sees the table for the first time he/she should have records with some certain value in one column (with my local currency in this example) put to the top. Just initially, later sorting should work in a standard way.
Let's see the code:
<table id="accountsList">
<thead>
<tr>
<th scope="col" class="sort" data-sort="currency-td" aria-role="button"><span>Currency</span></th>
<th scope="col" class="sort" data-sort="accountNo-td" aria-role="button"><span>Account number</span></th>
<th scope="col" class="sort td-centered" data-sort="used-td" aria-role="button"><span>Used</span></th>
</tr>
</thead>
<tbody class="list">
<tr>
<td class="currency-td">EUR</td>
<td class="accountNo-td">53106010151036926643566665</td>
<td class="used-td td-centered">
<input type="checkbox" checked>
</td>
</tr>
<tr>
<td class="currency-td">PLN</td>
<td class="accountNo-td">83106010151036926643522665</td>
<td class="used-td td-centered">
<input type="checkbox">
</td>
</tr>
<tr>
<td class="currency-td">PLN</td>
<td class="accountNo-td">59996010151036926643566665</td>
<td class="used-td td-centered">
<input type="checkbox" checked>
</td>
</tr>
<tr>
<td class="currency-td">USD</td>
<td class="accountNo-td">33106010151036999643566675</td>
<td class="used-td td-centered">
<input type="checkbox">
</td>
</tr>
</tbody>
<script type="application/javascript">
$(document).ready(function(){
var options = {
valueNames: ['currency-td', 'accountNo-td', 'used-td']
};
var accountsList = new List('accountsList', options);
accountsList.sort("currency-td", {
order: "desc"
});
});
</script>
The only thing I'd like to do is to put all the records with the 'PLN' currency at the top at the beginning. Why I don't just order them the way I want in HTML the way I want and later enable sorting, without initial sorting? Because in fact, these records are generated by PHP (I simplified the code above, just showing an example of generated HTML) and I can't predict what data I will get.
I need to write a sorting function in this place:
accountsList.sort("currency-td", {
order: "desc",
sortFunction: function () {}
});
Do you have any ideas? :)
try using alphabet feature of List.js, smthg like :
var options = {
valueNames: ['currency-td', 'accountNo-td', 'used-td']
};
var accountsList = new List('accountsList', options);
accountsList.sort("currency-td", { alphabet: "PLNABCDEFGHIJKMOQRSTUVXYZplnabcdefghijkmoqrstuvxyz" }
);
This is documented here http://listjs.com/api/#sort
I figured it out this way:
accountsList.sort('currencyTd', {
order: 'asc',
sortFunction: function (a, b) {
if ((a.currencyTd === 'PLN') != (b.currencyTd === 'PLN')) {
return a.currencyTd === 'PLN' ? 1 : -1;
}
return a.currencyTd > b.currencyTd ? 1 :
a.currencyTd < b.currencyTd ? -1 : 0;
}
});
The solution suggested in:
https://stackoverflow.com/a/17254561/5420497

store hidden field value and show them on next page in mvc

In JavaScript hidden field value is stored.
But when clicked on next page hidden field is null it doesn't have values from previous page.
Why is it not loading previous values in next page?
How to load previous value in hidden field??
function AddRemoveCustomer(id) {
//$(".checkBoxClass").click(function (e) {
alert('in main function');
alert(id);
var CustomerIDArray = [];
var hidCID = document.getElementById("hfCustomerID");
if (hidCID != null && hidCID != 'undefined') {
var CustID = hidCID.value;
CustomerIDArray = CustID.split("|");
var currentCheckboxValue = id;
var index = CustomerIDArray.indexOf(currentCheckboxValue);
alert('index value:' + index);
debugger;
if (index == 0) {
alert('if');
CustomerIDArray.push(currentCheckboxValue);
alert('pushed value:' + CustomerIDArray);
} else {
alert('else');
var a = CustomerIDArray.splice(index, 1);
alert("a" + a);
}
hidCID.value = CustomerIDArray.join("|");
alert('Final' + hidCID.value);
} else {
alert('undefined');
}
//});
}
<table id="tblEmailScheduler" class="table-bordered col-offset-12">
<thead>
<tr class="label-primary">
<th style="padding:5px 15px;">
First Name
</th>
<th style="padding:5px 15px;">
Last Name
</th>
<th style="padding:5px 15px;">
Email ID
</th>
<th style="padding:5px 15px;">
Customer Type
</th>
<th style="padding:5px 15px;">
Customer Designation #Html.DropDownList("CustomerDesignation", new SelectList(ViewBag.SelectAllCustomerDesignationDDL, "Value", "Text"), new { id = "CustomerDesignationDDL" , name = "CustomerDesignationDDL" })
</th>
<th style="padding:5px 15px;">
Select All
<div class="checkbox control-group">
<label><input type="checkbox" id="cbSelectAll" /></label>
</div>
</th>
</tr>
</thead>
<tfoot>
<tr>
<th colspan="2">
EmailTemplate : #Html.DropDownList("EmailSubject", new SelectList(ViewBag.SelectAllEmailTemplateDDL, "Value", "Text"), new { id = "SelectAllEmailTemplateDDL" })
</th>
<th colspan="2">
Set Date And Time:
<input type="text" class="from-date-picker" readonly="readonly" />
</th>
<th colspan="2">
<input type="submit" value="Schedule" id="btnSubmit" class="btn btn-default" />
</th>
<td>
</td>
</tr>
</tfoot>
#foreach (var item in Model) {
<tr style="text-align:center">
<td id="tblFirstName">
#item.FirstName
</td>
<td id="tblLastName">
#item.LastName
</td>
<td id="tblEmailID">
#item.EmailID
</td>
<td id="tblCustomerType">
#item.CustomerType
</td>
<td id="tblCustomerDesignation">
#item.CustomerDesignation
</td>
<td>
<div class="checkbox control-group">
<label><input type="checkbox" id="#item.CustomerID" value="#item.CustomerID"
onclick="AddRemoveCustomer(#item.CustomerID)" class="checkBoxClass"/>
#*#Html.CheckBox("Select", new { id = "cbCustomer", item.CustomerID})*#</label>
</div>
</td>
</tr>
}
</table>
<input type="hidden" id="hfCustomerID" />
In looking at your code, I noticed an issue that may be causing you the problem you indicate:
var index = CustomerIDArray.indexOf(currentCheckboxValue);
you then use index to decide if the Id is in the array, by doing this:
if (index == 0) {
it should be
if (index == -1) {
as -1 indicated not found. With it as it is currently, it would hit this line:
var a = CustomerIDArray.splice(index, 1);
and try to splice a negative index, which goes backward from the end of the string, which would give unexpected results.
Your hidden hfCustomerID field is always rendered to the browser as an empty field, because you haven't bound it to anything in your Model.
I assume this table is inside a form which is being posted to your controller? If so, then you could add a new field to your Model, and then use #Html.HiddenFor to render a hidden input field which is bound to that item in your model.
Alternatively, it looks like this field is entirely calculated based on the ticked checkboxes? In which case, update your view to set the value of the hidden field (this will duplicate some logic from your JavaScript though).

How to fix counter not showing correct value as well as resetting with new string

Here's a jsfiddle: https://jsfiddle.net/m6vxgg0m/15/
The console log shows the output.
I've been trying to get the number of occurrences of a string in an array using jQuery. The loop I'm using to check if the string value is present in each index of the array appears to be correct. I'm not sure why it isn't working correctly. I never get the correct counter value. If I keep the string in the text field and I keep hitting enter, the counter keeps increasing even though I set the counter back to 0 right inside the keyup event. If there are two occurrences of a string in the array, the counter should always display the value of 2. But it doesn't. Very frustrated.
JS:
$(function(){ keywordSearchFeature() });
function keywordSearchFeature(){
// Selector Variables
var inputSel = $('#search-term');
var noticeLblSel = $('.searchInstance');
var contentSel = $('.RadGrid.RadGrid_Default.mydatagrid .rgMasterTable tr');
// Functional Variables
var keywordVal;
var keywordValL; // keywordVal lowercase
var keyCounter = 0; // counter
var cellValues = []; //
var cellValuesL = []; // cellValues lowercase
// Type keyword
inputSel.on('keyup', function(e){
// Reset Counter
keyCounter = 0;
// Keyword Value
keywordVal = $(this).val();
// Keyword Lowercase Value
keywordValL = keywordVal.toLowerCase();
// console.log(keywordValL);
// Clear notice label when retyping
noticeLblSel.text('');
// Enter Key
if (e.which == 13) {
if(keywordValL != null && keywordValL != '' && keywordValL.length > 3){
console.log('ENTER KEY CLICKED: Value entered is: ' + keywordValL);
// Store content in arraykeyinstances[]
contentSel.each(function(i,tr){
var tdLines = $('td',tr).map(function(i,td){
// Get each cell string, and trim whitespace
var tdCellContent = $(td).text().trim();
// console.log(tdCellContent);
// Push each cell value to array
cellValues.push(tdCellContent);
cellValuesL.push(tdCellContent.toLowerCase());
});
});
// console.log(cellValues);
console.log(cellValuesL);
for (var i = 0; i < cellValuesL.length; i++) {
if (cellValuesL[i] == keywordValL) {
keyCounter++;
}
}
console.log(keyCounter);
// Notice label text
if(keyCounter > 0) {
noticeLblSel.text('Instance 1 of ' + keyCounter + ' found on this page.');
} else {
noticeLblSel.text('No instances for "' + keywordVal + '" found.');
}
} else {
noticeLblSel.text('Please enter 4 or more characters.');
}
}
});
// Click Events
//$(document).on('click','.btn-searchnext',function(){});
//$(document).on('click','.btn-searchprev',function(){});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="formholder searchkeywordholder">
<div class="form_inner">
<div class="formrow form-col-1" tabindex="0">
<div id="find-in-page">
<div class="fielditem searchfielditem">
<input type="text"
id="search-term"
placeholder="Type in the phrase to search and click Next..."
title="Enter Search Phrase"
class="text searchfield"
aria-label="Search Keyword Field" />
<button id="next"
class="button bttn-clear btn-searchnext"
title="Next"
aria-label="Search Next Button">
Next
</button>
<button id="prev"
class="button bttn-find btn-searchprev"
title="Previous"
aria-label="Search Previous Button">
Previous
</button>
</div>
<label id="labelResult" class="searchInstance"></label>
</div>
</div>
</div>
</div>
<div class="RadGrid RadGrid_Default mydatagrid staticheaders nostripes" id="ctl00_MainContent_customProjectAssets_gridItems" tabindex="0">
<div class="rgDataDiv" id="ctl00_MainContent_customProjectAssets_gridItems_GridData">
<table class="rgMasterTable rgClipCells rgClipCells" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00">
<tbody>
<tr class="groupinghighlight" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00__0">
<td valign="middle">
<div>
</div>
</td>
<td>
<div>
<div>
<div id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl04_divChildAssetStyle">
Antenna B1
</div>
</div>
</div>
</td>
<td>
Equipment and Materials
</td>
<td>
C2 Equipment
</td>
<td>
Antenna
</td>
<td>
Basic
</td>
<td>
B1
</td>
<td>
<div class="rating_general rating_yellow" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl04_divRating" title="Asset's Rate">
0.36
</div>
</td>
<td align="center">
<span class="aspNetDisabled"><input disabled="disabled" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl04_checkboxOverride" name="ctl00$MainContent$customProjectAssets$gridItems$ctl00$ctl04$checkboxOverride" type="checkbox"></span>
</td>
<td>
<span id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl04_spanAssetTag" title="Incident Response/Recovery">IRR</span>
</td>
<td align="center">
<span id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl04_spanClassificationLevel" title="UNCLASSIFIED">U</span>
</td>
<td align="center">
<input id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl04_checkboxDelete" name="ctl00$MainContent$customProjectAssets$gridItems$ctl00$ctl04$checkboxDelete" onclick="$.onCheckDeleteChange('0');" type="checkbox">
</td>
</tr>
<tr class="groupinghighlight" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00__1">
<td valign="middle">
<div>
</div>
</td>
<td>
<div>
<div style="width: 200px; margin: 0 auto;">
<div id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl05_divChildAssetStyle">
Content 1
</div>
</div>
</div>
</td>
<td>
This is content
</td>
<td>
My text
</td>
<td>
lorem ipsum dolor
</td>
<td>
sit amet
</td>
<td></td>
<td>
<div class="rating_general rating_orange" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl05_divRating" title="Asset's Rate">
0.56
</div>
</td>
<td align="center">
<span class="aspNetDisabled"><input disabled="disabled" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl05_checkboxOverride" name="ctl00$MainContent$customProjectAssets$gridItems$ctl00$ctl05$checkboxOverride" type="checkbox"></span>
</td>
<td>
<span id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl05_spanAssetTag" title="No Asset Tag Assigned"></span>
</td>
<td align="center">
<span id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl05_spanClassificationLevel" title="UNCLASSIFIED">U</span>
</td>
<td align="center">
<input id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl05_checkboxDelete" name="ctl00$MainContent$customProjectAssets$gridItems$ctl00$ctl05$checkboxDelete" onclick="$.onCheckDeleteChange('1');" type="checkbox">
</td>
</tr>
<tr class="rgRow" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00__2">
<td valign="middle">
<div>
</div>
</td>
<td>
<div>
<div style="width: 200px; margin: 0 auto;">
<div class="iconGridSubordinateArrow" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl06_divChildArrowImage" style="float: left; width: 17px;"></div>
<div id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl06_divChildAssetStyle" style="float: left; width: 180px;">
equivalent
</div>
</div>
</div>
</td>
<td>
People
</td>
<td>
Individuals
</td>
<td>
lorem
</td>
<td>
ipsum
</td>
<td></td>
<td>
<div class="rating_general rating_yellow" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl06_divRating" title="Asset's Rate">
0.44
</div>
</td>
<td align="center">
<span class="aspNetDisabled"><input disabled="disabled" id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl06_checkboxOverride" name="ctl00$MainContent$customProjectAssets$gridItems$ctl00$ctl06$checkboxOverride" type="checkbox"></span>
</td>
<td>
<span id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl06_spanAssetTag" title="No Asset Tag Assigned"></span>
</td>
<td align="center">
<span id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl06_spanClassificationLevel" title="UNCLASSIFIED">U</span>
</td>
<td align="center">
<input id="ctl00_MainContent_customProjectAssets_gridItems_ctl00_ctl06_checkboxDelete" name="ctl00$MainContent$customProjectAssets$gridItems$ctl00$ctl06$checkboxDelete" onclick="$.onCheckDeleteChange('2');" type="checkbox">
</td>
</tr>
</tbody>
</table>
</div>
</div>
First, the reason that your keyCounter increases each time you hit enter is because you do not reset cellValuesL to an empty array in your keyup event handler. This means that after the first time you hit enter, the contentSel table is parsed and 36 text values are pushed onto cellValuesL. The next time you hit enter, contentSel is parsed again and the same 36 values are again pushed onto cellValuesL so that cellValuesL.length is now 72. The same 36 values get pushed onto cellValuesL each time you hit the enter key.
One way you can fix this is by moving var cellValuesL = []; to inside the keyup event handler. However, a better solution is to move the code that builds the cellValuesL array (contentSel.each) to outside of the keyup event handler. As the text values in the table never change, it does not make sense to keep fetching the texts from the table and building a new array each time the user presses the enter key.
To your second point about having two occurrences of a string in your cellValuesL array, I think you must be confused about what your code is checking. Your code loops through each value in cellValuesL and for each element in that array that equals the lower-cased user input, keyCounter is incremented. In your example, no two elements in cellValuesL are equal, so it is not possible for the loop to ever produce more than one match. What I assume you must want to is to check whether each element in cellValuesL contains the lower-cased user input. If this is the desired behavior, you will need to update your conditional to the following:
for (var i = 0; i < cellValuesL.length; i++) {
if (cellValuesL[i].indexOf(keywordValL) > -1) {
keyCounter++;
}
}
A more modern and elegant way of achieving the same thing as the code above would be to use Array.prototype.filter and an Arrow Function:
keyCounter = cellValuesL.filter(val => val.indexOf(keywordValL) > -1).length;
Finally, I want to suggest that your JavaScript code can be cleaned-up quite a bit. Here is an example that doesn't use any ES6 language features:
$(function () {
var inputSel = $('#search-term');
var contentSel = $('.RadGrid.RadGrid_Default.mydatagrid .rgMasterTable tr');
var noticeLblSel = $('.searchInstance');
var cellValuesL = $('td', contentSel).map(function () {
return $(this).text().trim().toLowerCase();
}).get();
inputSel.on('keyup', function (e) {
noticeLblSel.text('');
if (e.which !== 13) { return; }
var keywordVal = $(this).val();
var keywordValL = keywordVal.toLowerCase();
if (!keywordValL || keywordValL.length <= 3) {
noticeLblSel.text('Please enter 4 or more characters.');
return;
}
var keyCounter = cellValuesL.filter(function (val) {
return val.indexOf(keywordValL) > -1;
}).length;
if (keyCounter > 0) {
noticeLblSel.text('Instance 1 of ' + keyCounter + ' found on this page.');
} else {
noticeLblSel.text('No instances for "' + keywordVal + '" found.');
}
});
});
I have also created an example fiddle.

AngularJS Displaying Table Row on expansion

I am trying to show a more detailed summary of a row when a user clicks on the "+" icon on the row. I got it to work when I used an tag but when I modified it to an tag, the javascript would not kick in.
Here's what I have:
<table class="table" ng-repeat="lineItem in order.OrderLineItems">
<tbody >
<tr >
<td class="col-md-3"><a ng-hide="!lineItem.OrderLineItemModifiers.length " class="glyphicon glyphicon-plus" ng-model=show></a> <b>Item</b></td>
<td class="col-md-3">{{lineItem.Name}}</td>
<td class="col-md-3">{{lineItem.Quantity}}</td>
<td class="col-md-3">{{lineItem.TotalPrice}}</td>
</tr>
<tr ng-repeat="modifiers in lineItem.OrderLineItemModifiers" ng-show="show">
<td class="col-md-3"></td>
<td class="col-md-3 ordermodifier">{{modifiers.Name}}</td>
<td class="col-md-3"></td>
<td class="col-md-3 ">{{modifiers.TotalPrice}}</td>
</tr>
</tbody>
</table>
<div><b>Total Amount: {{order.TotalAmount}}</b></div>
And in the Javascript file:
app.controller('ModalInstanceCtrl', function ($scope, $modalInstance, order) {
$scope.toggleDetail = function ($index) {
$scope.activePosition = $scope.activePosition == $index ? -1 : $index;
};
});
What I am confused about is why would this work if I used an tag instead of an ? With the current code above, I would click on the "+" and it would not expand the row to show the modifier rows
Thank you!
<td class="col-md-3"><a ng-hide="lineItem.OrderLineItemModifiers.length !== 0 " class="glyphicon glyphicon-plus" ng-model=show></a> <b>Item</b></td>
try this. not sure what problem you had.

Combines table filters in jquery

I have a table with different places, and implemented some simple buttons that allow you to filter the list. First filter is location (north, east, central, south, west) which is based on postcode. Another filter is on "impress". This shows you only the places that have have 4 or higher value in the column. Filters work great separately, but not together. The result that I am after is when I press "West" is shows me the places in "West, when I then click impress, I expect to see the places in west with a 4 or 5 score for impress.
JSFiddle here
$('.table td.postcode').each(function() {
var cellText = $(this).html();
var locationString = cellText.substring(0,2);
if (locationString.indexOf('W') > -1){
$(this).parent().addClass('west');
}
if (locationString.indexOf('C') > -1){
$(this).parent().addClass('central');
}
if (locationString.indexOf('E') > -1){
$(this).parent().addClass('east');
}
if (locationString.indexOf('S') > -1){
$(this).parent().addClass('south');
}
if (locationString.indexOf('N') > -1){
$(this).parent().addClass('north');
}
});
$("input[name='filterStatus'], select.filter").change(function () {
var classes = [];
$("input[name='filterStatus']").each(function() {
if ($(this).is(":checked")) {
classes.push('.'+$(this).val());
}
});
if (classes == "") {
// if no filters selected, show all items
$("#StatusTable tbody tr").show();
} else {
// otherwise, hide everything...
$("#StatusTable tbody tr").hide();
// then show only the matching items
rows = $("#StatusTable tr").filter(classes.length ? classes.join(',') : '*');
if (rows.size() > 0) {
rows.show();
}
}
});
$("input[name='impressStatus']").change(function(){
var classes = [];
$("input[name='impressStatus']").each(function() {
if ($(this).is(":checked")) {
classes.push('.'+$(this).val());
}
});
if(classes == ""){
$("#StatusTable tbody tr").show();
}
else{
$(".table td.impress").each(function(){
if($(this).data("impress") >= 4){
$(this).parent().show();
}
else{
$(this).parent().hide();
}
});
}
});
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!--BUTTON FILTERS -->
<div class="btn-toolbar" role="toolbar" aria-label="...">
<div class="btn-group" style="" data-toggle="buttons">
<label class="btn btn-primary outline">
<input type="checkbox" name="filterStatus" value="north" autocomplete="off">North
</label>
<label class="btn btn-primary outline">
<input type="checkbox" name="filterStatus" value="east" autocomplete="off" class="radio">East
</label>
<label class="btn btn-primary outline">
<input type="checkbox" name="filterStatus" value="central" autocomplete="off" class="radio">Central
</label>
<label class="btn btn-primary outline">
<input type="checkbox" name="filterStatus" value="south"autocomplete="off" class="radio">South </label>
<label class="btn btn-primary outline">
<input type="checkbox" name="filterStatus" value="west" autocomplete="off" class="radio">West
</label>
</div><!-- button group -->
<label class="btn btn-primary outline">
<input type="checkbox" name="impressStatus" class="radio" aria-pressed="true" autocomplete="off">Impress her
</label>
</div><!-- btn toolbar-->
<!--TABLE -->
<table class="table" id="StatusTable">
<thead>
<tr>
<th data-sort="string" style="cursor:pointer">name</th>
<!-- <th>Description</th> -->
<th data-sort="string" style="cursor:pointer;">postcode</th>
<th data-sort="int" style="cursor:pointer;">price</th>
<th data-sort="int" style="cursor:pointer;">total</th>
<th data-sort="int" style="cursor:pointer;">impress</th>
<th colspan="4"></th>
</tr>
</thead>
<tbody>
<tr data-link="/places/1">
<td>Name of place 1</td>
<td class="postcode">NW1</td>
<td class="price" data-price='3'>3</td>
<td class="rating" data-rating='69'>69</td>
<td class="impress" data-impress='4'>4</td>
</tr>
<tr data-link="/places/2">
<td>Name of place 2</td>
<td class="postcode">E3</td>
<td class="price" data-price='4'>4</span></td>
<td class="rating" data-rating='89'>89</td>
<td class="impress" data-impress='5'>5</td>
</tr>
<tr data-link="/places/3">
<td>Name of place 3</td>
<td class="postcode">SW3</td>
<td class="price" data-price='2'>2</td>
<td class="rating" data-rating='51'>51</td>
<td class="impress" data-impress='3'>3</td>
</tr>
</tbody>
</table>
Code is probably not the most efficient, but it works :). Once I got this working, I want to add more filters.
(sorry for my bad english)
if these are the only filters you need, you can use two different type of filter:
hide via Javascript
hide via Css
if you use 2 types of filters the filters can work correctly without use a complex javascript code to manage a big number of different cases and combination:
I add a initial (on document load) control that check if a tr has the value impress cell >4, if has it add a new class: is_impress else add an other: no_impress.
$('.table td.impress').each(function(){
var _class = ($(this).data("impress") >= 4) ? "is_impress" : "no_impress";
$(this).parent().addClass(_class);
});
The code of filter by position is the same... but... I edit the filter by impress to add a class to table () when is active and take it off when isn't:
$("input[name='impressStatus']").change(function(){
(!$(this).is(":checked"))
? $("#StatusTable").removeClass("active_impress")
: $("#StatusTable").addClass("active_impress");
});
if the table has the class active_impress a css rules override the inline code of dispaly to hide all the row that haven't an impress >4:
#StatusTable.active_impress tr.no_impress{
display:none !important;
}
This type of filter override any other display modification until the checkbox stay checked.
I edit your fiddle:
https://jsfiddle.net/Frogmouth/gkba343L/1/
USE CSS to more filter
First change on load check, add price:
$('.table tbody tr').each(function(){
var _class = "";
_class += ($(this).find(".price").data("price") >= 2) ? "is_price " : "no_price ";
_class += ($(this).find(".impress").data("impress") >= 4) ? "is_impress " : "no_impress ";
console.log(_class);
$(this).addClass(_class);
});
Add an other handler to new filter:
$("input[name='priceStatus']").change(function(){
(!$(this).is(":checked"))
? $("#StatusTable").removeClass("active_price")
: $("#StatusTable").addClass("active_price");
});
add new selector to the css rule:
#StatusTable.active_impress tr.no_impress,
#StatusTable.active_price tr.no_price{
display:none !important;
}
This is the result:
https://jsfiddle.net/Frogmouth/gkba343L/3/
Optimize code to add more filter:
HTML filter button:
<label class="btn btn-primary outline">
<input type="checkbox" name="impress" class="cssFilter radio" aria-pressed="true" autocomplete="off">Impress her
</label>
use cssFilter to indicate that is a css filter button and use name attribute to define the name of the filter, than use this namespace into the css class:
.active_{name} .no_{name} .is_{name}
And use a generic handler:
$("input.cssFilter").change(function(){
var _name = $(this).attr("name");
console.log(_name);
(!$(this).is(":checked"))
? $("#StatusTable").removeClass("active_"+_name)
: $("#StatusTable").addClass("active_"+_name);
});
With this you can manage all the filter with an unique handler, remember to add the filter to onload check and the new selector for each new filter.
Fiddle:
https://jsfiddle.net/Frogmouth/gkba343L/4/

Categories

Resources