J S
J S

Reputation: 3496

Applying an Event Handler to a Variable

Is there a way to apply an event handler to a variable, or does it need to be done with hidden inputs and the like? I've got a variable being set:

var c = document.getElementById('myCanvas');
c.myVar = 17;

And I'd like to set up an event handler for it in case it ever changes, saving a superfluous hidden input being created and changed and just generally streamlining my code.

Thanks!

Upvotes: 0

Views: 63

Answers (2)

Xitalogy
Xitalogy

Reputation: 1612

To illustrate what you want you could define getters and setters on the object properties with a call to the desired function:

HTML:

<canvas id="myCanvas" class="border"></canvas>

JavaScript:

var x = 0,
    y = 0,
    c = document.getElementById('myCanvas'),
    ctx = c.getContext('2d'),
    WIDTH = c.width,
    HEIGHT = c.height,
    paint = function () {
        ctx.clearRect(0, 0, WIDTH, HEIGHT);
        ctx.beginPath();
        ctx.rect(x, y, 6, 6);
        ctx.closePath();
        ctx.fill();
    };

Object.defineProperty(c, 'x', {
    get: function () {
        return x;
    },
    set: function (value) {
        x = value;
        paint();
    }
});

Object.defineProperty(c, 'y', {
    get: function () {
        return y;
    },
    set: function (value) {
        y = value;
        paint();
    }
});

window.setInterval(function () {
    var dx = Math.round(Math.random() * 6) - 3,
        dy = Math.round(Math.random() * 6) - 3;

    if (c.x + dx > 0 && c.x + dx < c.width) {
        c.x += dx;
    }

    if (c.y + dy > 0 && c.y + dy < c.height) {
        c.y += dy;
    }
}, 20);

CSS:

canvas.border {
    border-style: solid;
    border-color: 0;
}

FIDDLE

NOTE: The solution above is used to illustrate a point to answer the specific question. It does not do a good job of solving the desire for a self-drawing object. This is because I call paint from two places (whenever x or y change). If you are always changing x and y, you do twice the painting. A better way is to change x, change y and any other state changes needed then call a paint method on the object to have it paint itself.

This does do a good job of illustrating the problem with this type of model, so it has value in showing a pitfall one can get into when doing things this way. Therefore, I have left the code as is with this note.

I have done a new version of this that shows what I believe is a better way to do this in the following code. Only the JavaScript has changed:

JavaScript:

function DrunkBox(x, y) {
    'use strict';

    var c = document.getElementById('myCanvas'),
        ctx = c.getContext('2d');

    this.width = c.width;
    this.height = c.height;

    this.x = x,
    this.y = y;

    this.paint = function () {
        ctx.clearRect(0, 0, this.width, this.height);
        ctx.beginPath();
        ctx.rect(this.x, this.y, 6, 6);
        ctx.closePath();
        ctx.fill();
    };
}

var db = new DrunkBox(50, 30);

window.setInterval(function () {
    var dx = Math.round(Math.random() * 6) - 3,
        dy = Math.round(Math.random() * 6) - 3;

    if (db.x + dx > 0 && db.x + dx < db.width) {
        db.x += dx;
    }

    if (db.y + dy > 0 && db.y + dy < db.height) {
        db.y += dy;
    }
    db.paint();
}, 20);

FIDDLE

Upvotes: 0

struthersneil
struthersneil

Reputation: 2750

If you want to hook a change in an attribute of a DOM element, you probably want to look into DOM Mutation events. It feels like overkill though--I would just wrap all accesses to that attribute in a function and then call whatever I like from inside that function. You'd just make sure you always used that function to access the attribute.

Upvotes: 1

Related Questions