2

I'm trying to create a JavaScript object that creates a set of DOM elements (IMG tags to be specific) -- four functions (methods) are part of the object, one builds the group of icons, three are event handlers: Click, MouseOver, and MouseOut.

To properly define the event handlers, I need to know the name of the local variable that is the instance of my object, but can find no way to determine it.

In the web page:

...
var ip = new IconPicker(...)
...  </script> ...

<li><a href="#" onclick="ip.buildIt("daImageBox"); return false;">boB's Icon Picker</a> <div id="daImageBox" class="iconPickBox"  hidden></div> </li>

In the js file:

function IconPicker(...) { ... }

IconPicker.prototype.imageClicked = function(ctrl) { ... }

IconPicker.prototype.buildIt(divName) {
 ... "<img ... onClick='___.imageClicked(this)' ... />"

In this example, the ___ needs to be filled in with "ip" -- but how to determine that???

Assume there's a CSS file with the classes et al defined.

The uber-tricky part (or likely simple if one already knows the trick) is that all three handlers need a parameter that is the DOM instance of the clicked (or hovered) component.

This is communicated above with the 'this' parameter to the imageClicked() call -- but 'this' has a different meaning inside an object method, and what I'm slamming into is the dual-need in the same definition: I need this handler method to be sent 'this' parameter.

Granted, determining the name of the instance variable is a cheesy, hacky solution -- but it would solve the problem.

3
  • Are there other IconPicker instances for which a similar thing needs to be done? Can you post the context of where buildIt is invoked? Commented Jun 29, 2019 at 6:02
  • 1
    in almost every case, if a function or object needs to know the name of the variable to which it has been assigned, you're doing it wrong. Those variable names are for the benefit of the owner of the function / object who should be free to change those names (e.g. by copying to another varilable) without affecting the internals of it. Commented Jun 29, 2019 at 6:35
  • I've edited the question to approach both of your comments. If that helps produce a solution, or even a hint to push me in the right direction, that'd be great! Commented Jul 1, 2019 at 22:55

1 Answer 1

1

I suggest you create a DOM element rather than a string representation of the image element such that you can bind a click event to it using addEventListener():

IconPicker.prototype.buildIt = function(){
  this.icon = document.createElement('img');
  this.icon.src = this.url;
  this.icon.id = this.id;
  this.icon.alt = "A icon";
  var this_icon = this;
  this.icon.addEventListener('click', function() {
    this_icon.imageClicked();
  });
}

See example below:

function IconPicker(msg, url, id) {
  this.clickMessage = msg;
  this.url = url;
  this.id = id;
}

IconPicker.prototype.imageClicked = function() {
  console.log(this.clickMessage);
}

IconPicker.prototype.buildIt = function() {
  this.icon = document.createElement('img');
  this.icon.src = this.url;
  this.icon.id = this.id;
  this.icon.alt = "An icon";
  var this_icon = this;
  this.icon.addEventListener('click', function() {
    this_icon.imageClicked();
  });
}

IconPicker.prototype.addIcon = function(target) {
  target.appendChild(this.icon);
}

var myIcon = new IconPicker("Some click message", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS4eN1pqzmrn8pfD-g-LsTDigmkBY22rVSWSjV7n0FC7oILRqiAEw", "Icon 1 id");
myIcon.buildIt();
myIcon.addIcon(document.body);

var myNewIcon = new IconPicker("Some other message", "https://ih1.redbubble.net/image.316142692.7951/ap,550x550,12x12,1,transparent,t.png", "Icon 2 id");
myNewIcon.buildIt();
myNewIcon.addIcon(document.body);
img {
  height: 150px;
  width: 150px;
}

You can also achieve this a little easier/cleaner by using ES6 class syntax:

class IconPicker {
  constructor(msg, url, id) {
    this.clickMessage = msg;
    this.url = url;
    this.id = id;
  }

  imageClicked() {
    // access image DOM element that was been clicked using `this.icon` (ie: get id using `this.icon.id`
    console.log(this.icon.id);
    // action to perform when image is clicked
    console.log(this.clickMessage);
  }

  buildIt() {
    this.icon = document.createElement('img');
    this.icon.src = this.url;
    this.icon.id = this.id;
    this.icon.alt = "An icon";
    this.icon.addEventListener('click', _ => this.imageClicked());
  }

  addIcon(target) {
    if(!this.icon) // check preconditions
      throw Error("An icon must be built in order for it to be added");
      
    target.appendChild(this.icon);
  }
}

const myIcon = new IconPicker("Some click message", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS4eN1pqzmrn8pfD-g-LsTDigmkBY22rVSWSjV7n0FC7oILRqiAEw", "icon 1 id");
myIcon.buildIt();
myIcon.addIcon(document.body);

const myNewIcon = new IconPicker("Another click message", "https://ih1.redbubble.net/image.316142692.7951/ap,550x550,12x12,1,transparent,t.png", "icon 2 id");
myNewIcon.buildIt();
myNewIcon.addIcon(document.body);
img {
  height: 150px;
  width: 150px;
}

Sign up to request clarification or add additional context in comments.

5 Comments

This is a direction I tried to take ... the problem I ran into is that my click handler needs to know which control was clicked on (the control is on a repeating data line, the id of the control is required information). In similar cases, I've handled this by passing 'this' in the onClick call, which I can process within the function as the control (called ctrl in my example skeleton). But, of course, 'this' has a different meaning in this context. Other than that snag, this is my preferred method.
Is there some annotation I can use to get the handler called with a reference to the img tag that was clicked as it's parameter?
Oh, and I should add ... buildIt() creates a GRID of images, I need to know which one to highlight (Mouse Over), de-highlight (Mouse Out), or save (Click) -- thus the parameter to the event handlers.
@boB Hi, you can access the DOM element selected (ie img clicked) using this.icon. You can then go ahead and get/set its properties such as styles etc... (I've given an example of this in the 2nd snippet by getting the id attribute of the image clicked)
I like the idea, but this depends upon there being a member in the object with a reference to the one icon. That's not how this works. The IconPicker object presents several icons for the user to choose between, and I need to know which one they have clicked. One IconPicker object, multiple icons.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.