I have multiple grids in a panel. The base grids have data in them and can be dragged and dropped between each other. All the grids in the panel should be able to drag and drop between each other. This works perfectly in chrome but not Firefox, IE, or Safari.
In IE,FF and Safari the grids with data in them will drag and drop between each other w/o problem. They will not between the empty grids. I tried adding data to the empty grids but that wasn't the problem. Firebug also errors when using it with Extjs so any bugs i get are from a different dev tool. I have reinstalled all of those browsers and that is not the answer either. Im stuck...
edit I found out in chrome the viewconfig for my dragdrop groups are set but it doesnt set in the other browsers
This is my base grid with data in it.
var rround = "panel-game-"+round;
var ss = Ext.create('Ext.grid.Panel', {
stateful: true,
id: "panel-game-"+round,
stateId: 'stateGrid',
autoScroll: false,
store: store,
columns: [
{
text : 'Teams',
flex : 1,
sortable : true,
dataIndex: 'team_name'
}
],
height: 100,
width: 150,
title: 'Game ' + round,
viewConfig: {
stripeRows: true,
plugins: {
ptype: 'gridviewdragdrop',
dragGroup: [groups],
dropGroup: [groups]
},
listeners: {
drop: function(node, data, dropRec, dropPosition,record,store) {
var dropOn = dropRec ? ' ' + dropPosition + ' ' + dropRec.get('name') : ' on empty view';
var data = this.store.data.items;
var sdata = new Array();
data.each(function(e){
var bleh = {team_id: e.data.team_id, team_name:e.data.team_name};
sdata.push(bleh);
})
removeDupe(sdata,this.store);
}
}
}
});
This is my empty grid that should accept drops and should also drag when there is data in it.
var rCell = Ext.create('Ext.grid.Panel', {
stateful: true,
id: "panel-game-"+i+'-'+a,
stateId: 'stateGrid',
autoScroll: false,
store: rCellStore,
columns: [
{
text : 'Teams',
flex : 1,
sortable : true,
dataIndex: 'team_name'
}
],
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragGroup: [groups],
dropGroup: [groups]
},
listeners: {
beforedrop: function(node,data,overModel,dropPosition,eOpts){
console.log(node);
},
drop: function(node, data, dropRec, dropPosition, record) {
console.log("drop");
var dropOn = dropRec ? ' ' + dropPosition + ' ' + dropRec.get('title') : ' on empty view';
var f = node.id.replace('-body','');
var newval = data.records[0].data;
if(f != undefined && f != ''){
var fstore = Ext.getCmp(f).getStore();
fstore.add(newval);
}
var data = this.store.data.items;
var sdata = new Array();
data.each(function(e){
var bleh = {team_id: e.data.team_id, team_name:e.data.team_name};
sdata.push(bleh);
})
removeDupe(sdata,this.store);
}
}
},
height: 100,
width: 150,
title: 'Game ',
viewConfig: {
stripeRows: true
}
});
It does not give a dropzone avaliable when i and trying to drag something over. It could be that but im not sure how to fix it.
The problem was the second viewConfig{stripeRows:true}. Chrome could figure it out but the other browsers were overwriting the first viewConfig with the second.
Related
I have a problem when i am trying to generate the Base64 of my chartjs line.
The console.log of my base64 string is : "data:," (attachment)
i am launching this code in an iframe, not in the parent page. On this chart, there are 30000 lines of data.
**When i directly launched the page, i have no problem, everything is OK.
**
Here is my code :
`
function generateTrend2(data){
var line = document.getElementById('chartContainer').getContext('2d')
var dataY = []
var dataX = []
data.forEach(function (item) {
dataY.push(item.y)
dataX.push(item.x)
})
var lineChart = new Chart(line, {
type: 'line',
data: {
labels: dataX,
datasets: [{
data: dataY,
label: "Sample Coverage",
borderColor: "#3e95cd",
fill: false,
borderWidth: 1
}]
},
options: {
animation: {
duration: 0,
},
hover: {
animationDuration: 0,
},
responsiveAnimationDuration: 0,
onAnimationComplete: done(),
elements: {
point:{
radius: 0
}
}
}
});
function done(){
setTimeout(function(){
var image = lineChart.toBase64Image();
console.log(image)
$("body").append("<input type='hidden' value='" + image + "' id='img-chart' >")
},1000)
}
}
`
I tried to put a delay of 200,500,1000,5000,10000, but the result is the same in my var image...
I have generated an other base64 with an other chart with similar code, the same system, in an iframe and i have no problem.
I made a Highstock diagramm and got aproblem with zooming on the yAxis.
I have a Button and 2 textfield to get the wanted min/max values for the axis. With min:0, max: 100 it works well. With min:0, max:80 it doesn't (max will still be 100 in the Diagramm).
If I use the mouse for zooming it works well (even a min of: 3.7 and a max of 3.894 is possible). But using the mouse is not an Option, because in the later Diagramm there will be 3 yAxes with individual zoom.
$(function () {
var seriesOptions = [],
seriesCounter = 0,
names = ['MSFT', 'AAPL', 'GOOG'];
/**
* Create the chart when all data is loaded
* #returns {undefined}
*/
function createChart() {
$('#container').highcharts('StockChart', {
rangeSelector: {
selected: 4
},
chart:{
zoomType: 'xy'
},
yAxis: [
{
labels: {
format: '{value}',
},
height: '100%',
opposite: false,
plotLines: [{
value: 0,
width: 2,
color: 'silver'
}]
},
],
plotOptions: {
series: {
compare: 'percent'
}
},
tooltip: {
pointFormat: '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> ({point.change}%)<br/>',
valueDecimals: 2
},
series: seriesOptions
},
function(chart){
$('#btn').click(function(){
var min = temp_min.value,
max = temp_max.value;
chart.yAxis[0].setExtremes((min),(max));
});
});
}
$.each(names, function (i, name) {
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=' + name.toLowerCase() + '-c.json&callback=?', function (data) {
if(seriesCounter==0){
seriesOptions[i] = {
name: name,
data: data,
yAxis: 0
};
} else {
seriesOptions[i] = {
name: name,
data: data,
yAxis: 0
};
}
// As we're loading the data asynchronously, we don't know what order it will arrive. So
// we keep a counter and create the chart when all the data is loaded.
seriesCounter += 1;
if (seriesCounter === names.length) {
createChart();
}
});
});
});
JSFiddle
Another Question: Is it possible to set up a scrollbar for the yAxis as well?
Thanks for your help, Patrick
This is related with fact that tickInterval is not regular, so is rounded to value (like 100). The solution is using tickPositioner which calculates ticks, based on extremes which you define.
tickPositioner: function (min,max) {
var positions = [],
tick = Math.floor(min),
increment = Math.ceil((max - min) / 5);
for (tick; tick - increment <= max; tick += increment) {
positions.push(tick);
}
return positions;
},
http://jsfiddle.net/6s11kcwd/
The scrollbar is supported only for xAxis.
I'm working with a Kendo treelist widget, and disappointed to see there's no rowTemplate option as there is on the Kendo grid.
I see a columnTemplate option (i.e. http://docs.telerik.com/kendo-ui/api/javascript/ui/treelist#configuration-columns.template ), but this will affect the entire column.
However, I need to drill into each cell value and set a css color property based on a ratio ( i.e. If value/benchmark < .2, assign <span style='color:red;'> , but my color value is dynamic.
There's a dataBound: and dataBinding: event on the treelist, but I'm still trying to figure out how to intercept each cell value and set the color once I've done my calculation.
var treeOptions = {
dataSource: ds,
columns: colDefs,
selectable: true,
scrollable: true,
resizable: true,
reorderable: true,
height: 320,
change: function (e) {
// push selected dataItem
var selectedRow = this.select();
var row = this.dataItem(selectedRow);
},
dataBound: function (e) {
console.log("dataBinding");
var ds = e.sender.dataSource.data();
var rows = e.sender.table.find("tr");
}
};
and this is where I'm building out the `colDefs' object (column definitions):
function parseHeatMapColumns(data, dimId) {
// Creates the Column Headers of the heatmap treelist.
// typeId=0 is 1st Dimension; typeId=1 is 2nd Dimension
var column = [];
column.push({
"field": "field0",
"title": "Dimension",
headerAttributes: { style: "font-weight:" + 'bold' + ";" },
attributes : { style: "font-weight: bold;" }
});
var colIdx = 1; // start at column 1 to build col headers for the 2nd dimension grouping
_.each(data, function (item) {
if (item.typeId == dimId) {
// Dimension values are duplicated, so push unique values (i.e. trade types may have dupes, whereas a BkgLocation may not).
var found = _.find(column, { field0: item.field0 });
if (found == undefined) {
column.push({
field: "field2",
title: item.field0,
headerAttributes: {
style: "font-weight:" + 'bold'
}
,template: "<span style='color:red;'>#: field2 #</span>"
});
colIdx++;
}
}
});
return column;
}
**** UPDATE ****
In order to embed some logic within the template :
function configureHeatMapColumnDefs(jsonData, cols, model) {
var colDef = '';
var dimId = 0;
var colorProp;
var columns = kendoGridService.parseHeatMapColumns(jsonData, dimId);
// iterate columns and set color property; NB: columns[0] is the left-most "Dimension" column, so we start from i=1.
for (var i = 1; i <= columns.length-1; i++) {
columns[i]['template'] = function (data) {
var color = 'black';
if (data.field2 < 1000) {
color = 'red';
}
else if (data.field2 < 5000) {
color = 'green';
}
return "<span style='color:" + color + ";'>" + data.field2 + "</span>";
};
}
return columns;
}
Advice is appreciated.
Thanks,
Bob
In the databound event you can iterate through the rows. For each row you can get the dataItem associated with it using the dataitem() method (http://docs.telerik.com/kendo-ui/api/javascript/ui/treelist#methods-dataItem)
Once you have the dataitem, calculate your ration and if the row meets the criteria for color, change the cell DOM element:
dataBound: function (e) {
var that = e.sender;
var rows = e.sender.table.find("tr");
rows.each(function(idx, row){
var dataItem = that.dataItem(row);
var ageCell = $(row).find("td").eq(2);
if (dataItem.Age > 30) {
//mark in red
var ageText = ageCell.text();
ageCell.html('<span style="color:red;">' + ageText + '</span>');
}
}
DEMO
UPDATE: you can also do this with a template:
$("#treelist").kendoTreeList({
dataSource: dataSource,
height: 540,
selectable: true,
columns: [
{ field: "Position"},
{ field: "Name" },
{ field: "Age",
template: "# if ( data.Age > 30 ) { #<span style='color:red;'> #= data.Age # </span> #}else{# #= data.Age # #}#"
}
],
});
DEMO
#Oleg - I am new to jqGrid.I have three issues. Urgent help required.
I am using jqGrid 3.8, inline edit mode.
I want to retain the invalid cell values after the pop up for invalid cell.
Also I want to set the focus back to the invalid cell.
I have "add row" and filter tool bar feature in my jqGrid. I have used Oleg's solution in creating drop down for filter tool bar (posted in another jQuery thread).
**
- Problem:
** I am calling setSearchSelect from afterSaveCell, because I want to add new values in filter drop down every time I add or delete column.(Note: column is a textbox). But the filter tool bar isn't getting refreshed even if I use
var sgrid = $("#list")[0];
sgrid.triggerToolbar();
See the code below for setting the toolbar.
<script type="text/javascript">
var mydata = [
{id:"1", Name:"Miroslav Klose", Category:"sport", Subcategory:"football"},
{id:"2", Name:"Michael Schumacher", Category:"sport", Subcategory:"formula 1"},
{id:"3", Name:"Albert Einstein", Category:"science", Subcategory:"physics"},
{id:"4", Name:"Blaise Pascal", Category:"science", Subcategory:"mathematics"}
],
grid = $("#list"),
getUniqueNames = function(columnName) {
var texts = grid.jqGrid('getCol',columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i=0;i<textsLength;i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
return uniqueTexts;
},
buildSearchSelect = function(uniqueNames) {
var values=":All";
$.each (uniqueNames, function() {
values += ";" + this + ":" + this;
});
return values;
},
setSearchSelect = function(columnName) {
grid.jqGrid('setColProp', columnName,
{
stype: 'select',
searchoptions: {
value:buildSearchSelect(getUniqueNames(columnName)),
sopt:['eq']
}
}
);
};
grid.jqGrid({
data: mydata,
datatype: 'local',
colModel: [
{ name:'Name', index:'Name', width:200 ,editable:true},
{ name:'Category', index:'Category', width:200,editable:true },
{ name:'Subcategory', index:'Subcategory', width:200,editable:true }
],
sortname: 'Name',
viewrecords: true,
rownumbers: true,
sortorder: "desc",
editurl: "clientArray",
multiselect: true,
pagination:true,
cellEdit: true,
cellsubmit: 'clientArray',
//ignoreCase: true,
pager: '#pager',
height: "auto",
enableSearch: true,
caption: "How to use filterToolbar better locally",
afterSaveCell: function(rowid,name,val,iRow,iCol) {
setSearchSelect(name);
jQuery("#list").('setColProp', name,
{
width:100
}
);
var sgrid = $("#list")[0];
sgrid.triggerToolbar();
alert(name);
},
loadComplete: function () {
setSearchSelect('Category');
}
}).jqGrid('navGrid','#pager',
{edit:false, add:false, del:false, search:false, refresh:true});
setSearchSelect('Category');
setSearchSelect('Subcategory');
grid.jqGrid('setColProp', 'Name',
{
searchoptions: {
sopt:['cn'],
dataInit: function(elem) {
$(elem).autocomplete({
source:getUniqueNames('Name'),
delay:0,
minLength:0
});
}
}
});
grid.jqGrid('filterToolbar',
{stringResult:true, searchOnEnter:true, defaultSearch:"cn"});
function addRow(tableId){
var loopRow = document.getElementById("addRowsInput").value;
var recordCount = '';
var rwData = '';
//var selRowIds = getRowIDs('list');
var gridProducts = $("#list");
var resetFirstRow = jQuery("#list").getRowData( 1 );
jQuery("#list").setRowData( 1, resetFirstRow );
if(loopRow == null || loopRow == "" || loopRow == "Enter number of units to be added")
{
loopRow = 1;
}
for(i=0; i< loopRow; i++)
{
recordCount = jQuery("#list").getGridParam("records") ;
var emptydata = [
{id:(recordCount+1), Name:"", Category:"", Subcategory:""}]
gridProducts.jqGrid('addRowData', recordCount+1, emptydata[0]);
}
}
</script>
#Oleg - one more question on the solution you suggested. Sorry I tried myself to find it but couldn't.
In the buildSearchSelect: method , how can I include filter for empty string.
As explained above I have a "Add Row" button. So when the user wants to filter rows with empty columns I need a filter value.
The implementation of setSearchSelect function from my old answer work only if the searching toolbar not yet exist. If the toolbar exist one have to modify the options of the select element or autocomplete source of the jQuery UI autocomplete widget.
I extended the code. You can see the new version of the demo here. In the same way one could use inline editing instead of the cell editing.
Here is the modified JavaScript code:
var mydata = [
{id:"1", Name:"Miroslav Klose", Category:"sport", Subcategory:"football"},
{id:"2", Name:"Michael Schumacher", Category:"sport", Subcategory:"formula 1"},
{id:"3", Name:"Albert Einstein", Category:"science", Subcategory:"physics"},
{id:"4", Name:"Blaise Pascal", Category:"science", Subcategory:"mathematics"}
],
grid = $("#list"),
getUniqueNames = function(columnName) {
var texts = grid.jqGrid('getCol',columnName), uniqueTexts = [],
textsLength = texts.length, text, textsMap = {}, i;
for (i=0;i<textsLength;i++) {
text = texts[i];
if (text !== undefined && textsMap[text] === undefined) {
// to test whether the texts is unique we place it in the map.
textsMap[text] = true;
uniqueTexts.push(text);
}
}
uniqueTexts.sort();
return uniqueTexts;
},
buildSearchSelect = function(uniqueNames) {
var values=":All";
$.each (uniqueNames, function() {
values += ";" + this + ":" + this;
});
return values;
},
setSearchSelect = function(columnName) {
var $select = $('select#gs_'+columnName), un = getUniqueNames(columnName),
htmlForSelect = '<option value="">All</option>', i, l=un.length, val;
grid.jqGrid('setColProp', columnName,
{
stype: 'select',
searchoptions: {
value:buildSearchSelect(un),
sopt:['eq']
}
}
);
if ($select.length > 0) {
// The searching toolbar already exist. One have to update it manually
for (i=0;i<l;i++) {
val = un[i];
htmlForSelect += '<option value="'+val+'">'+val+'</option>';
}
$select.html(htmlForSelect);
}
},
setAutocomplete = function(columnName) {
var $input = $('input#gs_'+columnName), un = getUniqueNames(columnName);
grid.jqGrid('setColProp', columnName,
{
searchoptions: {
sopt:['cn'],
dataInit: function(elem) {
$(elem).autocomplete({
source:un,
delay:0,
minLength:0
});
}
}
});
if ($input.length > 0) {
// The searching toolbar already exist. One have to update the source
$input.autocomplete('option', 'source', un);
}
},
selectColumns = ['Category','Subcategory'], autocompleteColumns = ['Name'];
grid.jqGrid({
data: mydata,
datatype: 'local',
colModel: [
{ name:'Name', index:'Name', width:200 ,editable:true},
{ name:'Category', index:'Category', width:200,editable:true },
{ name:'Subcategory', index:'Subcategory', width:200,editable:true }
],
sortname: 'Name',
viewrecords: true,
rownumbers: true,
sortorder: "desc",
cellEdit: true,
cellsubmit: 'clientArray',
ignoreCase: true,
pager: '#pager',
height: "auto",
caption: "How to use filterToolbar better locally including local cell editing",
afterSaveCell: function(rowid,name,val,iRow,iCol) {
if ($.inArray(name,selectColumns) !== -1) {
setSearchSelect(name);
} else if ($.inArray(name,autocompleteColumns) !== -1) {
setAutocomplete(name);
}
}
}).jqGrid('navGrid','#pager',
{edit:false, add:false, del:false, search:false, refresh:true});
$.each(selectColumns,function() {
setSearchSelect(String(this));
});
$.each(autocompleteColumns,function() {
setAutocomplete(String(this));
});
grid.jqGrid('filterToolbar',
{stringResult:true, searchOnEnter:true, defaultSearch:"cn"});
I have a Sencha Touch app that has a nested list.
The nestedList automatically creates its own toolBar.
I would like to dock a panel below the toolbar, but above the list-items. And I only need this on the top-level of the list. I am hoping to have it disappear after the first leaf is selected.
Does this sound like something doable? As you can see in my code, I only have the ability to dock an item panel on top of the current toolbar.
Thanks so much in advance. I really appreciate any advice you guys might have.
Al.
Below is what I have so far...
// Menu Pages
var menu = new Ext.NestedList({
fullscreen: true,
title: 'Menu',
displayField: 'text',
store: menu_store,
// ** This is the dockedItem I would like to insert between the toolbar and list-items
dockedItems: [ {
xtype : 'panel',
dock : 'top',
html : '<span>This is the logo panel</span>',
cls : 'front-logo-panel',
flex : 1
}],
// Add Panel for Leaf nodes
getDetailCard: function(item, parent) {
var itemData = item.attributes.record.data,
parentData = parent.attributes.record.data,
detailCard = new Ext.Panel({
scroll: 'vertical',
cls: 'menu-item-panel',
styleHtmlContent : true,
tpl: menuTemplate,
// add button to Leaf Node
listeners: {
activate: function() {
Ext.getCmp('itemToolbar').setTitle('New Title Bar');
}
}
});
detailCard.update(itemData);
this.backButton.setText(parentData.text);
return detailCard;
},
// add template for all nodes
getItemTextTpl: function() {
var tplConstructor =
'<tpl if="newItem">' +
'<span class="list-new-item">New Item!</span>' +
'</tpl>'+
'{text}' +
'<tpl>'+
'<div class="metadata">' +
'{description:ellipsis(40)}' +
'</div>' +
'</tpl>';
return tplConstructor;
}
});
Old question, I know, but to solve this, you can remove the toolbar from the list (without destroying it) and add it to a panel above the list. All nestedList functionality stays the same on the toolbar. Here's the solution I have:
First, I created a view that extends from NestedList and contains a toolbar:
Ext.define('MyApp.view.DynamicList', {
extend: 'Ext.dataview.NestedList',
alias: 'widget.dynamiclist',
config: {
toolbar: {
xtype: 'toolbar',
docked: 'top',
itemId: 'header-bar',
layout: {
pack: 'end',
type: 'hbox'
},
items: [
{
xtype: 'spacer'
},
{
xtype: 'button',
itemId: 'show-nav-sheet-button',
ui: 'plain',
width: 45,
iconCls: 'more'
}
]
}
}
});
Next, I created a main panel with a vbox layout that contains a child panel and this toolbar:
Ext.define('MyApp.view.MainContainer', {
extend: 'Ext.Container',
requires: [
'MyApp.view.DynamicList'
],
config: {
id: 'main-container',
layout: {
type: 'vbox'
},
items: [
{
xtype: 'panel',
flex: 1,
itemId: 'info-container'
},
{
xtype: 'dynamiclist',
flex: 1
}
]
}
});
Then, in a controller, I listen for the initialize event of the nested list. When it's fired, I remove the toolbar from the nested list and add it to the panel.
onNestedListInitialize: function() {
// need to wait until everythin is initialized;
var me = this;
var renderFn = function renderPanels() {
var main = me.getMainContainer();
// wait until main is intialized;
if(!main) {
Ext.defer(renderFn, 50, this);
return;
}
var list = main.down('#my-list');
var infocont = main.down('#info-container');
// wait until the container's components are initialized
if(!list || !infocont) {
Ext.defer(renderFn, 50, this);
return;
}
// remove the toolbar from the list, and add it to the container.
var toolbar = list.down('#header-bar');
list.remove(toolbar, false);
infocont.add(toolbar);
}
// call the function for the first time.
renderFn();
}
Note, I had to add a few checks to make sure the components were correctly initialized before using them, but the heart of it comes to the list.remove(toolbar, false) followed by the infocont.add(toolbar) commands. The false flag in the .remove() method means that the item won't be destroyed, so it's available to be re-added to the panel.