$.fn.dataTableExt.aoFeatures.push change setting - javascript

I have below code
$.fn.dataTableExt.aoFeatures.push({
"fnInit": function (oSettings) {
oSettings.oScroll.sY = 5;
return { "oSettings": oSettings } ;
},
"cFeature": "T"
});
$.extend($.fn.dataTable.defaults, {
//"scrollY": 5,
"dom":"T"
});
I can see scrollY changed in function but no effect in datatable, How can overwrite the default setting using this function, since i have to put condition ono tableid,
otherwise I could have done below way which is working
$.extend($.fn.dataTable.defaults, {
"scrollY": 5,
});
I believe I am missing something on return statement which will override the things
fiddle reference

You code is not working for a few reasons. First, you are using an outdated API. $.fn.dataTableExt.aoFeatures.push is the old API used with $(...).dataTable(). By using $(...).DataTable() (note the capital "D") as you did in your fiddle, you are choosing to use the new API. (Read about converting code using the old API to use the new API here.) Using the current API is a great choice, but you then need to use $.fn.dataTable.ext.feature.push to set up your feature.
This works:
$.fn.dataTable.ext.feature.push({
"fnInit": function (settings) {
settings.oScroll.sY = 25;
},
"cFeature": "T"
});
However, the dom feature is intended to indicate the order of elements in the table. Using it to set style like scrollY is OK, but not exactly what they had in mind. The point being that if you are going to specify dom at all, you have to specify all the elements you want. In particular, you have to specify t for table or else the DataTable will not attach itself to the table at all. So you need to set up your table with something like this to trigger your scrollY "feature":
$(document).ready(function() {
var table = $('#example').DataTable({
"dom":"Tlftip"
});
Note that the order matters. The "T" has to come before the other elements that are affected by the changes made in the feature. "dom":"lftipT" will not have the desired effect.

Related

Creating .json file and storing data in javascript -- using vis.js

In my project I need to save the data to .txt or .xml or .json file. I could not find any answer from vis.js website/issues blog. It might be simple, do not know. Really helpful if anyone help me out with example code. Thank you so much in advance.
function saveData(data,callback) {
data.id = document.getElementById('node-id').value;
data.label = document.getElementById('node-label').value;
clearPopUp();
callback(data);
}
If I understand you correctly, you are looking for a way to save data and options of a graph. In my graph editor adaptation for TiddlyWiki Classic I use the following method to extract data (the full implementation can be found in the repo, see config.macros.graph.saveDataAndOptions, here's a simplified one):
config.macros.graph.saveDataAndOptions = function(network,newOptions) {
newOptions = newOptions || {};
// get nodes and edges
var nodes = network.body.data.nodes._data; // contains id, label, x,y, custom per-node options and doesn't contain options from options.nodes; presumably contains option values set when network was created, not current ones (it is so for x,y)
// no suitable getter unfortunately
var edges = network.body.data.edges._data; // map; for edges to/from? certain node use network.getConnectedNodes(id)
// network.body.data.edges._data is a hash of { id: , from: , to: }
// get node positions, options
var positions = network.getPositions(), // map
options = // get options stored previously
// merge newOptions into options
for(var nodeId in nodes) {
// nodes[nodeId].x is the initial value, positions[nodeId].x is the current one
if(positions[nodeId]) { // undefined for hidden
nodes[nodeId].x = positions[nodeId].x;
nodes[nodeId].y = positions[nodeId].y;
}
storedNode = copyObjectProperties(nodes[nodeId]);
storedNodes.push(storedNode);
}
//# do whatever you need with storedNodes, edges and options
// (pack them with JSON.stringify, store to a file etc)
};
However, while this works ok for storing data, this only helps to save options passed for storing explicitly which can be not very nice for some cases. I use this method in manipulation helpers and on dragEnd (network.on("dragEnd",this.saveToTiddlerAfterDragging), config.macros.graph.saveToTiddlerAfterDragging = function(stuff) { config.macros.graph.saveDataAndOptions(this,{ physics: false }); };). I haven't recieved any better suggestions, though.
If you need to get data and options reactively and setting such helper to handle certain edit events can't solve your problem, then I suggest wrapping nodes, edges and options as vis.DataSet and save those when needed. This is related too.
To answer the question about events/other ways to use such methods. Here's how I use them:
I save data after drag&drop moving of nodes, this is done using an event handler. Namely, I introduced
config.macros.graph.saveToTiddlerAfterDragging = function(stuff) {
config.macros.graph.saveDataAndOptions(this,{ physics: false });
};
(when drag&drop is used, physics should be switched off, otherwise coordinates won't be preserved anyway) and then I use
network.on("dragEnd",this.saveToTiddlerAfterDragging);
so that changes are saved.
As for saving after adding/editing a node/edge, I apply saving not by an event (although it's nice thinking, and you should try events of DataSet, since there's no special graph events for that). What I do is I add an elaborated hijack to the manipulation methods. Take a look at the source I've linked after the
var mSettings = options.manipulation;
line: for each manipulation method, like options.manipulation.addNode I hijack it so that its callback is hijacked to call config.macros.graph.saveDataAndOptions in the end. Here's a simplified version of what I'm doing:
var nonSaving_addNode = options.manipulation.addNode;
options.manipulation.addNode = function(data,callback) {
// hijack callback to add saving
arguments[1] = function() {
callback.apply(this,arguments); // preserve initial action
config.macros.graph.saveDataAndOptions(network); // add saving
};
nonSaving_addNode.apply(this,arguments);
}
The thing is, addNode is actually called when the add node button is clicked; though, I'm using a customized one to create a popup and apply changes once user is happy with the label they chose.

How to properly detect pages in DataTable?

I am using DataTables.
What I am trying to do is: by using one of the columns values, get page number, where this value is located.
I have tried this: jumpToData()
BUT this didn't work out. The reason is that
var pos = this.column(column, { order: 'current' }).data().indexOf(data);
in jQuery.fn.dataTable.Api.register('page.jumpToData()' returns value >=0 ONLY if I was placed on page where value was.
For example, I want to detect page where needed value is, but I am staying on another page, so to detect value on... page 3, I need to go to this page and only then I can detect it, which makes no sence at all.
What I need to do, is: by staying on pirst page, using value from another pages, detect those pages numbers and then navigate to them:
$('#Grid_grid').DataTable().page(PageNumber).draw(false);
How can I accomplish that?
EDIT:
Got some idea (several changes in jumpToData()):
jQuery.fn.dataTable.Api.register('page.jumpToData()', function (data, column) {
for (var i = 0; i < this.page.info().pages; i++) {
var test = this.page(i).column(column, { order: 'current' }).data().indexOf(data);
if (test >= 0) {
this.page(i).draw(false);
return this;
}
}
return this;
});
(EDIT 2: idea didn't paid off, no difference)
BUT now I got second issue:
None methods of datatable works in .cshtml page.
For example I need to get overall page count. I doing this:
$('#Grid_grid').DataTable().page.info().pages;
and this return me 0;
Meanwhile, putting it in to console (Chrome F12) works fine (returns 5). Whats the matter?
EDIT 3:
Came up with this:
function LoadPage(value) {
var table = $('#Grid_grid').DataTable();
var pageNumber = table.search(value).page();
table.page(pageNumber).draw(false);
}
Looks promising BUT, I still cant validate it because in console DataTable methods are working, but in .cshtml no. (search() or page() returns nothing).
EDIT 4:
Moved issue to another question
CAUSE
Your new API method page.jumpToData() tries to query all pages data because second argument selector-modifier in column() API method has property page: 'all' by default. As written it will always stay on first page.
SOLUTION
There is original page.jumpToData() plug-in posted by Allan Jardine, creator of DataTables. It works as intended and can be used instead of your modification to avoid unnecessary iterations.
$.fn.dataTable.Api.register('page.jumpToData()', function (data, column) {
var pos = this.column(column, {
order: 'current'
}).data().indexOf(data);
if (pos >= 0) {
var page = Math.floor(pos / this.page.info().length);
this.page(page).draw(false);
}
return this;
});
DEMO
See this jsFiddle for code and demonstration.
NOTES
In the demo above I added console.log("Number of pages", table.page.info().pages); just to demonstrate that API method works. However they may work because I have HTML-sourced data.
If you have Ajax-sourced data, you need to query number of pages only when data has been loaded. Use initComplete option to define a callback function that will be called when your table has fully been initialised, data loaded and drawn.

Programmatically set the value of a Select2 ajax

I have a Select2 auto-complete input (built via SonataAdmin), but cannot for the life of me figure out how to programmatically set it to a known key/value pair.
There's a JS Fiddle here that shows roughly what I have. What I want to know is what function I can attach to the button so that
the Select2 field shows the text "NEW VALUE" to the user, and
the Select2 field will submit a value of "1" when the form is sent to the server
I have tried all sorts of combinations of jQuery and Select2 data and val methods, called against various inputs on the page, but nothing seems to work... surely there's some way to do this?
-- Edit --
The accepted answer below is very useful, helps shed some light on the right way to initialise the selection and explains what initSelection is for.
Having said that, it seems that my biggest mistake here was the way I was trying to trigger the change.
I was using:
$(element).select2('data', newObject).trigger('change');
But this results in an empty add object inside select2's change event.
If, instead, you use:
$(element).select2('data', newObject, true);
then the code works as it should, with the newObject available in select2's change event and the values being set correctly.
I hope this extra information helps somebody else!
Note this was tested with version 4+
I was finally able to make progress after finding this discussion: https://groups.google.com/forum/#!topic/select2/TOh3T0yqYr4
The last comment notes a method that I was able to use successfully.
Example:
$("#selectelement").select2("trigger", "select", {
data: { id: "5" }
});
This seems to be enough information for it to match the ajax data, and set the value correctly. This helped immensely with Custom Data Adapters.
Note: For multi select, execute the above code for each item, like this :
// for each initially selected ids, execute the above code to add the id to the selection.
[{id: 5, text: 'op5'}, {id: 10, text: 'op10'}].forEach(option => {
$("#selectelement").select2("trigger", "select", {data: { id: option.id, text: option.text }});
})
Note: The Question and this Answer are for Select2 v3. Select2 v4 has a very different API than v3.
I think the problem is the initSelection function. Are you using that function to set the initial value? I know the Select2 documentation makes it sound like that is it's purpose, but it also says "Essentially this is an id->object mapping function," and that is not how you have implemented it.
For some reason the call to .trigger('change') causes the initSelection function to get called, which changes the selected value back to "ENABLED_FROM_JS".
Try getting rid of the initSelection function and instead set the initial value using:
autocompleteInput.select2('data', {id:103, label:'ENABLED_FROM_JS'});
jsfiddle
Note: The OP has supplied the formatResult and formatSelection options. As supplied, those callback functions expect the items to have a "label" property, rather than a "text" property. For most users, it should be:
autocompleteInput.select2('data', {id:103, text:'ENABLED_FROM_JS'});
More info on the initSelection function:
If you search through the Select2 documentation for "initSelection", you will see that it is used when the element has an initial value and when the element's .val() function is called. That is because those values consist of only an id and Select2 needs the entire data object (partly so it can display the correct label).
If the Select2 control was displaying a static list, the initSelection function would be easy to write (and it seems like Select2 could supply it for you). In that case, the initSelection function would just have to look up the id in the data list and return the corresponding data object. (I say "return" here, but it doesn't really return the data object; it passes it to a callback function.)
In your case, you probably don't need to supply the initSelection function since your element does not have an initial value (in the html) and you are not going to call its .val() method. Just keep using the .select2('data', ...) method to set values programmatically.
If you were to supply an initSelection function for an autocomplete (that uses ajax), it would probably need to make an ajax call to build the data object.
To set initial values you need to add the necessary options tag to the select element with jQuery, then define these options as selected with select2's val method and finally trigger select2's 'change' event.
1.-$('#selectElement').append('<option value=someID>optionText</option>');
2.-$('#selectElement').select2('val', someID, true);
The third boolean argument tells select2 to trigger the change event.
For more info, see https://github.com/select2/select2/issues/3057
Be carreful, there is a mistake in "validated" comment.
autocompleteInput.select2('data', {id:103, label:'ENABLED_FROM_JS'});
The correct way is
autocompleteInput.select2('data', {id:103, text:'ENABLED_FROM_JS'});
Use text instead of label
With Select2 version 4+, there is actually nothing special you need to do. Standard jQuery with a 'change' event trigger at the end will work.
var $select = $("#field");
var items = {id: 1, text: "Name"}; // From AJAX etc
var data = $select.val() || []; // If you want to merge with existing
$(items).each(function () {
if(!$select.find("option[value='" + this.id + "']").length) {
$select.append(new Option(this.text, this.id, true, true));
}
data.push(this.id);
});
$select.val(data).trigger('change'); // Standard event notifies select2
There is a basic example in the Select2 documentation:
https://select2.org/programmatic-control/add-select-clear-items
from their examples
https://select2.github.io/examples.html
Programmatic access:
var $example = $(".js-example-programmatic").select2();
var $exampleMulti = $(".js-example-programmatic-multi").select2();
$(".js-programmatic-set-val").on("click", function () { $example.val("CA").trigger("change"); });
$(".js-programmatic-open").on("click", function () { $example.select2("open"); });
$(".js-programmatic-close").on("click", function () { $example.select2("close"); });
$(".js-programmatic-init").on("click", function () { $example.select2(); });
$(".js-programmatic-destroy").on("click", function () { $example.select2("destroy"); });
$(".js-programmatic-multi-set-val").on("click", function () { $exampleMulti.val(["CA", "AL"]).trigger("change"); });
$(".js-programmatic-multi-clear").on("click", function () { $exampleMulti.val(null).trigger("change"); });
All you have to do is set the value and then execute: $ ('#myselect').select2 (); or $ ('select').select2 ();.
And everything is updated very well.
If you remove the .trigger('change') from your fiddle it logs Object {id: 1, label: "NEW VALUE"} (need to click twice since the logging is before the value change). Is that what you're looking for?
When using select2 with multiple option, use this construction:
$(element).select2("data", $(element).select2("data").concat(newObject), true);
jqueryselect2multiplesetconcatenation
this is it:
$("#tag").select2('data', { id:8, title: "Hello!"});
FOR VERSION 3.5.3
$(".select2").select2('data',{id:taskid,text:taskname}).trigger('change');
Based on John S' answer . Just the the above will work however only if while initializing the select2 the initSelection option is not initialized.
$(".select2").select2({
//some setup
})
For those still using version 3.5 or even higher ones. Please be sure how you reference select2.js to your page. If you are using async or defer load. This plug-in might behave differently.
Thought to mention.
In my situation I was able to render the preselected option into the HTML server side with PHP.
During my page load, I already knew the option value, so my <select name="team_search"></select> became the following;
<select name="team_search">
<?php echo !empty($preselected_team)
? '<option selected="selected" value="'. $preselected_team->ID .'">' . $preselected_team->team_name . '</option>'
: null ?>
</select>';
As you can see, when I have a $preselected_team available I render in an option with the selected attribute, value and label set. And, if I don't have a value then not option is rendered.
This approach may not always be possible (and in the case of the OP is not mentioned), but it does come with the added benefit of being ready on page load ahead of JavaScript execution.
Append a new option with id and text
let $newOption = $("<option selected='selected'></option>").val(1).text('New Text goes here');
$("#selector").append($newOption).trigger('change');

misleading jqgrid documentation : Client side sorting, but server side paging

this question has already been answered multiple times. but here I want to site that if the code provided in the documentation can't be achieved without additional codes, why it has been given there in first place. Its simply misleading. The code given in the documentation achieves paging, but while sorting, the grid data simply disappears.
Correct me if I am wrong.
jQuery("#gridid").jqGrid({
...
datatype: 'json', // can be xml
loadComplete : function () {
jQuery("#gridid").jqGrid('setGridParam',{datatype:'local'});
},
onPaging : function(which_button) {
jQuery("#gridid").jqGrid('setGridParam',{datatype:'json'});
},
...
});
You don't posted the exact reference to the documentation where you get the code. I found it here.
jqGrid is open source product which you get for free. It's practical, but you should understand, that in the case the product and its documentation could not be perfect. The part of code which you referenced could work probably in some very old version of jqGrid, but it's wrong code in the current version of jqGrid. The sense of implementing "Client side sorting, but server side paging" is very suspected at all. My old answer about the subject you would find here. I would rewrite some part of the answer now, but in general the code tested with old versions could be not full compatible with the new version of jqGrid.
I can say there is no place where intentional misleading has happened. They are giving the pluging for free though it is a very huge plugin. And the work done by people like Oleg is making it more perfect. For you question, the code related to "client side sorting and server side paging" here is the code that can solve your problems. And this was taken with the help of some old answer given by Oleg.
This is my version of code,
loadComplete: function(data) {
var $this = $(this);
if ($this.jqGrid('getGridParam', 'datatype') === 'json') {
// because one use repeatitems: false option and uses no
// jsonmap in the colModel the setting of data parameter
// is very easy. We can set data parameter to data.rows:
$this.jqGrid('setGridParam', {
datatype: 'local',
data: data.userdata,
pageServer: data.page,
recordsServer: data.records,
lastpageServer: data.total
});
// because we changed the value of the data parameter
// we need update internal _index parameter:
this.refreshIndex();
if ($this.jqGrid('getGridParam', 'sortname') !== '') {
// we need reload grid only if we use sortname parameter,
// but the server return unsorted data
$this.triggerHandler('reloadGrid');
}
} else {
$this.jqGrid('setGridParam', {
page: $this.jqGrid('getGridParam', 'pageServer'),
records: $this.jqGrid('getGridParam', 'recordsServer'),
lastpage: $this.jqGrid('getGridParam', 'lastpageServer')
});
this.updatepager(false, true);}
}
onPaging:function(){
/*this code is to fix the issue when we click on next page with some data in filter tool bar
* along with this in grid definition( in filterToolbar ) we have to return true in "beforeClear "event
* */
var data = $(this).jqGrid("getGridParam", "postData");
data._search = false;
data.filters=null;
data.page=$(this).jqGrid("getGridParam","page");
/* comment this line if you disable filter toolbar*/
$(this)[0].clearToolbar();
//Here making _search alone false will not solve problem, we have to make search also false. like in below.
$(this).jqGrid('setGridParam', { search: false, postData:data });
var data = $(this).jqGrid("getGridParam", "postData");
/*this is to fix the issue when we go to last page(say there are only 3 records and page size is 5) and click
* on sorting the grid fetches previously loaded data (may be from its buffer) and displays 5 records
* where in i am expecting only 3 records to be sorted out.along with this there should be a modification in source code.
*/
$(this).jqGrid("clearGridData");
/* this is to make the grid to fetch data from server on page click*/
$(this).setGridParam({datatype: 'json'}).triggerHandler("reloadGrid");
}
For the modification that you have to do in source code is , see this answer..

Dojo DataGrid Virtual Scrolling How-To?

I've been digging around for this one quite a bit. I'm using dojox.grid.datagrid and I have an ajax call that brings back 200-300 rows.
The grid renders and scrolls just fine in Chrome but scrolling is excruciatingly slow in IE 7 and 8. I'd like to use virtual scrolling to try and remedy the issue but can't find any sample code.
Here's what my code looks like at present.
function setupAvailableScenes(location) {
var avaiableScenesGridPane = dijit.byId("AvaiableScenesGridPane");
var availableScenesGrid = dijit.byId("AvailableScenesGrid");
if (_isFirstLoad) {
availableScenesGrid = new dojox.grid.DataGrid({
id: 'AvailableScenesGrid',
store: availableScenesStore,
query: { Id: "*" },
sortInfo: "1",
rowsPerPage: 20,
autoHeight:20,
style: "width:315px",
structure: [
{ name: "Available Scenes", field: "Name", width: "85%" },
{ name: " ",
field: "_item",
rowsPerPage: "25",
type: dojox.grid.cells._Widget,
editable: false,
width: "15%",
formatter: function (scene) {
return new dijit.form.Button(
{
label: "+",
onClick: function () {
AddSceneToSelectedScenes(scene);
}
})
}
}
]
});
avaiableScenesGridPane.set('content', availableScenesGrid);
}
var availableScenesStore = new dojo.data.ItemFileWriteStore({
url: _applicationPath + "/Location/" + location.Id + "/Scene.json",
preventUrlCache: true
});
availableScenesGrid.setStore(availableScenesStore);
}
Often one of the biggest things you can do to improve DataGrid performance is to throw away the ItemFileReadStore/WriteStore and use an optimized data store (personally I like QueryReadStore). It would mean needing a server-side servlet of some kind (PHP/JSP/etc) to handle the virtual scrolling/pagination, but I've seen major perf boosts over just using a store backed by a JSON file.
Some other things to consider, which may or may not help:
give your anonymous formatter function a name and try scrolling the table with the Chrome or Firebug profiles turned on to see if it's hogging a lot of cycles (or, like Vijay Agrawal said, you could try replacing the dijit.form.Button with a vanilla html <button> tag)
you shouldn't actually need to specify the dojox.grid.cells._Widget type for that cell; having a custom formatter returning a valid Dijit should be sufficient to make the Grid do the right thing.
Since you specified rowsPerPage=25, it is already doing virtual scrolling (it pulls the new set of rows only when user scrolls down)
Since you mention scrolling is very slow, the performance issue seems to be around rendering the new rows - you may try a couple things to improve performance:
1) remove autoHeight attribute. Instead, specify a fixed height in the style attribute
2) in the formatter function, instead of returning a dijit, try returning a simple html button/anchor styled as button
so remove the type:dojox.grid.cells._Widget attribute and in the format function return the html you want to use

Categories