Rails datatables select filter - javascript

I have an ajax datatable for my SKUs. For this I am using the ajax-datatables-rails gem. Searcing and sorting works perfectly, but now I'm trying to add a filtering function to my table and it doesn't seem to do anything. I used this example for the filter function: https://datatables.net/examples/api/multi_filter_select.html.
In the example, select boxes are drawn in the footer, but for me the footer is empty. Like the code doesn't run at all. I also don't get any errors.
I initialize my datatable in my coffeescrip file (assets/javascripts/vendor_skus.js.coffee) so I had to translate it to coffeescript. I'm not experienced with coffeescript or using ajax with rails so I'm kind of lost as to what is going wrong.
How I solved my problem:
The standard select boxes were problematic for my situation, as I am using AJAX for my table and the select boxes seemed to only work properly on client side tables. Instead of going with the standard select boxes, I decided to make my own custom filters. These are regular select boxes like so:
<%= select_tag "store-id", options_from_collection_for_select(#stores, "id", "name"), include_blank: true, class:"store-id form-control" %>
<%= select_tag "status", options_for_select([ "Open", "On Hold", "Cancelled", "Closed", "Error" ]), include_blank: true, class:"form-control", multiple:true %>
This is my coffeescript to make jQuery submit the parameters to the server and reload the table onchange:
$ ->
$('#orders-table').DataTable
processing: true
serverSide: true
retrieve: true
pageLength: 50
title: 'orders'
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]]
ajax: data: (d) ->
d.store_id = $('#store-id').val();
d.status = $('#status').val();
return
$ ->
$('#store-id').on 'change', ->
$('#orders-table').DataTable().ajax.reload()
return
$ ->
$('#status').on 'change', ->
$('#orders-table').DataTable().ajax.reload()
return
In your controller, make sure to pass the parameters along to Datatables like so:
respond_to do |format|
format.html
format.json { render json: OrderDatatable.new(view_context, { store_id: params[:store_id], status: params[:status] }) }
end
And then in your Datatable file, use the parameters to filter your results. In this case I am using a multi select for status, so when the blank value is selected, params[:status].present? results in true. That's why I added a check to see if the first item is an empty string.
def get_raw_records
# insert query here
query = Order.all
query = query.status(params[:status]) if params[:status].present? && (params[:status].count == 1 && params[:status][0] == "") == false
query = query.store(params[:store_id]) if params[:store_id].present?
query.joins(:store)
end

I ran into the same issue when implementing this. I found out that the issue was with this line:
column.search((if val then '^' + val + '$' else ''), true, false).draw()
where coffee script did not like the following bit:
, true, false
After removing it like so:
column.search(if val then '^' + val + '$' else '').draw()
everything worked fine. The caveat to this is, I am not a javascript/coffeescript guy, so what negative impact the result does is beyond me. But like you I am currently battling to get all results to appear in the selectable drop down filter. It only shows any unique values from the current page of data - which is not helpful.
FYI, to get pagination working on this, go to your datatable.rb file and uncomment the correct line toward the top that refers to the pagination you're using. I am using "will_paginate" for bootstrap, so mine looked like this:
include AjaxDatatablesRails::Extensions::WillPaginate
Hope that helps. By chance, did you find a way to show all results in the select filter?

My working code for an ajax datatable filter using the ajax-datatables-rails gem.
in the datatable view I created a table above the datatable to input the range variables, then add some javascript to reload the datatable on change:
<table>
<tbody><tr>
<td>Minimum CWD:</td>
<td><input type="text" id="minCWD" name="minCWD"></td>
</tr>
<tr>
<td>Maximum CWD:</td>
<td><input type="text" id="maxCWD" name="maxCWD"></td>
</tr>
</tbody></table>
<script>
$(document).ready(function () {
// other options
var table = $('#example').DataTable()
$("#minCWD").change(function () {
table.ajax.reload();
});
$("#maxCWD").change(function() {
table.ajax.reload();
});
});
</script>
then to add the filter variables to the ajax call (in the coffee file):
ajax: {
url: $('#example').data('source'),
beforeSend: (xhr) => xhr.setRequestHeader('Content-Type', 'application/json'),
data: (d) ->
$.extend {}, d, 'minCWD': $('#minCWD').val(),
$.extend {}, d, 'maxCWD': $('#maxCWD').val()
}
// note: the beforeSend may not be required
then add a filter in the model_datatable.rb:
def get_raw_records
#YOUR TYPICAL SELECTION...note: I'm using AREL and joining schools with pstats
#now filter by your max min variables
if params['minCWD'].present?
schools = schools.where(pstats[:cwd_percent].gteq(params['minCWD']))
end
if params['maxCWD'].present?
schools = schools.where(pstats[:cwd_percent].lteq(params['maxCWD']))
end
return schools
end
My controller looks like this:
respond_to do |format|
format.html
format.json { render json: ExampleDatatable.new(params, view_context: view_context) }
end
working example here: https://schoolsparrow.com/arizona/schools

Related

Getting search bar to simultaneously work with another search bar [duplicate]

I'm using DataTables (datatables.net) and I would like my search box to be outside of the table (for example in my header div).
Is this possible ?
You can use the DataTables api to filter the table. So all you need is your own input field with a keyup event that triggers the filter function to DataTables. With css or jquery you can hide/remove the existing search input field. Or maybe DataTables has a setting to remove/not-include it.
Checkout the Datatables API documentation on this.
Example:
HTML
<input type="text" id="myInputTextField">
JS
oTable = $('#myTable').DataTable(); //pay attention to capital D, which is mandatory to retrieve "api" datatables' object, as #Lionel said
$('#myInputTextField').keyup(function(){
oTable.search($(this).val()).draw() ;
})
As per #lvkz comment :
if you are using datatable with uppercase d .DataTable() ( this will return a Datatable API object ) use this :
oTable.search($(this).val()).draw() ;
which is #netbrain answer.
if you are using datatable with lowercase d .dataTable() ( this will return a jquery object ) use this :
oTable.fnFilter($(this).val());
You can use the sDom option for this.
Default with search input in its own div:
sDom: '<"search-box"r>lftip'
If you use jQuery UI (bjQueryUI set to true):
sDom: '<"search-box"r><"H"lf>t<"F"ip>'
The above will put the search/filtering input element into it's own div with a class named search-box that is outside of the actual table.
Even though it uses its special shorthand syntax it can actually take any HTML you throw at it.
For recent and new version of DataTables, You should follow these steps:
1- searching option must be true.
2- Hide default search input:
.dataTables_filter {
display: none;
}
3- Add new search input:
<input type="text" id="search">
4- Request search:
$('#search').keyup(function() {
var table = $('.table-meetups').DataTable();
table.search($(this).val()).draw();
});
This one helped me for DataTables Version 1.10.4, because its new API
var oTable = $('#myTable').DataTable();
$('#myInputTextField').keyup(function(){
oTable.search( $(this).val() ).draw();
})
I had the same problem.
I tried all alternatives posted, but no work, I used a way that is not right but it worked perfectly.
Example search input
<input id="searchInput" type="text">
the jquery code
$('#listingData').dataTable({
responsive: true,
"bFilter": true // show search input
});
$("#listingData_filter").addClass("hidden"); // hidden search input
$("#searchInput").on("input", function (e) {
e.preventDefault();
$('#listingData').DataTable().search($(this).val()).draw();
});
More recent versions have a different syntax:
var table = $('#example').DataTable();
// #myInput is a <input type="text"> element
$('#myInput').on('keyup change', function () {
table.search(this.value).draw();
});
Note that this example uses the variable table assigned when datatables is first initialised. If you don't have this variable available, simply use:
var table = $('#example').dataTable().api();
// #myInput is a <input type="text"> element
$('#myInput').on('keyup change', function () {
table.search(this.value).draw();
});
Since: DataTables 1.10
– Source: https://datatables.net/reference/api/search()
I want to add one more thing to the #netbrain's answer relevant in case you use server-side processing (see serverSide option).
Query throttling performed by default by datatables (see searchDelay option) does not apply to the .search() API call. You can get it back by using $.fn.dataTable.util.throttle() in the following way:
var table = $('#myTable').DataTable();
var search = $.fn.dataTable.util.throttle(
function(val) {
table.search(val).draw();
},
400 // Search delay in ms
);
$('#mySearchBox').keyup(function() {
search(this.value);
});
This should be work for you:(DataTables 1.10.7)
oTable = $('#myTable').dataTable();
$('#myInputTextField').on('keyup change', function(){
oTable.api().search($(this).val()).draw();
})
or
oTable = $('#myTable').DataTable();
$('#myInputTextField').on('keyup change', function(){
oTable.search($(this).val()).draw();
})
You could move the div when the table is drawn using the fnDrawCallback function.
$("#myTable").dataTable({
"fnDrawCallback": function (oSettings) {
$(".dataTables_filter").each(function () {
$(this).appendTo($(this).parent().siblings(".panel-body"));
});
}
});
$('#example').DataTable({
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": "../admin/ajax/loadtransajax.php",
"fnServerParams": function (aoData) {
// Initialize your variables here
// I have assign the textbox value for "text_min_val"
var min_val = $("#min").val(); //push to the aoData
aoData.push({name: "text_min_val", value:min_val});
},
"fnCreatedRow": function (nRow, aData, iDataIndex) {
$(nRow).attr('id', 'tr_' + aData[0]);
$(nRow).attr('name', 'tr_' + aData[0]);
$(nRow).attr('min', 'tr_' + aData[0]);
$(nRow).attr('max', 'tr_' + aData[0]);
}
});
In loadtransajax.php you may receive the get value:
if ($_GET['text_min_val']){
$sWhere = "WHERE (";
$sWhere .= " t_group_no LIKE '%" . mysql_real_escape_string($_GET['text_min_val']) . "%' ";
$sWhere .= ')';
}
If you are using JQuery dataTable so you need to just add "bFilter":true. This will display default search box outside table and its works dynamically..as per expected
$("#archivedAssignments").dataTable({
"sPaginationType": "full_numbers",
"bFilter":true,
"sPageFirst": false,
"sPageLast": false,
"oLanguage": {
"oPaginate": {
"sPrevious": "<< previous",
"sNext" : "Next >>",
"sFirst": "<<",
"sLast": ">>"
}
},
"bJQueryUI": false,
"bLengthChange": false,
"bInfo":false,
"bSortable":true
});

After set localization in Datatables needed change label text

I am using https://datatables.net/ for my tables. I need localization in this tables witch will set like this:
$('#tableId').dataTable( {
"language": {
"url": "//cdn.datatables.net/plug-ins/1.10.11/i18n/Slovak.json"
},
...
but at search input is label which i do not want... Is there any way in init. set label hidden? or empty string? I was trying (after localization set)
...
language: {
"sSearch": ""
}
or
...
oLanguage: {
"sSearch": ""
}
but without result... Any ideas?
You cannot modify the language settings once they are set, without recreating the table. You could load the language JSON first, modify it and then initialise the datatable. Or you could simply strip out plain text from the filter / search filter <label> :
var table = $('#example').DataTable({
...
initComplete : function() {
$('.dataTables_filter label').contents().filter(function() {
return this.nodeType === 3 //TEXT_NODE¹
}).remove()
}
})
The loop is necessary due to the nature of the injected markup :
<div class="dataTables_filter">
<label>
Search
<input />
</label>
</div>
So we cant just use .text('') or similar.
¹ https://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247

Updating an ArrayAttribute with ReactJs

EDITED:
renamed shouldComponentUpdate to onClick
I'm using Ruby on Rails with the gem react-rails. The idea is to use a "PATCH" method to update an ArrayAttribute but using just JavaScript. To be clear, I'm still a newbie building a project while learning.
The story is, when a user checks a checkbox, it marks their post as complete. Their Post's table has a column for is_complete: :boolean, :default => false. Im using Postgres for the database.
var Foo = React.createClass({
getInitialState: function() {
return {
is_complete: this.props.data.is_complete, # shows "Empty object"
# is_complete: this.props.data[0].is_complete ..... shows "false"
# I could not use that because data[0] and data[1] etc...
}
},
onClick: function(){
var newVal = this.state.is_complete;
this.setState({
is_complete: React.addons.update(this.state.is_complete, { '$set': [ newVal ] })
})
},
render: function() {
var supports = (s) => (
<input type="checkbox" onChange={this.onClick}
/> Mark complete
);
return (
<div>
{this.props.data.map(supports)}
</div>
);
}
});
Index.html.erb:
<%= react_component('Foo', { data: #userlist }) %>
controller:
#userlist = #user.supports.as_json(:only => [:is_complete] # shortened for emample
When the checkbox is checked I get Uncaught TypeError: Cannot read property of is_complete of undefined
I'm looping through all of that user's posts (supports) and outputting the result on one page with a checkbox to mark as complete. I could achieve something similar by adding the chechbox inside of the edit page but I don't want that.
After the edit, I'm not getting the result I want. I want when checked, Array[1] and [2]'s is_complete is set to true or false.
Somehow I need to loop the getInitialState(), is that possible? I see not documentation on that.

jQuery Tablesorter File Size in Rails App

So all of my columns sort without issue, except for my Media column which displays quotas for file size limits (GB, TB, etc.) I suspect the Rails NumberHelper number_to_human_size isn't playing nicely with tablesorter. Anyone have an idea how to get it to sort, while utilizing the NumberHelper?
_table.html.haml
%table#myTable.tablesorter
%thead
%tr
%th Name
%th.right Per Month
%th.right Members
%th.right Additional
%th.right Media
%th.right Subscriptions
- if #plans.any?
%tbody
- #plans.each do |plan|
%tr
%td
= link_to admin_plan_path(plan) do
= plan.name
%td.right
= "$ #{plan.base_price_in_cents / 100}"
%td.right
= plan.included_users
%td.right
= "$ #{plan.price_in_cents / 100}"
%td.right
= number_to_human_size(plan.media_data_quota) || '∞'.html_safe
%td.right
= link_to organizations_admin_plan_path(plan) do
= plan.subscriptions.count
application.js
$(document).ready(function()
{
$("#myTable").tablesorter( {sortList: [[0,0], [1,0]]} );
}
);
To make file sizes sort properly, you'll need a parser to convert "GB" and "TB", etc, into sortable numbers.
There is a metric parser available on my fork of tablesorter - demo which converts both metric & binary values to make sorting work.
To use it, load the parser file, then add a sorter-metric and data-metric-name attribute:
<th class="sorter-metric" data-metric-name="b|byte">Media</th>
I haven't tested it, but if you are using the original tablesorter, this parser should still work. If that is the case, the sorter class name won't work, so you'll need to set the headers option:
headers: {
0 : { sorter: 'metric' }
}

issues with jquery-select2 and rails form validation error

I'm using the select2 jQuery plugin, on a rails form to do autocompleting on a multi-select field. Everything works fine if there are no validation errors on the page. If there is a validation error (not related to this element), then the javascript portion gets an empty element and fails on the JSON.parse call.
However inspecting with chrome-tools show that the Form Data has the correct information under services
services:[{"id":93,"text":"Old School"},{"id":94,"text":"Gels"}],93,94
Here is the view snippet
<%= f.label :services, "Services" %>
<input name="services" type='hidden' id='services' data-values='<%= #services %>' value='<%= #selected_services %>' style="width: 100%"/>
The Javascript looks like this.
var initSel = function (element, callback) {
console.log("intiSel data BRFORE json parse", $(element).val());
try {
var data = JSON.parse($(element).val());
callback(data);
console.log("intiSel data AFTER json parse", data);
} catch (e) {
console.error("Parsing error:", e);
}
}
$(function() {
$("#services").select2({
initSelection: initSel,
createSearchChoice: function(term, data) {
if ( $(data).filter(function() {
return this.text.localeCompare(term)===0;
}).length===0) {return {id:term, text:term};}
},
multiple: true,
data: function (){
var data = $('#services').data('values');
return {results:data};
}
});
});
I had same problem, after validation error the select2 inputs fields were not able to load data.
I'm not sure that it will helps for your case but it can help other stack users with select2 error after validation.
In my case the error was coming from the controller. I was using a before_action filter to get the variables to prepare the options or the data for the select2 inputs fields.
I realize that I was missing some actions in my filter, so the variables were not generated anymore.
class MyController < ApplicationController
before_action :prepare_data, only: [:edit, :update, :new, :create] #now I had all my actions not only edit and new for instance.
private
def prepare_data
#my_var_for_data_select2 = User.all.collect.collect{|u| u.username}
end
end

Categories