I am using data tables to display a list of events of different types. Besides the default global text search I need to
1. filter list by event type
2. filter list by date range (show only today -> infinity)
3. Save the state of the table for the the current session.
The state saves as expected except for the date range search which is always reset. Am I missing something or custom search functions are out of the scope of state saving? Here's the relevant code in jQuery:
Fist I add my own search function through the provided method. This works except it's state is not saved
// Extend search()
var threshold_timestamp = xxxxxxxxxxxx // set for beginning of today)
$.fn.dataTable.ext.search.push(
function( settings, data, dataIndex) {
var timestamp = parseInt(data[1]); // event date timestamp
if (timestamp > threshold_timestamp) {
return true;
}
return false;
}
);
Then I add a listeners for the select used to switch between the event type options ('','Event','Sports','Dance'...) and the button user to turn on/off the date range filter
$('#filter-by-type').on('change', function() {
table.columns(0).search( $(this).val() ).draw();
});
$('#dt-history').on('click', function() {
// Logic to toggle threshold_timestamp between 0 or value
table.draw();
});
Then I call DataTables
var table = $('#example').DataTable( {
ajax: "datasource.json",
stateSave : true,
stateDuration: -1,
columns: [
{ data: "type"}, //str as 'Sport','Dance'
{ data: "date"} // int as 1528572000
]
});
I managed to scratch my head sideways and "save the date search" using localstorage but that is a hack. On page load I trigger a button click to execute the search so initially the tables seems empty, the "No data available in table" message appears and then the filtered results display. As a second hack I will suppress that message so when there will really be no data... there will be no message :(
Related
While creating a Vue.js application I have become stuck at a weird problem. I want to be able to manipulate an input field (think increment and decrement buttons and erasing a zero value on focus, so the user doesn't have to) and up until a user writes to the input field, everything is fine. After that, however, further changes in the data are no longer represented in the input field.
As I was sure I could not be the only one with this particular problem, I searched extensively, but had no luck. What baffles me the most is that everything works until the field is written to, since I can not really imagine why this would remove the data binding.
The following code should show the same behavior. It is an input field component, which is initialized with a zero value. On focus the zero gets removed. This works, until a user manually writes to the field after which zero values will no longer be removed, even though the focus method fires, the if-condition is met and the data in the amount-variable is changed.
Vue.component('item', {
data: function () {
return {
amount: 0
}
},
render: function (createElement) {
var self = this;
return createElement('input', {
attrs: {
//bind data to field
value: self.amount,
type: 'number'
},
on: {
//update data on input
input: function (event) {
self.amount = event.target.value;
},
//remove a zero value on focus for user convenience
focus: function (event) {
if (self.amount == 0 || self.amount == "0") {
self.amount = '';
}
}
}
})
}
})
I think you need to use domProps instead of attrs to make it reactive. But I would suggest you use vue's template syntax or if you insist on using the render function I would also suggest you to use JSX.
I am new to the jQuery dataTables plugin found on https://datatables.net/
I am trying to implement a custom filter for the table:
Basically, when I click a button, a custom filtering function will test the value of column #1 (numeric value) for all rows, and if the value in the column < 50 for a row, the row stays, otherwise the row is hidden.
The concept should be very simple, but I can't seem to find the right way to use the API:
column.filter() returns an array of column value
column.search() can only accept text data (not function)
What's the API that can achieve the effect?
Is there anything like the following?
var api = $('#table').DataTable();
api.column(1).data().somefilterfunction(function (val, ind) {
return parseFloat(val) < 50;
}).draw();
Have you seen this article in the documentation -> https://datatables.net/examples/plug-ins/range_filtering.html ??
You can create a custom filtering function on-the-fly, triggered by a button :
<button id="filter">filter < 50</button>
script :
$("#filter").click(function() {
$.fn.dataTable.ext.search.push(
function( settings, data, dataIndex ) {
return parseFloat(data[0])<50
? true
: false
}
);
table.draw();
$.fn.dataTable.ext.search.pop();
});
demo -> http://jsfiddle.net/dpwgqs2o/
Notice that the filter is created inside the click handler itself, and removed again as soon the table is drawn. This makes the filter temporary, i.e when the user click on a column header, the filter is cleared. If you want a permanent filter, make the filter global and do not remove it.
In my app I have to add Search field and some select fields.
when I add any character in search field corresponding content from store should be display.
Currently I am using search field on which I am handling keyup event.
Please let me know the flow and guide line to do this.
Thanks
I suppose you want a search feature for your search field..showing the results as you type. You can achieve this by using regular expressions and compare them with entries in the store.
Here's the code I used on a project:
//referencing my searchfield
Search: '#searchfield';
//attaching an event
Search: {
keyup: "OnFocus"
}
//the actual function
OnFocus: function (searchField, e) {
var query = searchField.getValue(); //get the value entered in the search field
var ContactsContainer = this.getContactsContainer(); //the container that holds my contacts
var store = Ext.getStore('Contacts'); // the store where I have the info
store.clearFilter(); //assure there aren't any filters set
if (query) { //if the current value in the search field
var thisRegEx = new RegExp(query, 'i'); //new regular expression with our value
store.filterBy(function (record) { //filter the store
if (thisRegEx.test(record.get('name')) //the fields in the store
thisRegEx.test(record.get('surname'))
thisRegEx.test(record.get('phone'))) {
return true; //must include this
};
return false;
});
}
Good Luck!
Environment: Dojo.1.8.4
If the DateTextBox does not contain a valid date, I wish to start the calendar popup at a date in the past (it's a date of birth entry box). What is the best way of achieving this?
<div maxlength="12"
data-dojo-type="dijit/form/DateTextBox"
data-dojo-props="required: true, constraints:{min:'1880-01-01',
max: new Date()}, popupClass: 'dojox.widget.Calendar'">
</div>
I want to be able to put a 'startDate' parameter or similar in the above such that the constructor for the popup will pick it up and use it.
It looks as though the dojox.widget._CalendarBase sets the date to the current date in its constructor. (actually seems to set it in both the constructor and the declaration).
NOTE: If you are using the dijit/Calendar dropdown default then use the dropDownDefaultValue property as #vogomatix says in the other answer.
The following is if you are using the dojox/widget/Calendar for the dropdown.
By default the popup is set to the current value of the textbox and if null, it will use the current date.
You can do
1) set the value of the text box to what you want the default to be
OR
2) use aspects to set the value in the calendar when it is opened.
require([
'dojo/dom',
'dojo/aspect',
'dijit/form/DateTextBox',
'dojox/widget/Calendar'
], function(dom, aspect, DateTextBox, Calendar){
var dt = new DateTextBox({ popupClass: Calendar }, dom.byId('dtText'));
aspect.after(dt, 'openDropDown', function() {
// only default if there is no value
if(dt.get('value') == null) {
// Do not set the text box when changing value,
// so temporarily override the onchange function
var oldOnChange = dt.dropDown.onChange;
dt.dropDown.onChange = function(){};
dt.dropDown.set('value', new Date(1980, 7, 4)); // default to August 4th, 1980
dt.dropDown.onChange = oldOnChange;
}
});
});
See it in action:
http://jsfiddle.net/cswing/kQYhQ/
One solution is to set dropDownDefaultValue, which works with the standard calendar.
var dt = new DateTextBox({dropDownDefaultValue: new Date( 1950,1,1)},
dom.byId('dtText'));
dropDownDefaultValue gets passed to the calender in the form of currentFocus by the popup. Unfortunately dojox.widget.Calendar does not recognise currentFocus and the way round that is to either extend the class to do so, or to use the aspect method above.
This is how to extend the dojox.widget.Calendar in order to accept the currentFocus passed by the popup. Like the aspect method above, it temporarily disables onChange in order to prevent the value being placed in the parent DateTextBox
define([
"dojo/_base/declare",
"dojox/widget/Calendar"
], function(declare, calendar){
return declare("my.dijit.Calendar", [calendar], {
postCreate: function() {
this.inherited(arguments);
var oldOnChange = this.onChange;
this.onChange = function(){};
this.set('value', this.parseInitialValue( this.currentFocus));
this.onChange = oldOnChange;
}
});
});
Is there a simpler list type than DataGrid that can be connected to a store for Dojo?
I would like the data abstraction of the store, but I don't need the header and cell stucture. I would like to be more flexible in the representation of the datalines, where maybe each line calls an function to get laid out...
You ask a really good question. I actually have a blog post that is still in draft form called "The DataGrid should not be your first option".
I have done a couple thing using the store to display data from a store in a repeated form.
I have manually built an html table using dom-construct and for each.
var table = dojo.create('table', {}, parentNode);
var tbody = dojo.create('tbody', {}, table); // a version of IE needs this or it won't render the table
store.fetch({ // this is a dojo.data.ItemFileReadStore, but you cana dapt to the dojo.Store API
query: {},
onComplete: function(itms) {
dojo.forEach(itms, function(itm, idx) {
var tr = dojo.create('tr', {}, tbody);
// use idx to set odd/even css class
// create tds and the data that goes in them
});
}
});
I have also created a repeater, where I have an html template in a string form and use that to instantiate html for each row.
var htmlTemplate = '<div>${name}</div>'; // assumes name is in the data item
store.fetch({ // this is a dojo.data.ItemFileReadStore, but you cana dapt to the dojo.Store API
query: {},
onComplete: function(itms) {
dojo.forEach(itms, function(itm, idx) {
var expandedHtml = dojo.replace(htmlTemplate, itm);
// use dojo.place to put the html where you want it
});
}
});
You could also have a widget that you instantiate for each item.