Nicholas Hazel Nicholas Hazel - 5 months ago 9
jQuery Question

Using data-attr to identify an active selection

I'll try to keep it at simple as I can.

I have a

JSON
object that is pulled via AJAX. I am displaying a list of icons in a
main div
from the data dynamically which can be toggled on or off.

I have a
secondary div
where the
selected
items are appearing, while the
main div
icon receives a class of
active
.

I want the end user to be able to remove any of them by clicking on them on either the
main div
or
secondary div
.

Most of this is working, but I'm having trouble figuring out the best way to map them together so that I have 2 separate
click events
which can control the same outcome.

I think it may have something to do with the fact that I'm dynamically creating elements... which create more elements... which have to alter the initial elements.

My structure so far is to map the current selection inside of an
array
. This gives me control over keeping a code-based list of everything that is selected (there is much more data than in the example I'll be providing).

So, here is how I have it so far:

HTML:

<div id="options"></div>
<div id="selectedOptions"></div>


Javascript/jQuery:

// Simple simulated AJAX data
var ourData = {
"color1": "yellow",
"color2": "blue"
};
var $options = $('#options');
var $selectedOptions = $('#selectedOptions');
// Array to keep track of which objects are selected
var selectedOptions = [];

// Makes the initial option dynamic list
makeOptions(ourData, $options);

// If an option from the main div is clicked, handle class changing
$('button').on('click', function(){
pickOption($(this));
});

/* This function is the problem. The option gets removed from the array, and from the secondary div, but the class of active still occurs on the main div. */
$selectedOptions.on('click', '.optionActive', function(){
var option = $(this).data('color');
var optionPosition = jQuery.inArray(option, selectedOptions);
selectedOptions.splice(optionPosition, 1);
displayOptions(selectedOptions, $selectedOptions);
});

// Creates initial icons (buttons in this case) to the DOM and applies a data-attribute for the color
function makeOptions(options, $container){
var $results = $('<div id="results">');
$.each(options, function(key, value){
var $optionButton = $('<button>' + key + ':' + value + '</button>');
$optionButton.data('color', value);
$results.append($optionButton);
});
$container.append($results);
}

/* Handler for selecting an option from the Main Div. Handling the class active.
I am not using a simple classToggle because there are many situations where a click is not allowed */
function pickOption($option){
var selectedOption = $option.data('color');
// If the option returns true, or that it doesn't exist yet
if(modifyOptions(selectedOption, selectedOptions)){
$option.addClass('active');
} else {
$option.removeClass('active');
}
// Recreate our current selected options
displayOptions(selectedOptions, $selectedOptions);
}

/* Searches array to see if the option exists. Returns true or false and either pushes or splices the option from the array */
function modifyOptions(option){
var optionPosition = jQuery.inArray(option, selectedOptions);
if(optionPosition == -1){
selectedOptions.push(option);
return true;
} else {
selectedOptions.splice(optionPosition, 1);
return false;
}
}

/* Displays all currently selected options that exist in our array */
function displayOptions(selectedOptions, $container){
$container.empty();
$.each(selectedOptions, function(option, value){
var $optionTile = $('<div class="optionActive">');
$optionTile.data('color', value)
.text(option + ":" + value)
.css('background', value);
$container.append($optionTile);
});
}


So, to summarize, I want some some way to remove the
.active
class from the
main div
equivalent element when the item from the
second div
is clicked.

I tried removing the class
active
by searching for any elements with the
data-color=data-color
of the selected item, but I couldn't get that to work.

ex:

$('*[data-color="' + $(this).data('color') + '"]').removeClass('active');


I would really like some
data
approach to this, such as removing the class active if it had
data-color="yellow"
for instance.

Playground:
https://jsfiddle.net/c75xcLha/

EDIT:

Both Are Selected, working as designed:
both selected, both displayed

Clicked Yellow Div. Yellow Button is still active:
yellow div clicked on (removed), but the option button remains active

Should remove the active class from the button when the yellow div OR the button is pressed, as shown here:
proper way it should display after clicking yellow div

Answer

You are assigning data property, not attribute hence element having data property could not be accessed using attribute-selector, assign attribute using .attr('data-color') instead of .data(property)

// Simple simulated AJAX data
var ourData = {
  "color1": "yellow",
  "color2": "blue"
};
var $options = $('#options');
var $selectedOptions = $('#selectedOptions');
// Array to keep track of which objects are selected
var selectedOptions = [];

// Makes the initial option dynamic list
makeOptions(ourData, $options);

// If an option from the main div is clicked, handle class changing
$('button').on('click', function() {
  pickOption($(this));
});

/* This function is the problem. The option gets removed from the array, and from the secondary div, but the class of active still occurs on the main div. */
$selectedOptions.on('click', '.optionActive', function() {
  var option = $(this).data('color');
  var optionPosition = jQuery.inArray(option, selectedOptions);
  selectedOptions.splice(optionPosition, 1);
  $('[data-color="' + $(this).data('color') + '"]').removeClass('active');
  displayOptions(selectedOptions, $selectedOptions);
});

// Creates initial icons (buttons in this case) to the DOM and applies a data-attribute for the color
function makeOptions(options, $container) {
  var $results = $('<div id="results">');
  $.each(options, function(key, value) {
    var $optionButton = $('<button>' + key + ':' + value + '</button>');
    $optionButton.attr('data-color', value);
    //___________^^^^^^^^^^^^^^^^^^Little trick here!
    $results.append($optionButton);
  });
  $container.append($results);
}

/* Handler for selecting an option from the Main Div. Handling the class active.
I am not using a simple classToggle because there are many situations where a click is not allowed */
function pickOption($option) {
  var selectedOption = $option.data('color');
  // If the option returns true, or that it doesn't exist yet
  if (modifyOptions(selectedOption, selectedOptions)) {
    $option.addClass('active');
  } else {
    $option.removeClass('active');
  }

  // Recreate our current selected options
  displayOptions(selectedOptions, $selectedOptions);
}

/* Searches array to see if the option exists. Returns true or false and either pushes or splices the option from the array */
function modifyOptions(option) {
  var optionPosition = jQuery.inArray(option, selectedOptions);
  if (optionPosition == -1) {
    selectedOptions.push(option);
    return true;
  } else {
    selectedOptions.splice(optionPosition, 1);
    return false;
  }
}

/* Displays all currently selected options that exist in our array */
function displayOptions(selectedOptions, $container) {
  $container.empty();
  $.each(selectedOptions, function(option, value) {
    var $optionTile = $('<div class="optionActive">');
    $optionTile.data('color', value)
      .text(option + ":" + value)
      .css('background', value);
    $container.append($optionTile);
  });
}
.active {
  background: #CCF;
}
.optionActive {
  min-width: 100px;
  min-height: 100px;
  display: inline-block;
  margin: 1em;
  background: #eee;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="options">

</div>

<div id="selectedOptions">

</div>

Updated Fiddle