Ext JS 4.1 get column index in itemcontextmenu - extjs4.1

When I add listener for itemcontextmenu for Grid/Tree I'm able to access view record, item, index, but how to get column?
What I want to create is a contextMenu but only if user click on items in first column.
Here is my listener function:
firstColumnContext: function(view,record,item,index,e,eOpts) {
console.log(view);
console.log(record.getName());//this works
console.log(index);
console.log('get column');//
},
My concept looks like this:
firstColumnContext: function(view,record,item,index,e,eOpts) {
e.stopEvent();
if(record.get('leaf') && 'first column')
{
//show context menu here
}
},
But as I wrote before I need to verify if rightclick was in first column.

See this code, setup your grids viewConfig like this:
viewConfig: {
listeners:{
beforecellcontextmenu: function(view, tableCell, columnIndex, record, tableRow, rowIndex){
//your menu code here
},
itemcontextmenu: function(view,record,item,index,e,eOpts){
e.stopEvent();
}
}
}
The column index is provided by the beforecellcontextmenu event but not the fired event does not provide the event itself, so you have to use a combination of both events, one to stop the default menu and the other to pop it up in the case you want it to show.

I had this problem too. Here is the hack I devised for Grids that works nicely. It compares the mouse position at click to the positions of each column and finds when they overlap.
grid.on('itemcontextmenu', function(view, record, item, index, e) {
var xPos = e.getXY()[0];
var cols = view.getGridColumns();
for(var c in cols) {
var leftEdge = cols[c].getPosition()[0];
var rightEdge = cols[c].getSize().width + leftEdge;
if(xPos>=leftEdge && xPos<=rightEdge) {
console.log(cols[c].dataIndex);
}
}
});

Related

Scroll to a programmatically selected row in a v-data-table

I have a map with features on it that are also listed in a v-data-table. When the user clicks a row, the feature is highlighted on the map. When the user clicks a map feature, the corresponding grid row is selected. So I am programmatically setting the selected row like this:
selectRow(id) {
this.selected = [this.getRowFromId(id)]
},
getRowFromId(id) {
for (let site of this.sites) {
if (site.id === id) return site;
}
return []
},
Works fine with one UX problem: The table is not scrolled to the selected row.
I am using a vertically scrolling data-table with all rows in the grid rather than pagination.
Any ideas on how to programmatically scroll the data table?
Here is my solution. I found most of what I was looking for in this post: Plain JavaScript - ScrollIntoView inside Div
I had to do a couple of v-data-grid specific things to make it work. I am using a watcher in my context but you could to this anywhere you needed to:
watch: {
selectedId: function(newVal) { // watch it
// Select the row
this.selectRow(newVal)
// Scroll the item into view
// First we need to let the component finish selecting the row in the background
setTimeout( () => {
// We get the selected row (we assume only one or the first row)
const row = document.getElementsByClassName("v-data-table__selected")[0]
// Then we get the parent. We need to give the -v-data-table a ref
// and we actually take the child of the table element which
// has the scrollbar in my case.
const parent = this.$refs.detailGrid.$el.firstChild
// Finally call the scroll function
this.scrollParentToChild(parent, row )
}, 100)
}
},
methods: {
scrollParentToChild(parent, child) {
// Where is the parent on page
var parentRect = parent.getBoundingClientRect();
// What can you see?
var parentViewableArea = {
height: parent.clientHeight,
width: parent.clientWidth
};
// Where is the child
var childRect = child.getBoundingClientRect();
// Is the child viewable?
var isViewable = (childRect.top >= parentRect.top) && (childRect.top <= parentRect.top + parentViewableArea.height);
// if you can't see the child try to scroll parent
if (!isViewable) {
// scroll by offset relative to parent
parent.scrollTop = (childRect.top + parent.scrollTop) - parentRect.top - childRect.height
}
},
}

Data table on click on dynamic controls

I have a jquery data table that I am populating from a drop down on change event. I have two check boxes in the data table and I am running an onclick on the check boxes. But on the first click the jquery does not fire only when I click it a second time does the jquery fire, also happens on switching pages.I added the .on() for the click, because I researched and saw that dynamic controls would work that way. Is there something I'm missing also to get this click function to work on first click? Below is some of my code.
data table click on check box control no jquery click event on first click
data table click on check box control on second click
$('#my-table').on('click', function () {
var i = -1;
$("input[id*='secondary']:checkbox").on("click", function () {
if ($(this).is(':checked')) {
i = selectedIds.indexOf($(this).val());
if (i === -1) {
selectedIds.push($(this).val());
}
CheckedSecondary(this);
}
else {
jQuery(this).closest("tr").css("background-color", "");
if (selectedIds.length > 0) {
i = selectedIds.indexOf($(this).val());
if (i != -1) {
selectedIds.splice(i, 1);
}
}
if (!primaryChecked)
$(this).closest('tr').find('input[type="checkbox"]').not(this).attr('disabled', false);
}
});
$("#my-table").find("input[id*='primary']:checkbox").on("click", function () {
if ($(this).is(':checked')) {
primaryChecked = true;
primaryID = this.value;
CheckedPrimary(this);
}
else {
primaryID = "";
primaryChecked = false;
$(this).closest('tr').find('input[type="checkbox"]').not(this).attr('disabled', false);
$('input:checkbox[id^="primary"]').each(function () {
if (!$(this).closest('tr').find('input[type="checkbox"]').is(':checked'))
$(this).attr('disabled', false);
});
jQuery(this).closest("tr").css("background-color", "");
}
});
});
You're attaching click handler inside another click handler which doesn't make sense.
Remove first click handler:
$('#my-table').on('click', function () {
});
Attach the click handler to the checkboxes as follows:
$('#my-table').on('click', "input[id*='secondary']:checkbox", function () {
});
and
$('#my-table').on('click', "input[id*='primary']:checkbox", function () {
});

TableView 'click' listener being ignored

I am dynamically building a TableView in my controller, which works fine: The initial table displays the initial collections data as expected.
The problem is that the TableView's 'click' event listener is ignored when I click on the table rows. I am testing in the browser, and I never even see the console event file (see comments in controller file). All relevant code snippets below:
In my alloy.js I setup a backbone collection:
function defaultTodo(name) { return {name: name, done: false}; }
function doneTodo(name) { return {name: name, done: true}; }
Alloy.Collections.todos = new Backbone.Collection();
Alloy.Collections.todos.reset([
defaultTodo('Apples'), // create not yet done todo
defaultTodo('Banana'),
defaultTodo('Paper Towels'),
defaultTodo('Broccoli'),
doneTodo('Beans'), // create already done todo
doneTodo('Water'),
doneTodo('Blueberries'),
doneTodo('Stir Fry')
])
Here is my index.js controller:
var todos = Alloy.Collections.todos;
function redrawTable() {
// clear all the old data
// See http://developer.appcelerator.com/question/49241/delete-all-rows-in-a-tableview-with-a-single-click
$.table.setData([]);
// Create and add the TableViewSections
var alreadyDone = Ti.UI.createTableViewSection({ headerTitle: "Already Done" });
var needsDoing = Ti.UI.createTableViewSection({ headerTitle: "Needs Doing" });
$.table.appendSection(needsDoing);
$.table.appendSection(alreadyDone);
// Add the todo to the appropriate sections
todos.forEach(function(todo) {
var section = todo.get('done') ? alreadyDone : needsDoing;
addEntry(todo, section);
});
// Add the click listener
// THIS LISTENER IS IGNORED ********************************
$.table.addEventListener('click', function(e) {
console.log(e);
todos.at(e.index).set('done', true);
todos.trigger('change');
});
// Helper function to add a row to a section
function addEntry(todo, section) {
var row = Ti.UI.createTableViewRow({
title: todo.get('name'),
className: "row"
});
section.add(row);
}
}
// Redraw our table each time our todos collection changes
todos.on('change', redrawTable);
// Trigger a change event to draw the initial table
todos.trigger('change');
$.index.open();
And here is index.xml view file:
<Alloy>
<Window class="container">
<Label id="test" class="header">My Grocery List</Label>
<TextField id="newItem"/>
<TableView id="table">
</TableView>
</Window>
</Alloy>
UPDATE: Working Code
In addition to the changes below, I also added onClick="markDone" to the xml.
function markDone(e) {
console.log(e.row.todo);
e.row.todo.set('done', true);
todos.trigger('change');
}
function redrawTable() {
// clear all the old data
// See http://developer.appcelerator.com/question/49241/delete-all-rows-in-a-tableview-with-a-single-click
$.table.setData([]);
var rows = [];
var done = [];
var doing = [];
// Add the todo to the appropriate sections
todos.forEach(function(todo) {
var row = Ti.UI.createTableViewRow({
title: todo.get('name'),
className: "row"
});
row.todo = todo;
todo.get('done') ? done.push(row) : doing.push(row);
});
// Create and add the TableViewSections
rows.push(Ti.UI.createTableViewSection({ headerTitle: "Needs Doing" }));
rows = rows.concat(doing);
rows.push(Ti.UI.createTableViewSection({ headerTitle: "Already Done" }));
rows = rows.concat(done);
$.table.setData(rows);
};
I created brand new project using files which you provided and eventListener is working perfectly fine. However there are couple other bugs:
Creating listener inside redrawTable() function, which is executed every time you click on something in TableView. As a result at the beginning you have one eventListener but after every click all listeners are duplicated.
Using index property in event handler to find index of Backbone model object to update. index property is indicating at which place given row was displayed in your TableView. When you are moving rows between sections their index are changing. In your case it's better to check e.row.name property and use Backbone.Collection.findWhere() method. If user can have two items with the same name on the list, then you have to create additional property to determine which object in model should be changed.
You should add rows to section before section are added to table. In your case table is very simple so instead of doing loops you can just create one simple array of objects (with title and optional header properties) and pass it to $.table.setData().
It's good to wait for postlayout event triggered on main view before triggering any custom events to make sure that the whole view was created and all objects are initiated.
Check rewrote index.js code below to see how it could be done.
var todos = Alloy.Collections.todos;
function redrawTable() {
var done = todos.where({done: true}).map(function(elem) {
return { title: elem.get('name') };
});
if (done.length > 0) {
done[0].header = 'Already Done';
}
var notdone = todos.where({done: false}).map(function(elem) {
return { title: elem.get('name') };
});
if (notdone.length > 0) {
notdone[0].header = 'Needs Doing';
}
$.table.setData( done.concat(notdone) );
}
$.table.addEventListener('click', function(e) {
todos.where({ name: e.row.title }).forEach(function(elem){
elem.set('done', !elem.get('done'));
});
todos.trigger('change'); // Redraw table
});
// Redraw our table each time our todos collection changes
todos.on('change', redrawTable);
// Trigger a change event to draw the initial table
$.index.addEventListener('postlayout', function init(){
todos.trigger('change');
// Remove eventListener, we don't need it any more.
$.index.removeEventListener('postlayout', init);
})
$.index.open();
redrawTable() could have a little more refactor but I left it so it's easier to read.
To read more about manipulating TableView check this Appcelerator documentation page.

Can we implement On key up filter option in Yii's cGridview?

I am currently trying to implement automatic filtering in Yii cGridview, By default it filters 'onclick', or 'enter' key press, But I need to change that event to "onkeyup"|
my code is like this
Yii::app()->clientScript->registerScript('search',"
$('.filters > td >input').keyup(function(){
$('#grid-id').yiiGridView('update', {
data: $(this).serialize()
});
return false;
});
");
?>
when I entered the first letter filtering occured, but after filtering and rendering the code fails.. please give me a solution.. Is there any php yii gridview extension which has filtering onkeyup
You need to change the way you attach the keyup listeners. After the gridview refreshed through AJAX, all elements inside the grid are replaced. So there's no keyup attached anymore. You can try something like:
$('body').on('keyup','.filters > td > input', function() {
$('#grid-id').yiiGridView('update', {
data: $(this).serialize()
});
return false;
});
#Michael Härtl's answer is right. But 2 Problem occur when you use this code.
1) When User Search in filter at that time, every time grid will be refresh so focus of input box will be lost.
2) When you search in one filter input and if you go to second input field field at that time first input box will be lost.
So now I have got the solution for that.
Set this java script code on your grid view.
Yii::app()->clientScript->registerScript('search', "
$('body').on('keyup','.filters > td > input', function() {
$(document).data('GridId-lastFocused',this.name);
data = $('#GridId input').serialize();
$('#GridId').yiiGridView('update', {
data: data
});
return false;
});
// Configure all GridViews in the page
$(function(){
setupGridView();
});
// Setup the filter(s) controls
function setupGridView(grid)
{
if(grid==null)
grid = '.grid-view tr.filters';
// Default handler for filter change event
$('input,select', grid).change(function() {
var grid = $(this).closest('.grid-view');
$(document).data(grid.attr('id')+'-lastFocused', this.name);
});
}
// Default handler for beforeAjaxUpdate event
function afterAjaxUpdate(id, options)
{
var grid = $('#'+id);
var lf = $(document).data(grid.attr('id')+'-lastFocused');
// If the function was not activated
if(lf == null) return;
// Get the control
fe = $('[name=\"'+lf+'\"]', grid);
// If the control exists..
if(fe!=null)
{
if(fe.get(0).tagName == 'INPUT' && fe.attr('type') == 'text')
// Focus and place the cursor at the end
fe.cursorEnd();
else
// Just focus
fe.focus();
}
// Setup the new filter controls
setupGridView(grid);
}
// Place the cursor at the end of the text field
jQuery.fn.cursorEnd = function()
{
return this.each(function(){
if(this.setSelectionRange)
{
this.focus();
this.setSelectionRange(this.value.length,this.value.length);
}
else if (this.createTextRange) {
var range = this.createTextRange();
range.collapse(true);
range.moveEnd('character', this.value.length);
range.moveStart('character', this.value.length);
range.select();
}
return false;
});
}");
Add this line to your gridview widget code.
'afterAjaxUpdate'=>'afterAjaxUpdate',
For example:
$this->widget('zii.widgets.grid.CGridView', array(
'id' => 'GridId',
'afterAjaxUpdate'=>'afterAjaxUpdate',
));

Ext.grid.Panel get selected record from tbar button

I created a View extend Ext.grid.Panel and also attach a tbar to it, in the toolbar I got 2 buttons [Add] and [Remove] in this question I am focus on the [Remove] command only.
As usual I want to get hold to current selected record in the grid which I want to delete.
so in the controller:
init: function() {
this.control({
'extendgridlist button[action=remove]': {
click: this.removeCurrentRow;
}
});
}
removeCurrentRow: function(t){
// how do i get current selected record
}
removeCurrentRow: function(t){
var grid = t.up('gridpanel');
var arraySelected =grid.getSelectionModel().getSelection();
//assuming you have a single select, you have the record at index 0;
var record = arraySelected[0]
}
The answer by 'nscrob' should work just fine, I just wanted to point out an alternate method. Every Ext component can have an 'id' field. So, if you gave your grid a config option like the following when it was created:
id:'my_grid_id'
Then, from anywhere including inside your removeCurrentRow function, you could do the following:
var grid = Ext.getCmp('my_grid_id');
var rows = grid.getSelectionModel().getSelection();
if(!rows.length)
{ //in case this fires with no selection
alert("No Rows Selected!");
return;
}
var row = rows[0];
As I said, similar to other answers, but just another way of accessing the grid.
In case grid is to selType = "cellModel" use code below:
var grid = Ext.getCmp('id-of-grid');
var recid = grid.getSelectionModel().getCurrentPosition();
if(recid && recid.row){
var r = grid.getStore().getAt(recid.row)
alert(r.data.anyofgridfieldid)
}
more details: http://as400samplecode.blogspot.com/2012/01/extjs-grid-selected-row-cell.html
...
xtype: 'button',
text: 'Edit',
handler: function() {
onEdit(this.up('theGrid')); // alias: 'widget.theGrid' in definition
}
...
function onEdit(theGrid) {
if (theGrid.getSelectionModel().hasSelection()) {
var rows = theGrid.getSelectionModel().getSelection();
var row = rows[0];
console.log('Count Rows Selected : ' + rows.length);
console.log('The Row : ' + row); // columns: 'id', 'name', 'age'
console.log('Student Id: ' + row.get('id'));
console.log('Student Name: ' + row.get('name'));
console.log('Student Age: ' + row.get('age'));
}
else {
console.log('No Row Selected.');
}
}