简体   繁体   中英

When I reference a parameter of an object inside of an event handler, the parameter is always null even when it's set to an object

it's my first Stack Overflow question as I usually find my answers upon googling, so bear with me...

I'm working on a project that involves heavy manipulation of canvas elements. To do this, I have imported and used jQuery and jCanvas. I am also writing the code in ECMAScript 6. For easier logging methods, I'm using loglevel (hence "log.debug" and "log.info" etc., instead of "console.log").

Currently, my problem is with the event handlers having some weird interactions with an object I use for storing data about each canvas. Basically, in my mousedown and mousemove handlers, I'm using the getCanvasData function to retrieve the data object for that certain canvas, which I apparently successfully retrieve, but when I access the "dragged" parameter, it's always null. In other parts of the code, I change that value to an object successfully, but whenever the event handlers access it, it's still null no matter what. I have tested whether it really is null by making a getter and setter for the property that prints out its state as it changes (I provided that snippet of code at the end, it's a replacement for the 'data' assignment in getCanvasData function).

If you'd like to see the full code in its current form, you can view my project where I'm currently hosting it . It's a live version, which means that it's synched with my working environment. As I modify something at home, it's going to update the website (so in case you come from the future - it's probably either down or completely different).

On the website, the move handler is supposed to be responsible for moving one end of a wire/connector when you spawn one (by clicking on one of the inputs or outputs). Since the handler can't retrieve 'dragged', the wire will never follow the mouse. However, when you click on another input/output (keep in mind that inputs only connect to outputs and vice versa) it'll connect the wire between them - that action is performed by accessing the 'dragged' property ('dragged' being a reference to the wire itself) and performing an action on it. Since you can connect the wire, it means 'dragged' is successfully referenced outside of the handler, but not inside of it.

getCanvasData() function:

var canvasData = []; // (among other declarations)

function getCanvasData(canvas) {
    var data, i, tmp;
    // Retrieve the stored data
    for (i = 0; i < canvasData.length; i++) {
        tmp = canvasData[i];
        if (canvas === tmp.canvas) {
            // We got the data for our canvas!
            data = tmp;
            // We no longer need to go through the rest of the list, let's break out of the loop
            break;
        }
    }
    // Check if we got anything back
    if (!data) {
        // No data for this canvas is stored yet. We need to initialize it!
        log.info("New canvas data set is being created. Index: " + canvasData.length);
        data = {
            canvas: canvas, // The canvas this data belongs to
            gates: [],      // An array of all the logic gates on the canvas
            wires: [],      // An array of all the wires on the canvas
            spawners: [],   // An array of all the spawners on the canvas
            dragged: null,  // Currently dragged wire which should follow our mouse
            gateWidth: GATE_WIDTH,  // Width of all logic gates on this canvas
            gateHeight: GATE_HEIGHT // Height of all logic gates on this canvas
        };
        // Store the data in our storage.
        canvasData.push(data);
    }
    return data;
}

Part of the code I assign the different handlers to all canvases of a certain class:

var canvasList = $('.logicExercise'), canvas;

/* some code */

// Initialize each canvas
canvasList.each(function (i, obj) {
    canvas = $(this);
    // Initialize the data stored for the canvas
    getCanvasData(canvas);
    // Draw the UI for the canvas
    drawUI(canvas);
    // Assign mouse handlers (for spawning new wires)
    canvas.mousemove(function(event) {
        mouseMoveHandler(event, canvas);
    });
    canvas.mousedown(function(event) {
        mouseDownHandler(event, canvas);
    });
    // Prevent right-click from firing up the context menu when over the canvas
    canvas.bind('contextmenu', function(e){
        e.preventDefault();
        return false;
    });
});

The mousedown and mousemove handlers:

function mouseMoveHandler(event, canvas) {
    var x = event.pageX - canvas.offset().left,
        y = event.pageY - canvas.offset().top,
        data = getCanvasData(canvas);
    if (data.dragged) {    // <--- ALWAYS NULL, AND THEREFORE FAILS
        if (data.dragged.inputs[0].type) {
            data.dragged.outputs[0].x = x;
            data.dragged.outputs[0].y = y;
            data.dragged.updateCoords();
        } else {
            data.dragged.inputs[0].x = x;
            data.dragged.inputs[0].y = y;
            data.dragged.updateCoords();
        }
    }
}

function mouseDownHandler(event, canvas) {
    var data = getCanvasData(canvas);
    if (event.which === 3) {
        // Right click detected!
        if (data.dragged) {    // <--- ALWAYS NULL, AND THEREFORE FAILS
            // We are dragging something! Right click means we need to remove it.
            data.dragged.remove();
            data.dragged = null;
        }
    }
}

Snippet of code I used to check the state of 'dragged' as it changes:

data = {
    canvas: canvas, // The canvas this data belongs to
    gates: [],      // An array of all the logic gates on the canvas
    wires: [],      // An array of all the wires on the canvas
    spawners: [],   // An array of all the spawners on the canvas
    gateWidth: GATE_WIDTH,  // Width of all logic gates on this canvas
    gateHeight: GATE_HEIGHT,// Height of all logic gates on this canvas
    _dragged: null,
    set dragged(obj) {
        log.info("'dragged' is changing to '" + obj + "'.");
        this._dragged = obj;
    },
    get dragged() {
        log.info("'dragged' is being retrieved when it's '" + this._dragged + "'.");
        return this._dragged;
    }
};

When the above code is in effect, I get a printout informing me that 'dragged' changed to 'Object object', but then when I move the mouse (to trigger mousemove event) I get a printout telling me it's 'null' (not even undefined). When some other part of my project uses it, it uses it successfully and actually retrieves the object.

You should be using if (canvas[0] === tmp.canvas[0]) to reference the actual canvas objects, and not the jQuery selectors being passed in to getCanvasData() .

When you are checking if (canvas === tmp.canvas) you are checking jQuery selectors, not than the actual canvas object. So, in one place you may be passing $("canvas#foo") and somewhere else you are passing $("canvas .foo") which have different contexts and won't == each other.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM