I have a widget with two grids.
When selected a row of the first grid is done the load of the second grid
according to the id_note sent on request.
If the grids are, for example, in a layout hbox, it works well.
However, when the second grid is within a modal window, the load of the store failed.
What is failing in my code?
(...)
},{
xtype: 'actioncolumn',
text:'Notes',
minWidth: 40,
flex:0.30,
align:'center',
items: [{
icon: 'resources/images/loadWin.png',
tooltip: 'show window',
handler: function(grid, record, item, index, e, eOpts){
var selectRow = grid.getSelectionModel().select(record);
var selection = grid.getSelectionModel().getLastSelected(record);
var id_note= selection.get('id_note');
var win = Ext.widget('popupWindow', {
animateTarget : item,
}).show();
var grid = Ext.ComponentQuery.query('#gridItemId')[0]; //grid within win
var store = grid.getStore();
store.proxy.extraParams = {
'id_note': id_note
},
//Right up to this point
store.load(); //**PROBLEM HERE**
}
}
(...)
The problem was to obtain the grid store reference in this case ( grid within window created dynamically).
I got the store reference with StoreManager (storeId) and now works well.
//var grid = Ext.ComponentQuery.query('#gridItemId')[0];
//var store = grid.getStore();
var store = Ext.getStore('storeId');
Thanks again Drake.
Related
I have custom control inside TabPanel: {items: Panel: {items: customcontrol}}.
Inside control, i create dynamically in onRender handler image control with picture. Picture can be different sizes. How me refresh current container, that it took the right size? It happen automatically, then i switch to another tab and back. doLayout() not working, function updateLayout() violates the layout of the other tabs.
creating image:
onRender: function () {
var me = this;
me.callParent(arguments);
this.el.update(this.imageFieldTpl.apply(this));
var imageWrap = Ext.query('.image-ct', this.el.dom)[0];
this['image'] = Ext.create(Ext.Img, {
name: 'image',
height: "100%",
width: "100%",
renderTo: imageWrap
});
if (this.value != null) {
this.fireEvent('imageChange', this.value);
}
}
I'm going crazy here trying o work out why the scoping of my variable won't pick up the right value from a loop of 60 items from a DB in my Appcelerator project.
My map marker displays the correct label, but when I click it, no matter what combo of scoping I try, I cannot get the correct value in the alert. It just returns the 60th entry every time.
Likely a schoolboy error, but this is driving me nuts.
This is my function
function loadAnimals() {
var db = Ti.Database.open('myDB');
var getSpecies = db.execute('select * from species');
while (getSpecies.isValidRow()) {
var speciesID = getSpecies.fieldByName('speciesnid');
var speciesName = getSpecies.fieldByName('speciesname');
var speciesDesc = getSpecies.fieldByName('speciesdescription');
var speciesLatitude = getSpecies.fieldByName('specieslatitude');
var speciesLongitude = getSpecies.fieldByName('specieslongitude');
var speciesConStatus = getSpecies.fieldByName('speciesconservationstatus');
var speciesMarkerFilename = getSpecies.fieldByName('speciesiconfilename');
var speciesMarkerIcon = getSpecies.fieldByName('speciesmapicon');
var speciesMarkerURI = getSpecies.fieldByName('speciesmapiconurl');
var speciesImageFullPath = speciesMarkerURI.replace("public://", "http://myurl.com/");
var speciesImageFullPath = speciesImageFullPath.replace(" ", "%20");
var imageFile = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, speciesMarkerIcon);
var iconFile = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, speciesMarkerFilename);
var annotationView = Ti.UI.createView({
backgroundColor: '#222222',
width: 150,
height: 75,
layout:'vertical'
});
var addtoTourView = Ti.UI.createView({
height:20,
backgroundColor:'#6ea108'
});
var addtoTourTitle = Ti.UI.createLabel({
color: '#FFF',
text: 'ADD TO TOUR',
width: 150,
height: 15,
top:3,
textAlign: 'center',
font: {
fontSize: 14,
fontWeight: 'bold'
}
});
var annotationTitle = Ti.UI.createLabel({
color: '#FFF',
text: 'test',
width: 150,
height:15,
top:0,
textAlign: 'center',
font: {
fontSize: 14,
fontWeight: 'normal'
}
});
var blankView = Ti.UI.createView({
backgroundColor: '#222222',
width: 1,
height: 73,
borderRadius: 0
});
annotationView.add(addtoTourView);
addtoTourView.add(addtoTourTitle);
annotationView.add(annotationTitle);
annotations.push(Map.createAnnotation({
latitude: speciesLatitude,
longitude: speciesLongitude,
title: ' ',
//pincolor: Map.ANNOTATION_RED,
image: iconFile,
animate: true,
myid: speciesID,
rightView: annotationView,
leftView: blankView
}));
addtoTourView.addEventListener('click', function(e) {
//alert(speciesName + ' has dded to Tour');
var dialog = Ti.UI.createAlertDialog({
message: 'Added to your Tour',
ok: 'Continue',
title: speciesName //this is the 60th entry, not the correct one
});
dialog.show();
// do the insert into the DB
var db = Ti.Database.open('myDB');
db.execute('INSERT INTO tour (speciesnid) VALUES (?)', speciesID); // same with this ID, needs to the correct ID
db.close();
});
annotationTitle.text = speciesName;
//load up the next record
getSpecies.next();
};
// close the database
getSpecies.close();
// add markers to map
mapview.annotations = annotations;
};// end of loadAnimals fucntion
Can anyone suggest what I'm doing wrong?
Michaels solution sounds right.
Let me post what I was gonna say anyway. I focus on explaining the scope problem, on why your code doesn't do what you expected.
In javascript the scope is bound to the function. When you declare a variable within a loop (for/while/do...) things can get a little confusing. You are not creating new variables, you are just overriding the value of the first (and only) variable with that name.
So, you have 1 variable in function loadAnimals, called speciesName. In the while-loop you just override the value of that variable. After the 60'th iteration, the variable just remembers the last thing you set it to.
When the client clicks on the marker, the loop is finished, the value has been set a long time ago.
Notice: there are probably solutions provided by your map service, but I don't know about that.
1 solution: 'this'.
The 'this' variable tells you what has been affected. Inside a onClick callback, this is the element that was clicked on.
The solution to your problem will probably involve 'this'. But I'm not sure exactly how.
Here an example of what I mean.
<h2>Click on the animal</h2>
<p>dog</p>
<p>cat</p>
<p>hamster</p>
<script>
function loadAnimals() {
var speciesName = '';
var animalElements = document.getElementsByTagName('p');
for (var i=0; i<animalElements.length; i++) {
speciesName = animalElements[i].innerHTML ; // notice, this variable will be overridden, so this variable is useless within the onClick callback.
animalElements[i].addEventListener('click', function(e) {
// variable 'this' is the <p> that was clicked on.
var value_clicked_on = this.innerHTML;
alert(value_clicked_on);
});
}
}
window.onload = loadAnimals;
</script>
When creating your annotations array to add to to the map add your title to the annotation paramters as well as the speciesID which you are setting with the key - myid.
annotations.push(Map.createAnnotation({
latitude: speciesLatitude,
longitude: speciesLongitude,
title: ' ',
//pincolor: Map.ANNOTATION_RED,
image: iconFile,
animate: true,
myid: speciesID, // We'll be querying this
myname: speciesName, // and also this
rightView: annotationView,
leftView: blankView
}));
Then add your event listener once onto the map object instead of each individual annotation object. This manages memory more efficiently and is the correct way to add it. Don't add the event listener on for every annotation, this is bad practise.
// Handle click events on any annotations on this map.
mapview.addEventListener('click', function(evt) {
Ti.API.info("speciesID " + evt.annotation.myid + " clicked, speciesName: " + evt.annotation.myname);
});
On this single event listener you can now create your alert dialog and DB insert by accessing each annotations individual properties by inspecting
evt.annotation
On the Map object you can do the following as well:
The click event includes a value which you can interrogate clicksource
This clicksource will let you know the source - pin, annotation, leftButton, rightButton, leftView, rightView, title, or subtitle which you can use in the event listener.
Also available is the source object that fired the event - source. You can then test if the clicksource is not null and the source is coming from the "ADD TO TOUR" element that you want to place the trigger on. still getting all your annotation properties from evt.annotation
Though I have successfully colored the bars of google chart individually but not able to keep them when we hover mouse over it. It is getting reset back to blue(which is default).
Here is the jsfiddle of what I have done jsfiddle.
I tried to control the hover behaviour with multiple ways like below.
This I am keeping outside (document.ready) but inside script tag.
1)
$('#chart_div').hover(
function() {
$('#chart_client').hide(); // chart_client is another google chart div.
}, function() { // just for testing I was doing hide/show of that.
$('#chart_client').show();
}
);
2)
$("#chart_div").on({
mouseenter: function () {
$('#chart_client').hide();
},
mouseleave:function () {
$('#chart_client').show();
}
},'rect');
3)
google.visualization.events.addListener('#chart_div', 'ready', function () {
$('#chart_div rect').mouseover(function (e) {
alert('hello');
});
});
I must be doing something wrong, could you please tell me what and where.
I solved it using below code. Earlier I was trying to create charts using dynamically adding rows into chart(please visit my jsfiddle) but with this below approach I am first preparing data(converting dynamic to static) and adding that static data in to chart's 'arrayToDataTable' method.
google.load("visualization", "1", {packages:["corechart"]});
google.setOnLoadCallback(drawUserKeywordChart);
function drawUserKeywordChart() {
var val = 'Tax:47;Finance:95;Awards:126;Bank:137;Debt:145;';
var length = val.length;
var array = [];
//preparing data
while(length>0){
var sepAt = val.indexOf(";");
var value = parseInt(val.substring(val.indexOf(":")+1, sepAt));
array.push(val.substring(0, val.indexOf(":")));
array.push(value);
val = val.substring(val.indexOf(";")+1, length);
length = val.length;
}
var data = google.visualization.arrayToDataTable([
['Keyword', 'Occurences', { role: 'style' }],
[array[0], array[1], '#8AA3B3'],
[array[2], array[3], '#A9B089'],
[array[4], array[5], '#848C49'],
[array[6], array[7], '#44464A'],
[array[8], array[9], '#704610'],
]);
var options = {
title: 'Keyword Matches',
width: 660,
height: 450,
titleTextStyle:{bold:true,fontSize:20},
legend:{position:'none'}
};
var chart = new google.visualization.ColumnChart(document.getElementById('chart_keyword1'));
chart.draw(data, options);
}
Please advice if you find anything wrong here or you have better approach than this.
I need to add a jquery ui slider to each cell of slickgrid. Number of records is over 10,000 with over 150 columns. The problem is that the initial set of sliders are rendered fine but as I scroll (left or right), they disappear. Somehow, the grid is not getting invalidated for those cells. I am using the following formatter on the column:
SliderFormatter = function (row, cell, value, colDef, dataContext) {
var html = "<div class='mySlider' id='slider_" + dataContext['id'] + "'></div>" + value;
return html;
}
and invoking the slider from my document.ready callback.
Any help will be appreciated. Thanks in advance !
SlickGrid renders only what's visible in the viewport, plus a small buffer. As you scroll, rows/cells are dynamically added and removed.
What this means for your case, is that when you initialize the slider widget in your document.ready callback, you're only initializing a tiny portion of them, and the ones that did get initialized, don't get re-initialized when the cells they are in are removed and recreated by SlickGrid.
SlickGrid doesn't allow you to use jQuery widgets like the slider in cells and requires that formatters output pure HTML in order to make it hard to implement the grid in a way that will slow it down. (I won't get into my reasoning behind that admittedly controversial decision.)
My advice here is to avoid using the jQuery UI slider here. It is simply not scalable or performant enough. Without virtualization, what you're trying to do is impossible - initializing 100 sliders is going to be really slow; initializing 10'000 x 150 of them is out of the question. With virtualization, you'll need to initialize and destroy them on the fly as you're scrolling around, and that's just too slow to scroll smoothly.
Consider using an HTML5 range input - <INPUT type="range">. It's supported by all major browsers with the exception of IE <10. See http://caniuse.com/#feat=input-range.
I've created an example using SlickGrid's async post-render option. #Tin is probably right that it would be better to use the native <input type="range"> but just in case you need to support older browsers here's how you can do it.
function waitingFormatter(value) {
return '<div class="slider"></div>';
}
function renderSlider(cellNode, row, dataContext, colDef) {
var cell = $(cellNode);
cell.find('.slider').slider({
value: dataContext.value,
slide: function(e, ui) {
data[row].value = ui.value;
cell.prev().html(ui.value);
}
});
}
var grid;
var data = [];
var columns = [
{ id: "title", name: "Title", field: "title", sortable: false, width: 120, cssClass: "cell-title" },
{ id: "value", name: "Value", field: "value", sortable: false, editor: Slick.Editors.Integer, width: 40, validator: requiredFieldValidator },
{ id: "chart", name: "Slider", sortable: false, width: 425, formatter: waitingFormatter, rerenderOnResize: true, asyncPostRender: renderSlider }
];
var options = {
editable: true,
enableAddRow: false,
enableCellNavigation: true,
asyncEditorLoading: false,
enableAsyncPostRender: true
};
$(function () {
for (var i = 0; i < 500; i++) {
var d = (data[i] = {});
d["title"] = "Record " + i;
d["value"] = Math.round(Math.random() * 100);
}
grid = new Slick.Grid("#myGrid", data, columns, options);
})
My problem: When I drag a row in jqGrid, and it completes a custom reload function, the cells of the grid, previously all of varying widths set when the grid is defined, are resized to all be the same width. This happens in Webkit browsers but not in Firefox.
Code:
I have dragging to sort enabled on a grid:
$mygrid.jqGrid(
'sortableRows', {
update: function(e, ui) {
sort_grid(e, ui);
}
}
);
As you can see I have a sorting function called on drag complete, sort_grid. Here it is:
function sort_grid(e, ui) {
var current_grid = $(ui.item[0]).closest('table').attr('id');
var $current_row, moved_id, next_id, next_priority;
var $moved_row = $('#' + current_grid + ' tr');
var cnt = 0;
this_id = ui.item[0].id;
$moved_row.each(function () {
if ($(this).attr('id') == this_id) {
$current_row = $moved_row.eq(cnt);
moved_id = $current_row.attr("id");
next_id = $current_row.next().attr("id");
next_priority = $current_row.next().children("td:first").attr("title");
}
cnt++;
});
if ( typeof moved_id !== 'undefined' ) {
if ( next_priority == 'undefined' ) {
next_priority = '999';
}
$.ajax({
url:my_url,
type:"POST",
data:"moved_id=" + moved_id + "&next_id=" + next_id + "&next_priority=" + next_priority,
success: function(data) {
$('.grid').setGridParam({loadonce:false, datatype:'json'}); // force grid refresh from server
$('#' + current_grid).trigger("reloadGrid");
$('.grid').setGridParam({loadonce:true}); // reset to use local values
}
})
}
}
Once I hit that reload trigger $('#' + current_grid).trigger("reloadGrid"); and reload finishes the grid now has incorrect widths on the cells in the grid (they go from being of various widths to all being the same width).
When the grid was originally created it had widths defined in the normal jqGrid fashion:
colModel:[
{name:'one', index:'one', sortable:true, width:45},
{name:'two', index:'two', sortable:true, width:180},
]
but after the grid reload the widths are reset all be the same width (I assume this is the total width of the grid being evenly divided over the total number of cells in the row). So, do I need to explicitly set these widths again, perhaps with something like the following called after the grid reloads?
$('.grid').setGridParam({
colModel:[
{name:'one', index:'one', sortable:true, width:45},
{name:'two', index:'two', sortable:true, width:180},
]
});
I tried the above fix, redefining the colModels after reload and explicitly setting the widths, but it had no effect. Weirder, if I go into the browser console and set the widths with javascript it also has no effect. That's got me stumped.
Unfortunately for me it looks like the jqGrid "Answer Man" (Oleg) is not around... lol.
I faced the same problem for Chrome. I recreated it here http://jsfiddle.net/gZSra/. Just drag the row and then sort any column.
But after few hard hours of debugging jqGrid sources I finally fixed this bug. The problem appears in emptyRows method of jqGrid.
emptyRows = function (scroll, locdata) {
var firstrow;
if (this.p.deepempty) {
$(this.rows).slice(1).remove();
} else {
firstrow = this.rows.length > 0 ? this.rows[0] : null;
$(this.firstChild).empty().append(firstrow); // bug "activation" line
}
if (scroll && this.p.scroll) {
$(this.grid.bDiv.firstChild).css({height: "auto"});
$(this.grid.bDiv.firstChild.firstChild).css({height: 0, display: "none"});
if (this.grid.bDiv.scrollTop !== 0) {
this.grid.bDiv.scrollTop = 0;
}
}
if(locdata === true && this.p.treeGrid) {
this.p.data = []; this.p._index = {};
}
},
*In recent jqGrid-4.4.4 this code begins from 1070 line of jqGrid.src.js
The problem connected removing and then appending firstrow. This row defines width of columns - one of it's cells in my jsFiddle example is
<td role="gridcell" style="height:0px;width:60px;"></td>
That is why problem seems to be connected with some Chrome's or Webkit's dynamic table behaviour.
FIX
Replace infected else scope with next line
$(this.firstChild).find('tr:not(:first)').remove();
It's not hard to see that instead of removing all lines and then appending first back, I just selecting and removing all except first row.
Result jsFiddle: http://jsfiddle.net/HJ3Q3/
Tested in Chrome, FF, IE 8 & 9.
Hope this fix will soon become part of jqGrid sources.
.trigger('reloadGrid');
is causing issues with sortablerows.
Below work around might help you (Unload & reload grid)
Create a function to configure grid, like below
jQuery().ready(ConfigureGrid);
function ConfigureGrid(){
jQuery("#grdCategory").jqGrid({
url: '/controller/action',
datatype: "xml",
colNames: ['Order', 'Name', 'Page Title', 'Is Active', 'Action'
],
colModel: [
{ name: 'col1', index: 'col1', width: 50, sortable: true, sorttype: 'int' }
, { name: 'col2', index: 'col2', width: 150, sortable: true }
],
rowNum: 10,
rowList: [10, 20, 30],
});
$("#list1").jqGrid('navGrid', '#pager1', { edit: false, add: false, del: false, search: true });
$("#list1").jqGrid('sortableRows', { update: function (event, ui) { updateOrder() } });
}
Create function to reload grid
function loadGrid() {
$('#grdCategory').jqGrid('GridUnload');
ConfigureGrid();
}
use loadGrid() function in ajax call back or to refresh grid
Have you tried to setup this property in your jQgrid options
width: 'auto',
If this doesnt work try reloading your grid after the update of the row
jQuery('.grid').trigger('reloadGrid');
The comment of PokatilovArt needs more attention : jqGrid - Dragging a row to sort it screws up cell widths .
It solves the problem in Chrome.
Here is the parameter to change in jqGrid :
deepempty : true
In jqGrid wiki, here is the definition of this option.
This option should be set to true if an event or a plugin is attached to the table cell. The option uses jQuery empty for the the row and all its children elements. This of course has speed overhead, but prevents memory leaks. This option should be set to true if a sortable rows and/or columns are activated.