MitchCool1
MitchCool1

Reputation: 329

Selecting images in HTML

I have a grid of images which is echoed out as HTML from a PHP function. The images currently have an onclick() function which adds a value linked to the image to a universal value. EG: universalInt += imageInt;

What I want to do is, when the image is clicked, have some kind of variable show that the image is selected, and when it is clicked again it is unselected. I want this so the onclick() function can work like this:

    if(selected){ 
    universalInt += imageInt;
    //append item to array
} 
    else if (!selected){ 
    universalInt -= imageInt; 
    //remove item from array
}

I've been looking around but I can't find anything, is there a simple way to add a "selected"-like variable to a HTML image? I would prefer not to use an add-on.

Upvotes: 2

Views: 696

Answers (2)

David Thomas
David Thomas

Reputation: 253308

I'd suggest the following approach:

function select(opts) {

  // caching the clicked element for later (repeated) use:    
  var clicked = this,

  // setting the default settings:
    defaults = {
      'element': 'img',
      'selectedAttribute': 'data-selected',
      'markParent': true,
      'parentAttribute': 'data-childSelected',
      'parentMarker': '✓'
    };

  // finding the currently-selected elements (if any) and, if
  // any are found, converting that NodeList to an Array,
  // otherwise using an empty array:    
  var selected = Array.prototype.slice.call(document.querySelectorAll(defaults.element + '[' + defaults.selectedAttribute + ']'), 0).length ? Array.prototype.slice.call(document.querySelectorAll(defaults.element + '[' + defaults.selectedAttribute + ']'), 0) : [];

  // discovering whether the clicked element is already
  // in the array (if it's already selected):
  isSelected = selected.indexOf(clicked) > -1;

  // if it's in the array already, we want to de-select:
  if (isSelected) {

    // we de-select by removing the relevant attribute:
    clicked.removeAttribute(defaults.selectedAttribute);

    // if the settings indicate that the parent is also
    // marked:
    if (defaults.markParent === true) {

      // we remove the parent's 'marking' attribute also:
      clicked.parentNode.removeAttribute(defaults.parentAttribute);
    }
  } else {

    // otherwise we set the 'marking' attribute on the 
    // clicked element (to true), and:
    clicked.setAttribute(defaults.selectedAttribute, true);

    // if we're to mark the parent also:
    if (defaults.markParent === true) {

      // we set the parent-marking attribute to the string
      // held in the given variable, for use in the CSS (later):
      clicked.parentNode.setAttribute(defaults.parentAttribute, defaults.parentMarker);
    }
  }

  // here we return the (new) NodeList of selected elements:
  return document.querySelectorAll(defaults.element + '[' + defaults.selectedAttribute + ']');
}

// converting the NodeList of <img> elements to an array:    
var images = Array.prototype.slice.call(document.querySelectorAll('img'), 0);

// iterating over that array with Array.prototype.forEach(),
// the first argument to forEach() (here: 'img') is the
// current array-element of the array over we're iterating:
images.forEach(function(img) {

  // binding the select() function to handle the 'click' event
  // on the given element-node:
  img.addEventListener('click', select);
});

function select(opts) {

  var clicked = this,
    defaults = {
      'element': 'img',
      'selectedAttribute': 'data-selected',
      'markParent': true,
      'parentAttribute': 'data-childSelected',
      'parentMarker': '✓'
    };

  var selected = Array.prototype.slice.call(document.querySelectorAll(defaults.element + '[' + defaults.selectedAttribute + ']'), 0).length ? Array.prototype.slice.call(document.querySelectorAll(defaults.element + '[' + defaults.selectedAttribute + ']'), 0) : [];
  isSelected = selected.indexOf(clicked) > -1;

  if (isSelected) {
    clicked.removeAttribute(defaults.selectedAttribute);
    if (defaults.markParent === true) {
      clicked.parentNode.removeAttribute(defaults.parentAttribute);
    }
  } else {
    clicked.setAttribute(defaults.selectedAttribute, true);
    if (defaults.markParent === true) {
      clicked.parentNode.setAttribute(defaults.parentAttribute, defaults.parentMarker);
    }
  }

  return document.querySelectorAll(defaults.element + '[' + defaults.selectedAttribute + ']');
}

var images = Array.prototype.slice.call(document.querySelectorAll('img'), 0);

images.forEach(function(img) {
  img.addEventListener('click', select);
});
ul,
li {
  list-style-type: none;
  margin: 0;
  padding: 0;
}
li {
  height: 100px;
  width: 100px;
  display: inline-block;
  position: relative;
}
li[data-childSelected]::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  border: 5px solid rgba(255, 190, 0, 0.5);
  pointer-events: none;
}
li[data-childSelected]::after {
  content: attr(data-childSelected);
  position: absolute;
  top: 5px;
  right: 5px;
  width: 2em;
  height: 2em;
  background-color: rgba(255, 190, 0, 0.5);
  border-radius: 0 0 0 1em;
  color: #fff;
  font-weight: bold;
  text-align: center;
  text-shadow: 0 0 4px #000;
  line-height: 2em;
}
#selected::before {
  content: 'Selected images: '
}
#selected:empty::before {
  content: '';
}
<div id="selected"></div>
<ul>
  <li>
    <img src="http://lorempixel.com/100/100/people/1" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/2" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/3" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/4" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/5" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/6" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/7" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/8" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/9" />
  </li>
</ul>

External JS Fiddle demo, for experimentation.

Alternatively, to use the returned NodeList we can call the exact same function in the following way (the unchanged function omitted here for brevity, but it's in the Snippet and external Fiddle):

images.forEach(function(img) {
  img.addEventListener('click', function() {

    // setting the textContent of the selected Node
    // to the length of the returned NodeList:
    document.getElementById('selected').textContent = select.apply(img).length;
    // above we use Function.prototype.apply() to
    // explicitly set the select() function's 'this'
  });
});

function select(opts) {

  var clicked = this,
    defaults = {
      'element': 'img',
      'selectedAttribute': 'data-selected',
      'markParent': true,
      'parentAttribute': 'data-childSelected',
      'parentMarker': '✓'
    };

  var selected = Array.prototype.slice.call(document.querySelectorAll(defaults.element + '[' + defaults.selectedAttribute + ']'), 0).length ? Array.prototype.slice.call(document.querySelectorAll(defaults.element + '[' + defaults.selectedAttribute + ']'), 0) : [];
  isSelected = selected.indexOf(clicked) > -1;

  if (isSelected) {
    clicked.removeAttribute(defaults.selectedAttribute);
    if (defaults.markParent === true) {
      clicked.parentNode.removeAttribute(defaults.parentAttribute);
    }
  } else {
    clicked.setAttribute(defaults.selectedAttribute, true);
    if (defaults.markParent === true) {
      clicked.parentNode.setAttribute(defaults.parentAttribute, defaults.parentMarker);
    }
  }

  return document.querySelectorAll(defaults.element + '[' + defaults.selectedAttribute + ']');
}

var images = Array.prototype.slice.call(document.querySelectorAll('img'), 0);

images.forEach(function(img) {
  img.addEventListener('click', function(e) {
    document.getElementById('selected').textContent = select.apply(img).length;
  });
});
ul,
li {
  list-style-type: none;
  margin: 0;
  padding: 0;
}
li {
  height: 100px;
  width: 100px;
  display: inline-block;
  position: relative;
}
li[data-childSelected]::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  border: 5px solid rgba(255, 190, 0, 0.5);
  pointer-events: none;
}
li[data-childSelected]::after {
  content: attr(data-childSelected);
  position: absolute;
  top: 5px;
  right: 5px;
  width: 2em;
  height: 2em;
  background-color: rgba(255, 190, 0, 0.5);
  border-radius: 0 0 0 1em;
  color: #fff;
  font-weight: bold;
  text-align: center;
  text-shadow: 0 0 4px #000;
  line-height: 2em;
}
#selected::before {
  content: 'Selected images: '
}
#selected:empty::before {
  content: '';
}
<div id="selected"></div>
<ul>
  <li>
    <img src="http://lorempixel.com/100/100/people/1" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/2" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/3" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/4" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/5" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/6" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/7" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/8" />
  </li>
  <li>
    <img src="http://lorempixel.com/100/100/people/9" />
  </li>
</ul>

External JS Fiddle demo, for experimentation.

References:

Upvotes: 1

ankur
ankur

Reputation: 157

In your onclick callback you can do something like this

function onCLickCallback() {
    if(selected){
      selected = false;
    }
    else {
      selected = true;
    }

    if(selected){ 
        universalInt += imageInt;
        //append item to array
    } 
        else if (!selected){ 
        universalInt -= imageInt; 
        //remove item from array
    }
}

Upvotes: 0

Related Questions