jQuery Tablesorter File Size in Rails App - javascript

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' }
}

Related

How to change the display format on a P13nItem TimePicker/DatePicker?

I'm trying to change the display format on the DatePicker/TimePicker used by the sap.m.P13nItem when the selected column type is date/time.
I have tried changing the aggregation P13nItem from the P13nFilterPanel in order to include the property formatSettings, but it didn't work.
Here is a sample of my XML view code.
<P13nFilterPanel id="filterPanel" visible="true" type="filter" containerQuery="true" items="{
path: 'SchedulingFilter>/ColumnCollectionFilter'
}" filterItems="{
path: 'SchedulingFilter>/FilterItems'
}">
<P13nItem columnKey="{SchedulingFilter>columnKey}" text="{SchedulingFilter>label}" type="{SchedulingFilter>type}" maxLength="{SchedulingFilter>maxLength}" formatSettings="{SchedulingFilter>formatSettings>" />
<filterItems>
<P13nFilterItem columnKey="{SchedulingFilter>keyField}" operation="{SchedulingFilter>operation}" value1="{SchedulingFilter>value1}" value2="{SchedulingFilter>value2}" exclude="{SchedulingFilter>exclude}" />
</filterItems>
</P13nFilterPanel>
Here is an extract of how I'm filling the bound data.
$.each(columnsKeys, function (i, item) {
const columnData = {};
const columnDescriptionItem = columnDescription[item];
columnData.columnKey = item;
columnData.text = columnDescriptionItem.label;
columnData.type = columnDescriptionItem.type;
columnData.formatSettings = {
pattern: 'yyyy/MM/dd',
UTC: false
};
columnData.maxLength = columnDescriptionItem.maxLength;
columnData.visible = columnDescriptionItem.visible;
columnData.index = columnDescriptionItem.index;
columnData.isEditable = columnDescriptionItem.isEditable;
columnData.isFilter = columnDescriptionItem.isFilter;
columnData.isSorter = columnDescriptionItem.isSorter;
columnsData.push(columnData);
});
The default behavior of the control displays the time/date fields as:
https://ibb.co/JcJJZhJ.
Edit: I discovered that the default behavior is based on the user's locale. I'm not considering the user's locale to change the display format on the others parts of my application.
I want to achieve, for example, the display formats "yyyy/MM/dd" and "hh:mm:ss" on these fields.
I had to extend the P13nConditionPanel (this one is responsible for the time/date components instantiation) and the P13nFilterPanel (it creates the P13nConditionPanel) on version 1.44.6 of SAPUI5 in order to solve this problem. I only had to add the necessary parameters to the DatePicker and TimePicker constructors (as shown below).
case "date":
oConditionGrid.oFormatter = sap.ui.core.format.DateFormat.getDateInstance();
params.displayFormat = DateFormatter.displayFormat();
oControl = new sap.m.DatePicker(params);
break;
case "time":
oConditionGrid.oFormatter = sap.ui.core.format.DateFormat.getTimeInstance();
params.displayFormat = TimeFormatter.getDisplayFormat();
oControl = new sap.m.TimePicker(params);
I posted my customized extended components code on pastebin:
Customized P13nConditionPanel
Customized P13nFilterPanel
I will later open an enhancement request on openui5 Github.

Rails datatables select filter

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

HTML5 and angularJS only conditional template solution possible (without ComponentOne pricetag)?

I am looking at the ComponentOne Wijmo angularJS conditional template example and dynamic columns with templates example further down the page here:
http://demos.componentone.com/wijmo/5/Angular/CellTemplateIntro/CellTemplateIntro/
ComponentOne is asking quite a bit of $$$ for the software and I just need something built as a one-off.
I have a database of consignment customers and their inventory in MS Access from a form from about ten years ago.
I print out price labels, bar codes, product information, and several receipts for the each items on consignment using static html pages as templates.
I would like to have more control over what I am able to select to print out by moving to HTML5 and AngularJS.
Not to sound contemptuous, but looking at the ComponentOne example below, I am not clear on what is special or proprietary about what they have designed. I would like to design my own version from scratch with guidance from the SO Brain Trust.
HTML
<div class="col-md-6 conditional">
<wj-flex-grid
items-source="data3"
allow-sorting="false"
initialized="dynaColumnsFlexInit(s)"
style="height:300px"
selection-mode="None"
allow-dragging="None"
defer-resizing="true">
<wj-flex-grid-column
header="Country"
binding="country">
<wj-flex-grid-cell-template cell-type="GroupHeader">
<ng-include
src="'scripts/CellTemplates/countryGroupHeaderTemplate.html'">
</ng-include>
</wj-flex-grid-cell-template>
</wj-flex-grid-column>
<!-- ng-init here creates the colCtx property with subproperties
that are isolated on a column level, that is not visible to
another columns but share data with all the cell templates
defined for the column. -->
<wj-flex-grid-column
ng-repeat="col in statisticsColumns"
ng-init="colCtx = { reportType: col.reportType || 'Chart' }"
ng-if="col.isAvailable"
header="{​{col.header}}"
binding="{​{col.binding}}"
width="{​{col.width}}"
format="{​{col.format}}"
aggregate="Sum"
align="{​{col.align}}">
<wj-flex-grid-cell-template
cell-type="ColumnHeader"
ng-if="col.columnHeaderTemplateUrl">
<ng-include src="col.columnHeaderTemplateUrl">
</ng-include>
</wj-flex-grid-cell-template>
<wj-flex-grid-cell-template
cell-type="Group"
ng-if="col.groupTemplateUrl">
<ng-include src="col.groupTemplateUrl">
</ng-include>
</wj-flex-grid-cell-template>
</wj-flex-grid-column>
</wj-flex-grid>
<div style="margin:5px 0 5px"><b>Show statistics for:</b></div>
<wj-list-box
class="checkable-listbox"
style="min-width:150px"
items-source="statisticsColumns"
display-member-path="header"
checked-member-path="isAvailable">
</wj-list-box>
</div>
JS file
var getCv = function (data) {
var dataCv = new wijmo.collections.CollectionView(data);
dataCv.sortDescriptions.push(new
wijmo.collections.SortDescription('date', true));
dataCv.groupDescriptions.push(new
wijmo.collections.PropertyGroupDescription('country'));
return dataCv;
}
$scope.data3 = getCv(data);
$scope.statisticsColumns = [
{
binding: 'downloads',
header: 'Downloads',
width: '230',
align: 'center',
format: 'N0',
columnHeaderTemplateUrl:
'scripts/CellTemplates/statHeaderTemplate.html',
groupTemplateUrl: 'scripts/CellTemplates/statGroupTemplate.html',
reportType: 'Chart',
isAvailable: true
},
{
binding: 'sales',
header: 'Sales',
width: '230',
align: 'center',
format: 'N2',
columnHeaderTemplateUrl:
'scripts/CellTemplates/statHeaderTemplate.html',
groupTemplateUrl: 'scripts/CellTemplates/statGroupTemplate.html',
reportType: 'Chart',
isAvailable: false
},
{
binding: 'expenses',
header: 'Expenses',
width: '230',
align: 'center',
format: 'N2',
columnHeaderTemplateUrl:
'scripts/CellTemplates/statHeaderTemplate.html',
groupTemplateUrl: 'scripts/CellTemplates/statGroupTemplate.html',
reportType: 'Table',
isAvailable: true
},
];
$scope.dynaColumnsFlexInit = function (flex) {
flex.collapseGroupsToLevel(0);
flex.columnHeaders.rows.defaultSize = 36;
flex.cells.rows.defaultSize = 156;
}
Am I missing something here behind the scenes, or would a generic flex grid of any kind accomplish the same thing without the hefty price $$$ ?
statHeaderTemplate file:
{​{$col.header}}:
<wj-combo-box
items-source="['Chart', 'Table']"
selected-value="colCtx.reportType"
style="width:100px;font-weight:400"
is-editable="false">
</wj-combo-box>
statGroupTemplate file:
<div style="font-size:small;text-align:center">
<wj-flex-grid ng-if="colCtx.reportType == 'Table'"
items-source="$item.items"
is-read-only="false"
headers-visibility="None"
selection-mode="Cell"
format="{​{$col.format}}"
style="height:140px;width:200px">
<wj-flex-grid-column
binding="date"
width="*">
</wj-flex-grid-column>
<wj-flex-grid-column
binding="{​{$col.binding}}"
width="*">
</wj-flex-grid-column>
</wj-flex-grid>
<wj-flex-pie
ng-if="colCtx.reportType == 'Chart'"
items-source="$item.items"
binding="{​{$col.binding}}"
tooltip-content="<b>{value:{​{$col.format}}}</b><br/>{date:MMM yyyy}"
style="height:140px;width:140px;display:inline-block">
<wj-flex-chart-legend position="None"></wj-flex-chart-legend>
<wj-flex-pie-data-label
content="'{date:MMM}'"
position="Inside">
</wj-flex-pie-data-label>
</wj-flex-pie>
</div>
countryGroupHeaderTemplate
<img ng-src="resources/{​{$item.name}}.png" />
{​{$item.name}}
If you notice the statHeaderTemplate, statGroupTemplate, and countryGroupHeaderTemplate have the Angular ng references, but I see the wijmo references interspersed (wj-whatever) and the wijmo collection (see the JS tab).
I am completely open to suggestions - - whatever works so I can make conditional selections for what I want to display within each column (and in what form I choose) for the corresponding row.
My goal is to keep the static html files for printing the borders and logos, and use the cell data from the flex chart as inputs to the templates so I can print out selected items in one pass.
I want to be realistic about whether this is something that can be dissected and redone using only HTML5 and AngularJS before I start the project.
I want to get away from MS Access / VBA.
I am to the point that even if I have to give up the static HTML files templates to keep AngularJS happy, I am willing to do it, but the static HTML files have graphics, etc. I prefer to keep.
Is there a way to modify the templates which generate my static HTML files to work directly with AngularJS somehow instead?
Thanks in advance...

The entity with name <entityName> was not found in the MetadataCache

Following a Microsoft hands-on lab for Dynamics CRM 2011, I am attempting to add a custom view to a form that responds 'onchange' to a particular property. Here is my function to add the custom view:
function HandleOnChangeDVMInformationLookup()
{
var locAttr = Xrm.Page.data.entity.attributes.get("new_referringdvm");
if (locAttr.getValue() != null)
{
var dvmId = locAttr.getValue()[0].id;
var viewDisplayName = "DVM Information";
var viewIsDefault = true;
var fetchXml = '<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false"><entity name="dvminformation"><attribute name="dvminformation_id"/><attribute name="dvminformation_name"/><attribute name="new_firstname"/><attribute name="new_lastname"/><filter type="and"><condition attribute="id" operator="eq" value="' +dvmId +'"/></filter></entity></fetch>';
var layoutXml = '<grid name="resultset" object="10001" jump="dvminformation_name" select="1" icon="1" preview="1"><row name="result" id="dvminformation_id"><cell name="dvminformation_name" width="300" /><cell name="new_firstname" width="125"/></row></grid>';
var control = Xrm.Page.ui.controls.get("new_dvm_information");
control.addCustomView("62e0ee43-ad05-407e-9b0b-bf1f821c710e", "dvminformation", viewDisplayName, fetchXml, layoutXml, viewIsDefault );
}
}
Upon changing the selected 'dvm' in the form and triggering this function I receive the following error:
Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: The entity with a name = 'dvminformation' was not found in the MetadataCache.Detail:
-2147217150
The entity with a name = 'dvminformation' was not found in the MetadataCache.
2013-06-10T22:01:49.4392114Z
Is 'dvminformation' not the entity name I just defined in the XML? Am I missing a step?
Thanks.
It's unlikely that dvminformation is a real entity name. Are you sure there is an entity that exists with that name?
Open the solution and look for the entity, then check its schema name.
If its a custom entity they usually have the format of prefix_name, e.g. new_timeline, new_alert, in your case it might just be dvm_information. If dvm is your solution prefix.
Only system entity have a name without an underscore, e.g. contact, account, incident and dvminformation doesn't look like a system entity to me.
I had the same error message with the customerAddress entity.
Turns out I referenced the entity as "customerAddress" (note the camel case).
But CRM wants logical names of entities and attributes in all lower case. So "customeraddress" did work.
Check if you are connecting to correct org (web.config?)
See

routing/asset pipeline issue - undefined javascript method

I'm getting back into Rails (it's been a few years) so I'm pretty sure I'm just missing something simple. Tho it could also be my lack of understand of how javascript works within Rails.
I think I have my view (in haml) set up correctly. I have added the javascript to a file that I made sure was included in the layout. (And the css looks right.) I'm just not getting the javascript function (a slideshow I found online) to connect to the view. I'm trying to use %body{ :onload => setUpslideShow() }
Here's my view:
%body{ :onload => setUpSlideShow() }
%script{type: 'text/javascript'}
if ( ! window.CMFmainmenu ) { CMFmainmenu = {}; }
var s = CMFmainmenu;
s.user_id = "#{#user.id.to_s}";
s.partial_mainmenu_path = "/users/" + s.user_id + "/xx/mainmenu";
s.add_new_senior = "#{UsersController::ADD_NEW_SENIOR}"
s.add_new_senior_path = "#{new_seniors_settings_path(#locale,#user,#senior)}"
#mainmenu
... (edited out to save space) ...
#slideshow.greenBorder
#slides
= image_tag '/assets/newlook/div_1_img.png', class: 'slide'
%p
Everyone loves photo albums.
Get your user ready to brag, and
populate and arrange albums by
event, special people, year or any
category you can imagine.
=link_to "Learn how.", ''
= image_tag '/assets/newlook/div_2_img.png', class: 'slide'
%p
If typing is difficult for your
loved one, remove the frustration
of a typed response. They can
respond with a voice message, or
with auto replies that you set up.
=link_to "Learn how.", ''
= image_tag '/assets/newlook/div_3_img.png', class: 'slide'
%p
Arms too short? You can specify
the minimum font size used for
your user's email.
=link_to "Learn how.", ''
#slides-controls
1
2
3
Here's my javascript:
if (! window.CMFuser) { CMFuser = {}; }
$(function() {
var s = CMFuser;
... (edited out to save space) ...
// slideshow
slidePrefix = "slide-";
slideControlPrefix = "slide-control-";
slideHighlightClass = "highlight";
slidesContainerID = "slides";
slidesControlsID = "slides-controls";
setUpSlideShow = function()
{
... lots of code that doesn't get called so I'm leaving it out to save space ...
And here's what I think the relevant line is in the layout: = javascript_include_tag "lib/modernizr-2.0.6.min", "lib/respond.min","application", "users" where "users" is the javascript file. When I comment out the %body{ :onload => setUpslideShow() }, the javascript file appears in the html source.
The full text of the error:
NoMethodError in Users#mainmenu
Showing /opt/cmf/app/views/users/mainmenu.html.haml where line #4 raised:
undefined method `setUpSlideShow' for #<#<Class:0x007fe054fa0a28>:0x007fe05594ae20>
Extracted source (around line #4):
2: - # users/mainmenu
3:
4: %body{ :onload => setUpSlideShow() }
Thanks
Shouldn't the value for :onload be a string?
%body{ :onload => 'setUpSlideShow()' }
You do want to produce this HTML after all, right?
<body onload="setUpSideShow()">

Categories