Reputation: 2017
The linked snippet is just a rough example of what I'm doing but will demonstrate the issue I'm having. I have two select boxes that I can transfer items between. I need to track when an item has moved from its original box for when I submit changes through an ajax call later because I don't want to include the entire list in the transmission, only whats necessary. (my real data is much larger lists)
To keep track, I'm using a data attribute, "data-changed". And to help reflect what's been flagged for updating, I toggle a class on that particular option. This all works fine and dandy. My problem is when I try to implement sorting on these lists. The options get sorted as expected but it seems like it's losing its data attribute in the process, which breaks the other stuff. I can't figure out how to fix this.
https://jsfiddle.net/bnLfhpq4/
$('#btnSubmit').click(function(e) {
e.preventDefault();
var arr = new Array();
// get options from active list
var options = $('#activeList option');
options.each(function(i, o) {
if ($(o).data('changed') == "yes") {
var skill = {
id: $(o).val(),
active: 0
}
arr.push(skill);
}
});
// get options from inactive list
var options = $('#inactiveList option');
options.each(function(i, o) {
if ($(o).data('changed') == "yes") {
var skill = {
id: $(o).val(),
active: 1
}
arr.push(skill);
}
});
console.log(arr);
});
$('#btn_in').click(function() {
var options = $('#activeList option:selected');
options.each(function(i, o) {
var c = $(o).data('changed');
if (c == "yes") {
$(o).data('changed', 'no');
$(o).removeClass('flagged');
} else {
$(o).data('changed', 'yes');
$(o).addClass('flagged');
}
});
$('#inactiveList').append(options);
//sortOptions('#inactiveList');
});
$('#btn_out').click(function() {
var options = $('#inactiveList option:selected');
options.each(function(i, o) {
var c = $(o).data('changed');
if (c == "yes") {
$(o).data('changed', 'no');
$(o).removeClass('flagged');
} else {
$(o).data('changed', 'yes');
$(o).addClass('flagged');
}
});
$('#activeList').append(options);
sortOptions('#activeList');
});
function sortOptions(selector) {
var options = $(selector + ' option');
options.sort(function(a, b) {
if (a.text > b.text) return 1;
if (a.text < b.text) return -1;
return 0;
});
$(selector).empty().append(options);
}
.superSelect {
min-height: 200px;
}
.buttons {
display: inline-block
}
.flagged {
color: red
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select multiple id="activeList" class="superSelect">
<option value="t1" data-changed="no">Option 1</option>
<option value="t2" data-changed="no">Option 2</option>
<option value="t3" data-changed="no">Option 3</option>
<option value="t4" data-changed="no">Option 4</option>
</select>
<div class="buttons">
<button id="btn_in">>>></button><br/><br/>
<button id="btn_out"><<<</button>
</div>
<select multiple id="inactiveList" class="superSelect">
<option value="x1" data-changed="no">Thingy 1</option>
<option value="x2" data-changed="no">Thingy 2</option>
<option value="x3" data-changed="no">Thingy 3</option>
<option value="x4" data-changed="no">Thingy 4</option>
</select>
<br/>
<button id="btnSubmit">Submit</button>
Upvotes: 0
Views: 121
Reputation: 10879
A very good explanation of why not to mix data-
attributes and data()
has already been given in this answer. Therefore, change everything to use .attr('data-changed')
and it will work.
The reason it worked without the ordering functionality is because the association between the data that jQuery stores internally and the DOM node is apparently lost when the node is removed from the DOM via empty()
and re-added via append()
.
[data-changed="yes"]
in your CSS.<
and >
characters (in your button labels) without encoding them as HTML entities <
/>
. Although all major browsers should render the buttons just fine, there is a chance that a client's parser might get confused and lead to some display issues.$('#btnSubmit').click(function(e) {
e.preventDefault();
var arr = new Array();
// get options from active list
var options = $('#activeList option');
options.each(function(i, o) {
if ($(o).data('changed') == "yes") {
var skill = {
id: $(o).val(),
active: 0
}
arr.push(skill);
}
});
// get options from inactive list
var options = $('#inactiveList option');
options.each(function(i, o) {
if ($(o).data('changed') == "yes") {
var skill = {
id: $(o).val(),
active: 1
}
arr.push(skill);
}
});
console.log(arr);
});
$activeList = $('#activeList');
$inactiveList = $('#inactiveList');
function moveOptions() {
var $otherList = this === $activeList ? $inactiveList : $activeList;
var options = $('option:selected', this);
options.each(function(i, o) {
var c = $(o).data('changed');
if (c == "yes") {
$(o).attr('data-changed', 'no');
} else {
$(o).attr('data-changed', 'yes');
}
});
$otherList.append(options);
sortOptions($otherList);
}
$('#btn_in').click(moveOptions.bind($activeList));
$('#btn_out').click(moveOptions.bind($inactiveList));
function sortOptions(list) {
var options = $('option', list);
options.sort(function(a, b) {
if (a.text > b.text) return 1;
if (a.text < b.text) return -1;
return 0;
});
list.empty().append(options);
}
.superSelect {
min-height: 200px;
}
.buttons {
display: inline-block
}
[data-changed="yes"] {
color: red
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<select multiple id="activeList" class="superSelect">
<option value="t1" data-changed="no">Option 1</option>
<option value="t2" data-changed="no">Option 2</option>
<option value="t3" data-changed="no">Option 3</option>
<option value="t4" data-changed="no">Option 4</option>
</select>
<div class="buttons">
<button id="btn_in">>>></button><br/><br/>
<button id="btn_out"><<<</button>
</div>
<select multiple id="inactiveList" class="superSelect">
<option value="x1" data-changed="no">Thingy 1</option>
<option value="x2" data-changed="no">Thingy 2</option>
<option value="x3" data-changed="no">Thingy 3</option>
<option value="x4" data-changed="no">Thingy 4</option>
</select>
<br/>
<button id="btnSubmit">Submit</button>
Upvotes: 2