M
Murray Hopkins
Hi.
THE QUESTION: How do I get a reference to my Object when processing an
event handler bound to an html element ?
CONTEXT:
Sorry if it is a bit long.
I am developing a JS calendar tool. One of the requirements is that the
calendar will need to display a varying number of months (1..3)
depending on the calling page. Imagine 1, 2 or 3 calendar pages side by
side as required.
I have built a grid object that will contain one month's dates with the
day names at the top. The calendar object inherits the grid object as an
array of "calendar pages" - one grid per month and the calendar provides
the content for each grid. I will use the grid object for another
completely different object later and so I want to use good OOP
encapsulation. The grid is a table generated on the fly and is "dumb" as
far as what it is used for.
I have attached an onlick event to each cell of the grid. Using OOP
priciples I want the calling program (the calendar object in this case)
to provide a function to handle the click and the grid object will
provide to the calendar the row and column of that cell as well as the
grid number (so the calendar can work out which date was clicked since
it knows what the data means and the grid doesnt).
The following technique works:
// INITIALISE THE GRID
function Grid(gridNumb) {
this.gridNumb = gridNumb;
this.rows = 6;
this.cols = 7;
this.gridobj = $('grid_'+gridnumb) // a reference to the table that is
the grid
this.onclickHandler = null
}
// ASSIGN THE ONCLICK FUNCTION PASSED IN
Grid.prototype.assignOnclickHandler = function(handler) {
this.onclickHandler = handler;
}
// ADD THAT HANDLER TO EACH CELL
Grid.prototype.addHandlers = function() {
for (r=0; r < this.rows; r++) {
for (c=0; c < this.cols; c++) {
this.gridObj.rows[r].cells[c].onclick = this.onclickHandler
}
}
}
And if I do this on a test page:
var grid = new Array()
grid[0] = new Grid(0)
grid[0].assignOnclickHandler(handleClick)
function handleClick() {
alert(this) // this is a reference to the table cell that was click on
col = this.cellIndex
etc..
}
the handleClick function works and returns the reference to the table
cell that was clicked. All good.
BUT...
what I actually want to do is have the grid object return the row,
column and gridID number to the calling program instead of just a
reference to the table cell that was clicked.
So, I modified the above so that I am using an internal onclick handler
function that will do the necessary work to return the row, column and
gridID to the calling object.
ie
// INITIALISE THE GRID
function Grid(gridNumb) {
this.gridNumb = gridNumb;
this.rows = 6;
this.cols = 7;
this.gridobj = $('grid_'+gridnumb) // a reference to the table that is
the grid
// this.onclickHandler = null <-- removed this
}
/* removed this
// ASSIGN THE ONCLICK FUNCTION PASSED IN
Grid.prototype.assignOnclickHandler = function(handler) {
this.onclickHandler = handler;
}
*/
// ADDED THIS INTERNAL HANDLER:
Grid.prototype.onclickHandler = function() {
alert(this.rows)
// 1. calculate the row, col and gridNumb ...
// 2. return those values ...
}
// ADD THAT HANDLER TO EACH CELL - SAME AS BEFORE
Grid.prototype.addHandlers = function() {
for (r=0; r < this.rows; r++) {
for (c=0; c < this.cols; c++) {
this.gridObj.rows[r].cells[c].onclick = this.onclickHandler
}
}
}
Now, when a cell on the grid is clicked, the new internal onclick
function fires - which is correct.
THE PROBLEM:
The alert(this.rows) in the internal onclick function shows "undefined"
because the "this" refers to the table cell element, not the grid object!
How do I get a reference to the grid object from that point ???
The obvious work-around is to use the external grid var directly but
apart from breaking the encapsulation when I have multiple grids I dont
know which one has been clicked since I cant reference anything about
the grid object itself.
The other solution is to set the id of each td element to contain the
grid number and use getElementById to get the reference, but I was
hoping to find an OOP way of doing it.
Any ideas ?
Thanks,
Murray
THE QUESTION: How do I get a reference to my Object when processing an
event handler bound to an html element ?
CONTEXT:
Sorry if it is a bit long.
I am developing a JS calendar tool. One of the requirements is that the
calendar will need to display a varying number of months (1..3)
depending on the calling page. Imagine 1, 2 or 3 calendar pages side by
side as required.
I have built a grid object that will contain one month's dates with the
day names at the top. The calendar object inherits the grid object as an
array of "calendar pages" - one grid per month and the calendar provides
the content for each grid. I will use the grid object for another
completely different object later and so I want to use good OOP
encapsulation. The grid is a table generated on the fly and is "dumb" as
far as what it is used for.
I have attached an onlick event to each cell of the grid. Using OOP
priciples I want the calling program (the calendar object in this case)
to provide a function to handle the click and the grid object will
provide to the calendar the row and column of that cell as well as the
grid number (so the calendar can work out which date was clicked since
it knows what the data means and the grid doesnt).
The following technique works:
// INITIALISE THE GRID
function Grid(gridNumb) {
this.gridNumb = gridNumb;
this.rows = 6;
this.cols = 7;
this.gridobj = $('grid_'+gridnumb) // a reference to the table that is
the grid
this.onclickHandler = null
}
// ASSIGN THE ONCLICK FUNCTION PASSED IN
Grid.prototype.assignOnclickHandler = function(handler) {
this.onclickHandler = handler;
}
// ADD THAT HANDLER TO EACH CELL
Grid.prototype.addHandlers = function() {
for (r=0; r < this.rows; r++) {
for (c=0; c < this.cols; c++) {
this.gridObj.rows[r].cells[c].onclick = this.onclickHandler
}
}
}
And if I do this on a test page:
var grid = new Array()
grid[0] = new Grid(0)
grid[0].assignOnclickHandler(handleClick)
function handleClick() {
alert(this) // this is a reference to the table cell that was click on
col = this.cellIndex
etc..
}
the handleClick function works and returns the reference to the table
cell that was clicked. All good.
BUT...
what I actually want to do is have the grid object return the row,
column and gridID number to the calling program instead of just a
reference to the table cell that was clicked.
So, I modified the above so that I am using an internal onclick handler
function that will do the necessary work to return the row, column and
gridID to the calling object.
ie
// INITIALISE THE GRID
function Grid(gridNumb) {
this.gridNumb = gridNumb;
this.rows = 6;
this.cols = 7;
this.gridobj = $('grid_'+gridnumb) // a reference to the table that is
the grid
// this.onclickHandler = null <-- removed this
}
/* removed this
// ASSIGN THE ONCLICK FUNCTION PASSED IN
Grid.prototype.assignOnclickHandler = function(handler) {
this.onclickHandler = handler;
}
*/
// ADDED THIS INTERNAL HANDLER:
Grid.prototype.onclickHandler = function() {
alert(this.rows)
// 1. calculate the row, col and gridNumb ...
// 2. return those values ...
}
// ADD THAT HANDLER TO EACH CELL - SAME AS BEFORE
Grid.prototype.addHandlers = function() {
for (r=0; r < this.rows; r++) {
for (c=0; c < this.cols; c++) {
this.gridObj.rows[r].cells[c].onclick = this.onclickHandler
}
}
}
Now, when a cell on the grid is clicked, the new internal onclick
function fires - which is correct.
THE PROBLEM:
The alert(this.rows) in the internal onclick function shows "undefined"
because the "this" refers to the table cell element, not the grid object!
How do I get a reference to the grid object from that point ???
The obvious work-around is to use the external grid var directly but
apart from breaking the encapsulation when I have multiple grids I dont
know which one has been clicked since I cant reference anything about
the grid object itself.
The other solution is to set the id of each td element to contain the
grid number and use getElementById to get the reference, but I was
hoping to find an OOP way of doing it.
Any ideas ?
Thanks,
Murray