Using tablesorter custom parser only for filtering with Checkboxes - working example needed - checkbox

I am trying to implement filtering my checkbox checked status similar to (or exactly like?) Ivan when he posted "Using tablesorter custom parser only for filtering". I've gone back and forth on custom parsers and text extraction and every permutation from the examples provided in the docs to no avail.
Could someone look at my example posted at
http://jsfiddle.net/5fLr7c4o/14/
and help me get it working?
I'm using the headers and textExtraction function provided in that and other examples:
headers: {
0: {
sorter: 'false',
filter: 'parsed'
}
},
textExtraction: {
0: function (node, table, cellIndex) {
return $(node).find('.MyCheckbox').prop('checked') ? 'True' : 'False';
}
}
To boil it down, I have two buttons. One will filter anything without the checkbox checked, the other resets the filter. The reset is working fine. The filter (in my local file) filters everything. jsfiddle doesn't work at all.

The jsFiddle isn't working because jQuery is being loaded after the plugin. And the framework is set to load jQuery v1.11.0, so jQuery is actually being loaded twice. The second copy overrides the first and the tablesorter is associated to the first copy. Lots of stuff break - here is the demo updated to remove the second copy - but it still doesn't work!
If you use the parser-input-select.js file included in the repository, it has a checkbox parser that updates the cell after changing so the sort updates properly. Anyway, there are four versions of the code, the older ones don't use the mentioned parser. The demo you might be interested in is this one: http://jsfiddle.net/abkNM/6163/ You probably don't need the pager, so just don't include that code:
$(function() {
var $table = $('table').tablesorter({
theme: 'blue',
widgets: ['zebra', 'filter'],
widgetOptions : {
group_checkbox: [ "checked", "unchecked" ]
},
headers: {
0: { sorter: 'checkbox' }
}
})
// HEADER CELL Checkbox - toggles state of visible checkboxes
// make sure to include the "parser-input-select.js" file
// it contains the most up-to-date checkbox parser
.on('change', 'thead input[type="checkbox"]', function(){
var checkboxColumn = 0,
onlyVisible = true,
$this = $(this),
isChecked = this.checked;
$table
.children('tbody')
.children( 'tr' + ( onlyVisible ? ':visible' : '' ) )
.children(':nth-child(' + ( checkboxColumn + 1 ) + ')')
.find('input')
.prop('checked', isChecked)
.trigger('update');
});
});
Make sure to modify the checkboxColumn & onlyVisible variables as desired.
Update: There was an error in the parser code that was just fixed, it is currently available in the master branch only (linked in my answer). Otherwise you could just enter unchecked or checked" (checked with a quote for an exact match) to filter the checkboxes.
These filter names (checkbox states) are set by the group_checkbox option, which I just added to my answer.

Related

Angular FormControl's material-checkboxes.component has selected values but this.controlValue is an empty array

I have an Angular form I've built that consists of a single material-checkboxes component. I have two copies of this component, one is static and one is dynamic. The only difference is that the dynamic version gets its control values from an API call. Both of these examples have one or more options defaulted as checked when the controls initialize.
The issue I have is that the dynamic one's model is out of sync with its view as long as its left unchanged (ie, if I don't click on any of the checkbox controls to select or unselect them). Once I click on one of the checkboxes, the model updates to sync with the view.
I can tell this because I can submit the static version and get expected results (the defaulted items are posted as values as expected). However, when I submit the dynamic one, I get an empty post.
Here is what the component looks like with the defaulted values before I submit it to see the submitted form data:
And here is the resulted submitted values (as expected):
By way of comparison, here is the same control (material-checkboxes.component.ts) but built using an external datasource to feed in the titleMap and also has defaulted values.
And here is the result after submit of the above form:
So, as the screencaps indicate, The manually created one works as expected and submits the form containing the defaulted values. However, the component with the dynamically generated values, even though the view shows it to have selected default options, submits as EMPTY.
Expected: this.controlValue = ['12', 'd4']
Actual:
onInit > this.controlValue = ['12', 'd4']
After updateValue method > this.controlValue = undefined // But the view is unchanged from the init
However, I can get it to submit data as expected, if I manually change any of the values, even if i set them exactly as they were defaulted. Its as if the form data is not being set until manually clicking on the options.
Here is a snippet from the template that holds the component:
<mat-checkbox
type="checkbox"
[class.mat-checkboxes-invalid]="showError && touched"
[class.mat-checkbox-readonly]="options?.readonly"
[checked]="allChecked"
[disabled]="(controlDisabled$ | async) || options?.readonly"
[color]="options?.color || 'primary'"
[indeterminate]="someChecked"
[name]="options?.name"
(focusout)="onFocusOut()"
(change)="updateAllValues($event)"
[required]="required"
[value]="controlValue">
Update: I found that the issue was that the form control's value is not updated before leaving the syncCurrentValues() method called just after the setTitleMap hostlistener. Adding a call to this.updateValue() in syncCurrentValues() resolves it and the model and view are back in sync. However, there is a problem, but first, here is the code that resolves the issue when there is a default value set in the this.options data:
#HostListener('document:setTitleMap', ['$event'])
setTitleMap(event: CustomEvent) {
if (event.detail.eventName === this.options.wruxDynamicHook && isRequester(this.componentId, event.detail.params)) {
this.checkboxList = buildTitleMap(event.detail.titleMap, this.options.enum, true, true, this.options.allowUnselect || false);
// Data coming in after ngInit. So if this is the first time the list is provided, then use the defaultValues from the options.
const value = this.setDefaultValueComplete ?
this.jsf.getFormControl(this)?.value || [] :
[].concat(this.options?.defaultValue || []);
this.syncCurrentValues(value);
// Set flag to true so we ignore future calls and not overwrite potential user edits
this.setDefaultValueComplete = true;
}
}
updateValue(event: any = {}) {
this.options.showErrors = true;
// this.jsf.updateArrayCheckboxList(this, this.options.readonly ? this.checkboxListInitValues : this.checkboxList);
this.jsf.updateArrayCheckboxList(this, this.checkboxList);
this.onCustomAction(this.checkboxList);
this.onCustomEvent(this.checkboxList);
this.jsf.forceUpdates();
if (this.jsf.mode === 'builder-properties') {
this.jsf.elementBlurred();
}
}
syncCurrentValues(newValues: Array<any>): void {
for (const checkboxItem of this.checkboxList) {
checkboxItem.checked = newValues.includes(checkboxItem.value);
}
this.updateValue(); // Fixed it. Otherwise, the checked items in titlemap never get synced to the model
}
The call to updateData() above fixes the issue in that case. However, when there are no default values in the options data and the checkbox data is loaded externally from an API call that executes after the ngOnInit has fired, I have the same issue. this.controlValue is empty after ngOnInit despite that the view has updated to show checked checkboxes. The model has made that happen through the setTitleMap() method but the controlValue still logs as an empty array.

ExtJS Issue with boolean data and grid column list filter as well as Ext.Data.Store

I am using ExtJS 6 (although from what I can tell it applies up to version 7.4 as well) and I have a grid with a booleancolumn xtype. For that boolean column I wanted to use the filter list option. Yes I know there is a boolean filter option however I don't like how it works using a radio button. I wanted to be able to select the Yes or No with checkboxes, however I found that only the option with true as the value worked. Here is my column config:
{
header: 'Active'
, dataIndex: 'inactive'
, xtype: 'booleancolumn'
, trueText: 'No'
, falseText: 'Yes'
, filter:{
type: 'list',
options: [[true,"No"],[false, "Yes"]]
}
}
This didn't work when excluding the 'options' property and letting it get the data from the store either by the way. After looking through the code I discovered that it takes the 'options' config and creates its own Ext.Data.Store using that as the data. See here as a simple example that can be run that will get the same issue:
var teststore = new Ext.data.Store({
fields: [
'id',
'text'
],
data: [[true,"No"],[false, "Yes"]]
});
The problem is that the 'false' boolean value is changed and is replaced with a dynamically created generic id. I discovered the issue lays in the constructor for 'Ext.data.Model' for the following line:
if (!(me.id = id = data[idProperty]) && id !== 0) {
If that line evaluates to true it will replace the id with the generated one. To fix this I just added ' && id !== false' to the end of the if statement and this fixed the issue.
I have not tested this fully, however the logic seems sound and it looks like the same type of issue occurred with the value of '0' hence the ' && id !==0'. Since we are directed here from the sencha forums I wanted to bring this up in case it helps someone.
Since my post already has the answer I will post a better way to do it other than directly changing the Ext code file (whether this is the proper way I may be wrong). Instead, you can create a new js file that will need to be included in your application (you can name it ext-overrides.js). In the new js file you need only type:
Ext.override(Ext.data.Model, {
constructor: function(data, session) {
.....
}
}
You would then copy the constructor function code from your version of the ExtJS code in where the '.....' is (if perchance the constructor function arguments are different you would have to update those as well) and just add the suggested change I made above in the 'question'. A search of the Extjs code for Ext.define('Ext.data.Model' should get you there easily and then just scroll to the constructor function.

MUI DataTables Search on hidden column

hello im using mui datatables (https://github.com/gregnb/mui-datatables) on my react app, i have trouble when i am trying to search on hidden column, my code below work just fine but when im trying to search city value (column default hidde) it return nothing meanwhile the text is shown on the column (address), theres two case here i am combining the column wrongly or i can use my recent code but with some search function tweak, please let me know how to make this work, thanks.
FWIW 6 months+ later, I just ran into something similar...
There's an example on how to do this in the examples folder that should work in unison with "display:false, viewColumns:false".
https://github.com/gregnb/mui-datatables/blob/master/examples/customize-search/index.js
MUIDataTable columns:
...
{
"name":"hiddenCity",
"options":{
"filter":false,
"sort":false,
"display":false,
"viewColumns":false
}
},
{
"name":"hiddenState",
"options":{
"filter":false,
"sort":false,
"display":false,
"viewColumns":false
}
},
...etc...
MUIDataTable options:
let options = {
...lots of options...,
// Search ALL columns, including hidden fields that use display:false, viewColumns:false...
customSearch: (searchQuery, currentRow, columns) => {
let isFound = false;
currentRow.forEach(col => {
if (col && col.toString().indexOf(searchQuery) >= 0) {
isFound = true;
}
});
return isFound;
},
...more options...
}
couple of days ago I found myself solving the same issue. As per 3.7.1 release, the search code relies in this conditional, that means, no matching for hidden or excluded columns. But hey, I came out with a simple solution:
If you provide a custom search function in the options object, you will be able to access hidden and excluded column for the matching. Of course, you need to provide a search function capable of matching text and objects. In this case I rely on the super-search library.
const options = {
customSearch: (searchText, row) =>
superSearch(searchText.toLowerCase(), { ...row }).numberOfMatches > 0
};
See an example in this sandbox I have just created:
https://codesandbox.io/s/muidatatables-example-custom-search-function-0pm9o?file=/index.js
That will override the embedded search function in MUI-datatables.

Ask to confirm when changing tabs in angular bootstrap

I have tabs with forms and I want ask the user to confirm or discard their changes when changing tabs. My current code works
<uib-tab heading="..." index="3" deselect="main.onDeselect($event)" ... >
this.onDeselect = function($event) {
if(...isDirty...) {
if($window.confirm("Do you want to discard?")) {
... discard (and go to new tab) ...
} else {
$event.preventDefault(); //stays on current tab
}
}
}
The problem is I want to change confirm to javascript dialog and I will get result in callback.
I planed to preventDefault() all and then switch manually, but I cannot figure out where to get new tab id.
Any solution is appreciated. Even if it is easier in other tab implementations.
I use AngularJS v1.4.7, ui-bootstrap-tpls-1.3.3.min.js
You can make use of $selectedIndex and the active property for that purpose. See this Plunk
One thing to be noted here is that when we manually change the active property, it again fires the deselect event which needed to be handled. Otherwise it seems to do what you wanted.
Edit
Indeed as noted in the comments, the deselect carries the HTML index rather than what is passed in in the tab index property. A workaround could be in this: Another Plunk. Here I'm pulling the actual index from the HTML index.
And a little research indicates that this issue might as well be fixed already with 3.0 bootstrap tpl See this.
I spent some time with different approaches and this one is stable for some time. What I do is to prevent deselect at the beginning and set the new tab in callback if confirmed to loose changes...
this.onDeselect = function($event, $selectedIndex) {
var me = this;
if(this.tabs.eventDirty || this.tabs.locationDirty || this.tabs.contractDirty) {
$event.preventDefault();
var alert = $mdDialog.confirm({
title: 'Upozornění',
textContent: 'Na záložce jsou neuložené změny. Přejete si tyto změny zrušit a přejít na novou záložku?',
ok: 'Přijít o změny',
cancel: 'Zůstat na záložce'
});
$mdDialog
.show( alert )
.then(function() {
$rootScope.$emit("discardChanges");
me.tabs.activeTab = $selectedIndex;
})
}
};

Extjs 4.0.7, Editor Grid - how to get updated cell value?

I need to get(retrieve) updated cell value in controller. (MVC)
So I tried this,
var modified = this.getItemGrid().getStore().getUpdatedRecords();
console.log(modified); // return [] empty array
var modified = this.getItemList_Store().getUpdatedRecords();
console.log(modified); // return [] empty array
but always it returns empty array even I updated some cell value.
anybody know what I am doing wrong?
Here is my part of view code,
Ext.define("App.view.orders.ItemList_view", {
extend: "Ext.grid.Panel",
alias: "widget.itemList_view",
plugins: [
Ext.create('Ext.grid.plugin.CellEditing', {
clicksToEdit: 1
})
],
initComponent: function () {
this.store = "ItemList_store";
this.columns = [
{
xtype: 'checkcolumn', text: "Ship", width: 50, dataIndex: "DR"
},
{ header: "test", width: 100, dataIndex: "test",
editor: {
xtype : 'textfield'
}
}
];
this.selModel = Ext.create("Ext.selection.CheckboxModel");
//this.selModel = Ext.create("Ext.selection.CellModel"); // It does not works either.
this.callParent(arguments);
},
.
.
.
Thank you!
[EDIT]
Thank you very much for your answer! I have some more question about editor grid.
Its much different from Ext3. so I'm very confusing now :(
Q1. How to collect edited record data (once click button)?
the event fired once the grid cell be changed.
but I want collect edited grid record once I click the 'Update edited cell' button, and I want to update all together at the once.
In Ext3, I did like this,
(button) click : function(){
var modified = mygridStore.getModifiedRecords();
var recordsToSend = [];
Ext.each(modified, function(record){
recordsToSend.push(record.data);
});
var grid = Ext.getCmp('grid');
grid.el.mask('Updating','x-mask-loading');
grid.stopEditing();
recordsToSend = Ext.encode(recordsToSend);
Ext.Ajax.request({
url : '/test/test',
params : {
data : recordsToSend
},
success : function(response){
grid.el.unmask();
alert(response.responseText);
mygridStore.commitChanges();
},
failure : function(response){
mygridStore.rejectChanges();
}
});
}
How can I change the code for Extjs4 ?
Q2. I don't know still how to find out for changed checkcolumn.
I tried this, but I does not work for checkcolumn (of cause I tested after change checkbox)
// grid coumn
{
xtype: 'checkcolumn', header: "My Check Column", width: 50, dataIndex: "CH"
}
-
// in control
'myGrid': {
validateedit: function (plugin, edit) {
console.log(edit);
},
checkchange: function (plugin, edit) {
console.log(edit);
console.log(edit.value);
}
}
Q3. When I click the cell to edit, the show some HTML tag in -_-;;
I really appreciate for your help. and thank you very much for your valuable time!
The editors (cell editors or row editors) do not commit their values to the store until you complete the edit - which means pressing ENTER or blurring the active cell editor by clicking elsewhere on the page, or clicking the save button on the row editor form .
If your purpose for reading the updated value in your editor is to perform some kind of validation I would suggest simply listening to the validateedit event in your grid's controller, as described here.
The second argument that this event passes to your handler contains a lot of data about the edit that you can then perform validation with. If the edit doesn't pass your validation you can return false from your handler and the value in the celleditor will revert to it's original value. The validateedit event gets fired from the editor grid itself so you would add an event handler in your controller for it like this:
Ext.define('MyApp.controller.MyController', {
init: function() {
this.control({
'mygridpanel': {
validateedit: function(plugin, edit) {
// silly validation function
if (edit.value != 'A Valid Value') {
return false;
}
},
},
});
},
});
But you should check out the link above to see all the different objects available in that second argument I named edit.
The validateedit event is fired right before the record is committed into the store - after the user has already clicked ENTER or blurred the editor, i.e., while the editor is closing.
If you are trying to get the celleditor's value before it starts to close, for some reason other than validation for example, you could get the active celleditor's value like this:
// myGrid is a reference to your Ext.grid.Panel instance
if (myGrid.editingPlugin.editing) {
var value = myGrid.editingPlugin.getActiveEditor().field.value
console.log('value: ' + value);
}
If there is no active editor then myGrid.editingPlugin.getActiveEditor().field would throw an error, that's why I wrapped a conditional around it.
One other point I should make, for validation in editor grids, I found that it is easiest to just put a validator config in the grid column's editor definition. That will give you all the handy validation CSS while the user is setting the field's value and alert him if there is a problem with the value before he tries to save it.
To get an idea of what I mean, try entering letters in the date column of this example. Mouse over the editor cell and you will get the error message.
EDIT
It seems I misunderstood you original question, I'll break down my answers to your questions above though,
Question 1
Once you have completed an edit (clicked ENTER or ), your call to mygridStore.getModifiedRecords() should be working fine because the record will have been committed to the store. I see that it was not working, I will cover that in a moment.
I should point out that ExtJS4 has a store.sync() method as covered here.
Instead of extracting the modified records from the store, encoding them, manually doing an ajax request to save them to the server and then manually committing them you can call this sync method and it will take care of all of these actions for you.
If you have different URLs to handle the different create, read, update, destroy operations fired off by your store's load and sync methods, you can use the store's proxy api config to map your URLs to these operations as covered here. Or you can set-up your server side controller to be able to differentiate between your store's load request (read operations default to HTTP GET) and it's sync requests (create, update and delete operations default as HTTP POST).
There could be many different ways to go about doing this on the server side, the way I usually do it is to have one SQL stored procedure for GET requests and one for POST requests for any given store. I include the store name as an extra param and then my server side controller runs the appropriate stored procedure based on whether it is a GET or a POST request.
Question 2
Cell editing doesn't support checkcolumn edits. You have to make a different handler to listen to changes on that, something like this:
checkchange: function (column, rowIndex, checked) {
var record = store.getAt(rowIndex),
state = checked ? 'checked' : 'unchecked'
console.log('The record:');
console.log(record)
console.log('Column: ' + column.dataIndex);
console.log('was just ' + state)
}
Your call to mygridStore.getModifiedRecords() should be able to pick up the check changes also however, they get committed to the grid's store right away after being checked. store.sync() would also pick up changes to checkcolumn.
Question 3
I can't completely tell what is causing that problem but it may be something strange going on with your validateedit event, your handler should be returning true or false.
As I said earlier, I misunderstood the reason you originally asked this question. I thought you were trying to do some kind of validation while an edit was in progress. Now I understand that you are trying to get all of the modified records from the store after all the editing is completed in order to save them to the database, I was thrown off because in ExtJS 4 a store is usually saved to the database with the sync method as I mentioned.
In other words, you don't need the validateedit event or checkchange event to get a list of modified records.
The actual problem you are having might be trouble with the store's getter methods (getModifiedRecords, getUpdatedRecords) in some 4.07 versions, take a look at this post and this one.
So with all that said, the best advice I can give you is 1) try out the stores sync method for saving modified data to the database and 2) upgrade to ExtJS 4.1, there were a lot of bugs that were straightened out between 4.07 and 4.1 which you should be able to take advantage of, I cut out about 75% of the overrides I was using to make things work when I switched over to 4.1.
EditedGrid.plugins[0].completeEdit();
This will make the active changes commit and call edit event also.
listeners: {
validateedit: function (editor, e) {
//console.log(editor);
var oldVal = editor.originalValue;
var newVal = editor.value;
}
}

Resources