Click on the x in the SelectPicker element - javascript

var selectedTags = [];
var selectedTags2 = [];
if (d && d.length) {
d.forEach(function(value, index, array) {
if (index < 5) {
var color = $('option[value="' + value + '"]').data('color');
var tagSpan = '<span class="label label-' + color + '" style="margin-right:1px;"><span class="icon icon-times">' + value + '</span></span>';
selectedTags.push(tagSpan);
list = [];
c = 1;
} else {
var color2 = $('option[value="' + value + '"]').data('color');
var tagSpan2 = '<span class="label label-' + color2 + '" style="margin-right:1px;"><span class="icon icon-times">' + value + '</span></span>';
selectedTags2.push(tagSpan2);
list.push(tagSpan2);
}
});
}
var allTagsElement = selectedTags.join('');
if (a <= 0) {
return "<div class='col-md-11 col-xs-10' style='padding-left:0px;'> " + allTagsElement + " </div><div class='col-md-1 col-xs-2'id='eSecim'></div>";
}
return "<div class='col-md-10 col-xs-10' style='padding-left:0px;'> " + allTagsElement + " </div><div class='col-md-1 col-xs-2'id='eSecim'>+" + (-a) + "</div>";
I want to get out of here.
I use the bootstrap selectpicker. I will select it by clicking on the x next to the elements.

Related

Toggle function problem, What am I doing wrong?

I've created a comment system that posts comments in an ordered list. My requirememnts were to add hide/show toggle function to each comment.
Currently, the toggle function only works on the first comment (even when you try to click on 2nd, 3rd, etc.)
I've tried to use querySelectAll, but it didn't work for me. What am I doing wrong?
<div class="textbox">
<h3>Leave comments</h3>
<label for=msg>Name</label><br>
<input type=text id=fname> <br>
<label for=msg>Content</label><br>
<textarea id=msg> </textarea>
<br>
<input type=button onclick="postcomments()" value="Send" />
<input type="reset" value="Reset" />
<ol id="showcomments" style="max-width:200px; font-size:12px; padding-left:10px;">
</ol>
</div>
<script>
var ans = [];
function postcomments() {
var fname = document.getElementById("fname").value;
var msg = document.getElementById("msg").value;
var lastpos = ans.length;
var current = new Date();
console.log(current);
var time = current.getHours() + ":" + (current.getMinutes() < 10 ? '0' : '') + current.getMinutes();
var date = current.getDate() + "." + (current.getMonth() + 1) + "." + current.getFullYear();
var i = 0;
ans[lastpos] = '<img src="Media/minusicon.png" alt="minusicon" onclick="toggle(document.getElementById("txt&quot))" style="width:8%;" id="plusminusicon">' + " " + "Sent By" + " " + '' + fname + '' + " " + " In" + " " + date + " " + "At" + " " + time + '<br>' + '<span id="txt" class="toggle_panel">' + msg + '</span>' + '<br>' + '-------------------------------';
var ol = document.getElementById("showcomments");
ol.innerHTML = "";
for (var i = 0; i < ans.length; i++) {
ol.innerHTML += "<li id=" + (i + 1) + ">" + ans[i] + "</li>";
}
}
function toggle(x) {
if (x.style.display === "none") {
x.style.display = "block";
document.getElementById("plusminusicon").src = "Media/minusicon.png";
} else {
x.style.display = "none";
document.getElementById("plusminusicon").src = "Media/plusicon.png";
}
}
</script>
You have always the same id for all "txt" span, so the browser change always the first.
If you don't want change much of your code the simpliest solution is add the lastpost variable to the span id and to the parameter of toggle function.
Here the changes to do:
ans[lastpos] = '<img src="Media/minusicon.png" alt="minusicon" onclick="toggle(' + lastpos + ')" style="width:8%;" id="plusminusicon' + lastpos + '">' + " " + "Sent By" + " " + '' + fname + '' + " " + " In" + " " + date + " " + "At" + " " + time + '<br>' + '<span id="txt' + lastpos + '" class="toggle_panel">' + msg + '</span>' + '<br>' + '-------------------------------';
function toggle(x) {
let comment = document.getElementById("txt" + x);
let icon = document.getElementById("plusminusicon" + x);
if (comment.style.display === "none") {
comment.style.display = "block";
icon.src = "Media/minusicon.png";
} else {
comment.style.display = "none";
icon.src = "Media/plusicon.png";
}
}
To bind click listeners to dynamically added elements, you can use event delegation.
document.addEventListener('click', function(e) {
if (e.target && e.target.classList.contains('comment')) {
// do something
}
})
jQuery makes it even easier.
$(document).on('click','.comment',function(){ //do something })
And here's a jsfiddle link to the complete code example. https://jsfiddle.net/ep2bnu0g/

Transform + transition (rotate) an Image by x degrees

i have an arrow image, which i want to turn according to a degree value I get in javascript (g_drivers[i].heading) .
<img class="dir_img" style="transform: rotate(' + g_drivers[i].heading + 'deg)" src="' + dir_img + '">
This is working fine. I get a degree value every 3 seconds or so and the image rotates by that value.
I would now like a smooth transition when the degree changes every 3 seconds or so.
The CSS must look something like this...
.dir_img {
transition: transform 2s;
}
For some reason the .dir_img class is not catching that transition.
I am adding elements in the following manner:
I am creating the HTML out of JavaScript variables:
var html = '<img class="dir_img" style="transform: rotate(' + g_drivers[i].heading + 'deg)" src="' + dir_img + '">'
and then I append this like this:
document.getElementById('sidebar-scroll').innerHTML = html;
And this for some reason isn't working.
Here is the function, where I added Kosh Very's code, but it is still not working:
function displayDriversInSidebar() {
var countM = 0; //Moving
var countS = 0; //Standing
var countI = 0; //Inaktiv (no_signal = 1)
var countO = 0; //Offline (online = 0)
var activeCSS = '';
var status_img;
var dir_img;
var movingDrivers = '<tbody class="sidebar_header"><tr><td>In Bewegung<span id="moving_counter">0</span></td></tr></tbody><tbody>';
var standingDrivers = '<tbody class="sidebar_header"><tr><td>Steht <span id="standing_counter">0</span></td></tr></tbody><tbody>';
var inactiveDrivers = '<tbody class="sidebar_header"><tr><td>Inaktiv <span id="inactive_counter">0</span></td></tr></tbody><tbody>';
var offlineDrivers = '<tbody class="sidebar_header"><tr><td>Offline <span id="offline_counter">0</span></td></tr></tbody><tbody>';
for (var i = 0; i < g_drivers.length; i++) {
if (g_drivers[i].updated == 'yes') {
status_img = 'images/sidebar/signal3.png';
} else if (g_drivers[i].updated == 'waiting') {
status_img = 'images/sidebar/signal2.png';
} else if (g_drivers[i].updated == 'NA') {
status_img = 'images/sidebar/signal1.png';
} else {
status_img = 'images/sidebar/signal0.png';
}
if (g_drivers[i].heading === 0 || isNaN(g_drivers[i].heading) === true || g_drivers[i].headingOldCounter >= 30) {
dir_img = 'images/sidebar/no_dir.png';
} else {
dir_img = 'images/sidebar/arrow.png';
}
if (g_activeID == g_drivers[i].uuid) {
activeCSS = ' active';
} else {
activeCSS = '';
}
if (g_drivers[i].online === true) {
if (g_drivers[i].headingOldCounter >= 30 && g_drivers[i].no_signal == 0){
g_drivers[i].heading = 0;
countS += 1;
standingDrivers += '<tr id="' + g_drivers[i].uuid + '" class="sidebar_row' + activeCSS + '" onclick="changeTableRowColor(this.id);openInfo(' + i + ');"><td>' +
'<div class="row_container">' +
'<div class="driver_img"><img class="driver" src="images/drivers/' + g_drivers[i].img + '"></div>' +
'<div class="driver_name">' + g_drivers[i].nachname + ', ' + g_drivers[i].vorname + '</div>' +
'<div id="driver_info" class="driver_info"><img class="signal_img" src="' + status_img + '"></div>' +
//'<img class="dir_img" style="transform: rotate(' + g_drivers[i].heading + 'deg);" src="' + dir_img + '">' +
'<img id="img_' + g_drivers[i].uuid + '" class="dir_img" src="' + dir_img + '">' +
'</div>' +
'</td></tr>';
} else if (g_drivers[i].no_signal == 1) {
countI += 1;
inactiveDrivers += '<tr id="' + g_drivers[i].uuid + '" class="sidebar_row' + activeCSS + '" onclick="changeTableRowColor(this.id);openInfo(' + i + ');"><td>' +
'<div class="row_container">' +
'<div class="driver_img"><img class="driver" src="images/drivers/' + g_drivers[i].img + '"></div>' +
'<div class="driver_name">' + g_drivers[i].nachname + ', ' + g_drivers[i].vorname + '</div>' +
'<div id="driver_info" class="driver_info"></div>' +
'' +
'</div>' +
'</td></tr>';
} else {
countM += 1;
movingDrivers += '<tr id="' + g_drivers[i].uuid + '" class="sidebar_row' + activeCSS + '" onclick="changeTableRowColor(this.id);openInfo(' + i + ');"><td>' +
'<div class="row_container">' +
'<div class="driver_img"><img class="driver" src="images/drivers/' + g_drivers[i].img + '"></div>' +
'<div class="driver_name">' + g_drivers[i].nachname + ', ' + g_drivers[i].vorname + '</div>' +
'<div id="driver_info" class="driver_info"><img class="signal_img" src="' + status_img + '"></div>' + //<p class="img__description">' + timeConverter(g_drivers[i].signal_time) + '</p>
//'<img class="dir_img" style="transform: rotate(' + g_drivers[i].heading + 'deg);" src="' + dir_img + '">' +
'<img id="img_' + g_drivers[i].uuid + '" style="transition: transform 2s;" src="' + dir_img + '">' +
'</div>' +
'</td></tr>';
}
} else if (g_drivers[i].online === false) {
countO += 1;
offlineDrivers += '<tr id="' + g_drivers[i].uuid + '" class="sidebar_row' + activeCSS + '" onclick="changeTableRowColor(this.id);openInfo(' + i + ');"><td>' +
'<div class="row_container">' +
'<div class="driver_img"><img class="driver" src="images/drivers/' + g_drivers[i].img + '"></div>' +
'<div class="driver_name">' + g_drivers[i].nachname + ', ' + g_drivers[i].vorname + '</div>' +
'<div class="driver_info"> </div>' +
'</div>' +
'</td></tr>';
} else {
console.log('Hier darf eigentlich nix passieren');
}
}
movingDrivers += '</tbody>';
inactiveDrivers += '</tbody>';
standingDrivers += '</tbody>';
offlineDrivers += '</tbody>';
document.getElementById('sidebar-scroll').innerHTML = '<table class="sidebar_table">' + movingDrivers + standingDrivers + inactiveDrivers + offlineDrivers + '</table>';
document.getElementById('moving_counter').innerHTML = countM;
document.getElementById('standing_counter').innerHTML = countS;
document.getElementById('inactive_counter').innerHTML = countI;
document.getElementById('offline_counter').innerHTML = countO;
for (var j = 0; j < g_drivers.length; j++) {
if (g_drivers[j].online === true && g_drivers[j].no_signal === 0 && g_drivers[j].headingOldCounter < 30) {
//added the following line, to get better data-values
g_drivers[j].heading = Math.random()*360;
document.getElementById('img_' + g_drivers[j].uuid).style.transform = 'rotate(' + g_drivers[j].heading + 'deg)';
}
}
}
CSS transitions allows you to change property values smoothly (from
one value to another), over a given duration.
But, you're not changing the property (transform) in your code. You're replacing img so it has no start and end values for the transition.
Like this:
var dir_img = 'https://image.freepik.com/iconos-gratis/flecha-hacia-arriba_318-74795.jpg';
setInterval(function() { // emulating the data changes continuously
var g_drivers = [
{id:1, heading: ~~(Math.random()*360)},
{id:2, heading: ~~(Math.random()*360)}
];
var html = '';
for (var i in g_drivers)
html += '<img class="dir_img" style="transform: rotate(' + g_drivers[i].heading + 'deg)" src="' + dir_img + '">';
document.getElementById('sidebar-scroll').innerHTML = html;
}, 500);
.dir_img {
width:70px; margin:20px;
transition: transform 2s;
}
<div id="sidebar-scroll"></div>
But if you need the transitions to be applied you have to keep the images and change their transform property like this:
var dir_img = 'https://image.freepik.com/iconos-gratis/flecha-hacia-arriba_318-74795.jpg';
var sidebar = document.getElementById('sidebar-scroll');
// setting up the drivers (initially empty):
var drivers = {};
// emulating the data changes continuously
setInterval(function() {
var drivers_data = {
'driver_1': {heading: ~~(Math.random()*360)},
'driver_2': {heading: ~~(Math.random()*360)}
};
for (var i in drivers_data) {
if (!drivers[i]) { // it's a new driver, lets add it:
drivers[i] = Object.assign({}, drivers_data[i]);
sidebar.innerHTML += '<img id="' + i + '" class="dir_img" src="' + dir_img + '">';
}
// now change driver's property:
document.getElementById(i).style.transform = 'rotate(' + drivers_data[i].heading + 'deg)';
}
}, 1000);
.dir_img {
width:70px; margin:20px;
transition: transform .7s;
}
<div id="sidebar-scroll"></div>
Use CSS transitions. This will let you ease between the transforms. Couple that with the setInterval that you should be using to get the amount you need to transform each iteration.
For example, the below snippet will have the transform ease between whatever the current transform is and the target transform over the course of 200ms (milliseconds).
const img = document.getElementById("image"),
input = document.getElementById("amount");
let curr = 0;
setInterval(() => {
curr += (parseInt(input.value, 10) || 0);
img.style.transform = `rotate(${curr}deg)`;
}, 1000);
.rotater {
transition: transform 200ms ease;
}
<div><label for="amount">How much to rotate by</label> <input type="number" id="amount" value="10" step="10" min="10" max="90"></div>
<div>
<img id="image" class="rotater" src="https://cdn.sstatic.net/Sites/stackoverflow/img/sprites.svg?v=1b3cdae197be">
</div>

How to fire the javascript function in the textboxes that are getting created dynamically in asp .net

Below is my code which creates the textboxes dynamically in modal pop up each time when i click add button and removes the text boxes in that row each time when i click remove button which is working fine till here the problem is i have the javascript function which validates the month date and year in text box that if if we give any number greater than 12 it shows message that month should be less than 12 similarly for date also it will accept till 31 but if it is greater than 31 it shows error message and similarly year also but this is done for our asp text boxes how can i make this javascript function to work in modal pop where the textboxes are created dynamically
<script type="text/javascript">
function GetDynamicTextBox(value) {
if (value == "") {
FillDropdown()
return '<input name = "DynamicTextBox" value = "' + value + '" placeholder="MM/DD/YYYY"></input> <select name = "DynamicTextBox" >"' + Hours + '"</Select><b>:</b><select name = "DynamicTextBox">"' + Min + '"</Select>' +
' <input id="btnAdd123" type="button" value="Add" onclick="AddTextBox()" /><input type="button" value="Remove" onclick = "RemoveTextBox(this)" />'
//Min = "";
// Hours = "";
//
}
}
var HHEdit = "";
var MMEdit = "";
function GetDynamicTextBox1(value) {
values = value.split(' ');
one = values[0];
two = values[1];
values = two.split(':');
three = values[0];
Four = values[1];
HHEdit = three;
MMEdit = Four;
FillDropdown()
return '<input name = "DynamicTextBox" value = "' + one + '" placeholder="MM/DD/YYYY"></input> <select name = "DynamicTextBox" >"' + Hours + '"</Select><b>:</b><select name = "DynamicTextBox">"' + Min + '"</Select>' +
' <input id="btnAdd123" type="button" value="Add" onclick="AddTextBox()" /><input type="button" value="Remove" onclick = "RemoveTextBox(this)" />'
// $('.DynamicTextBox').val(one);
}
function AddTextBox() {
var div = document.createElement('DIV');
div.innerHTML = GetDynamicTextBox("");
document.getElementById("TextBoxContainer").appendChild(div);
}
function AddTextBox1() {
var inputCount = document.getElementById('TextBoxContainer').getElementsByTagName('input').length;
if (inputCount == "0") {
var div = document.createElement('DIV');
div.innerHTML = GetDynamicTextBox("");
document.getElementById("TextBoxContainer").appendChild(div);
}
}
function RemoveTextBox(div) {
document.getElementById("TextBoxContainer").removeChild(div.parentNode);
}
function RecreateDynamicTextboxes() {
var values = eval('<%=Values%>');
if (values != null) {
var html = "";
for (var i = 0; i < values.length; i++) {
html += "<div>" + GetDynamicTextBox1(values[i]) + "</div>";
}
document.getElementById("TextBoxContainer").innerHTML = html;
}
}
var Hours = "";
var Min = "";
function FillDropdown() {
for (var i = 0; i < 24; i++) {
if (i >= 0 && i <= 9) {
if (HHEdit != "" && HHEdit == i) {
Hours += '<option value="' + i + '" selected="selected">' + " 0" + i + " " + '</option>'
}
else {
Hours += '<option value="' + i + '">' + " 0" + i + " " + '</option>';
}
}
else {
if (HHEdit != "" && HHEdit == i) {
Hours += '<option value="' + i + '" selected="selected">' + " " + i + " " + '</option>';
}
else {
Hours += '<option value="' + i + '">' + " " + i + " " + '</option>';
}
}
}
for (var i = 0; i < 60; i++) {
if (i >= 0 && i <= 9) {
if (MMEdit != "" && MMEdit == i) {
Min += '<option value="' + i + '" selected="selected">' + " 0" + i + " " + '</option>';
}
else {
Min += '<option value="' + i + '">' + " 0" + i + " " + '</option>';
}
}
else {
if (MMEdit != "" && MMEdit == i) {
Min += '<option value="' + i + '" selected="selected">' + " " + i + " " + '</option>';
}
else {
Min += '<option value="' + i + '">' + " " + i + " " + '</option>';
}
}
}
//$('#Item').append(option);
}
window.onload = RecreateDynamicTextboxes;
</script>
Code for date month year validation using javascript
var fdate = document.getElementById('<%=txtFromDate.ClientID%>').value;
var tdate = document.getElementById('<%=txtToDate.ClientID%>').value;
var fromdate = fdate.split('/');
var fmonth = fromdate[0];
var fdate = fromdate[1];
var fyear = fromdate[2];
if (fmonth > 12) {
message += "From Month Should Be Less Than 12." + "\n";
}
if (fdate > 31) {
message += "From Date Cannot Be Greater Than 31." + "\n";
}
if (fyear < 2000 || fyear > 2030) {
message += "From Year Should Be In Between 2000 to 2030." + "\n";
}
var todate = tdate.split('/');
var tmonth = todate[0];
var tdate = todate[1];
var tyear = todate[2];
if (tmonth > 12) {
message += "To Month Should Be Less Than 12." + "\n";
}
if (tdate > 31) {
message += "To Date Cannot Be Greater Than 31." + "\n";
}
if (tyear < 2000 || tyear > 2030) {
message += "To Year Should Be In Between 2000 to 2030."+"\n";
}
if (message != "") {
alert(message);
return false;
}
From Date: <asp:TextBox ID="txtFromDate" Width="113px" runat="server" placeholder="mm/dd/yyyy" onkeypress="return IsValidData(event);" ondrop="return false;"
onpaste="return false;" onkeyup="this.value=this.value.replace(/^(\d\d)(\d)$/g,'$1/$2').replace(/^(\d\d\/\d\d)(\d+)$/g,'$1/$2').replace(/[^\d\/]/g,'')"></asp:TextBox> <span id="error" style="color: Red; display: none">* Invalid Character</span>
To Date: <asp:TextBox ID="txtToDate" Width="113px" runat="server" placeholder="mm/dd/yyyy" onkeypress="return IsValidData(event);" ondrop="return false;"
onpaste="return false;" onkeyup="this.value=this.value.replace(/^(\d\d)(\d)$/g,'$1/$2').replace(/^(\d\d\/\d\d)(\d+)$/g,'$1/$2').replace(/[^\d\/]/g,'')"></asp:TextBox><span id="Span1" style="color: Red; display: none">* Invalid Character</span>
I don't see that you've actually defined your IsValidData function. I'm assuming that you've done that somewhere...
You can pass this to your IsValidData function as a parameter to work with the element that triggered the event in your function..
Also you should try moving away from inline functions to event listeners. This stack post (JavaScript click event listener on class) talks about applying an event listener to a class of DOM elements.
If you are using jQuery, since you included this tag, then I'd encourage you to look into the jQuery .on() function to add event handlers. It'll make everything much easier (http://api.jquery.com/on/)
If you do not know what a javascript event listener is, then start here (https://www.w3schools.com/js/js_htmldom_eventlistener.asp)

Hide/show dynamic generated div based on select option

I have some divs which are generated by jquery. Inside there is showing up the price, the title and the selected option value.
I've tried a lot of things to hide each div class "result" if no option is select, but with no luck.
Is there a way to hide each div without rewriting the whole code?
JS:
function pcc_calc_forms() {
jQuery(".calcolare").each(function (e) {
var t = jQuery(this).attr("id");
var n = pcc_form_data(t);
jQuery("#" + t + "-mostra").html('<h3 class="pcc-total">Totale : ' + n[0] + "" + "€" + '</h3><div class="content">' + n[1] + '<br /><br /></div>')
})
}
function pcc_form_data(e) {
var t = new Array(0, "");
var n = new Array;
var r = new Array;
$("#" + e + " select").each(function (e) {
var title = $(this).attr("data-title");
var inside = $(this).find("option:selected").attr("data-title");
var i = $(this).find("option:selected").html();
if (inside === undefined) {
inside = " ( " + i + " ) "
} else {
inside = " ( " + inside + " ) "
}
var i = $(this).find("option:selected").attr("data-price");
var s = parseFloat($(this).attr("data-mult"));
if (isNaN(s)) {
s = 1
}
var o = parseFloat($(this).find("option:selected").text());
if (isNaN(o)) {
o = 0
}
if (i !== undefined) {
if (i == "this") {
i = o
} else {
i = parseFloat(i)
}
t[0] = t[0] + parseFloat(i) * s;
if (s == 1) {
t[1] = t[1] + "<div class=\"result\"><b>" + title + "" + inside + "</b> : " + parseFloat(i) + "" + " € " + "</div>"
} else {
t[1] = t[1] + "<div class=\"result\"><b>" + title + "" + inside + "</b> : " + parseFloat(i) + " X " + s + " = " + parseFloat(i) * s + "" + " € " + "</div>"
}
}
});
n = [];
r = [];
return t
}
$(document).ready(function () {
pcc_calc_forms();
$(document).on("change", ".calcolare select", function () {
pcc_calc_forms()
});
});
THIS is the link to the fiddle
Thanks in advance for any hint.
$(document).on("change", ".calcolare select", function () {
var i = $(this).find('option:selected').index();
alert(i);
//if(i>0) ppc_calc_forms();
//else $('.results').hide();
})
This will find the index of the selected option... as you can see, it works, just not with your function...
I would simplify that script as much as possible..
I understand not wanting to rewrite the code substantially at this point. However, for comparison, here is the way I would do it while still holding to your general pattern:
function pcc_calc_forms() {
jQuery(".calcolare").each(function (e) {
var t = jQuery(this).attr("id");
var items = pcc_item_data(t);
var totalPrice = $.makeArray(items).reduce(function(total,item,i,a) {
return total+item.price;
},0);
text = '<h3 class="pcc-total">Totale : ' + totalPrice + "" + "€" + '</h3>';
text += '</h3><div class="content">';
items.each(function(i,item) {
if (item.mult > 1)
text += "<div class=\"result\"><b>" + item.title + " ( " + item.name + " )</b> : " + item.price + " X " + item.mult + " = " + item.price * item.mult + "" + " € " + "</div>";
else
text += "<div class=\"result\"><b>" + item.title + " ( " + item.name + " )</b> : " + item.price + "" + " € " + "</div>";
});
text += '<br /><br /></div>';
jQuery("#" + t + "-mostra").html(text);
});
}
function pcc_item_data(e) {
return $("#" + e + " select").map(function (e) {
if (this.selectedIndex > 0) {
var item = {};
item.title = $(this).attr("data-title");
var inside = $(this).find("option:selected").attr("data-title");
var i = $(this).find("option:selected").html();
item.name = inside ? inside : i;
item.price = parseFloat($(this).find("option:selected").attr("data-price"));
var mult = parseFloat($(this).attr("data-mult"));
item.mult = isNaN(mult) ? 1 : mult;
return item;
}
});
}
$(document).ready(function () {
pcc_calc_forms();
$(document).on("change", ".calcolare select", function () {
pcc_calc_forms();
});
});
What I've done:
Separate data collection (pcc_item_data) from data presentation;
this makes the code more readable and easier to maintain later.
Used map (http://api.jquery.com/jQuery.map/) and reduce (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) to transform / aggregate arrays; they're concise
and expressive once you're familiar with them.

How to append all the elements at once to create a drop down in jQuery

I'm creating a drop down with three sub menus, so a main dropdown with publishers, a sub menu with authors (which are within that publisher) and a sub menu to authors containing the years they've been published. So hover over publisher, see authors in that publisher.
It worked fine but i've changed it to improve performance so instead of appending to the DOM each time i've been storing up the values in a variable and then appending to the DOM, however i'm now getting an error
cannot call method find of null
relating to the line:
var author = ulauthors.find('li.author[data-value="' + authorval + '"]');
Any ideas how i fix it, i guess because i'm not appending until near the end it can't find the element?
var target = $('#listpublishers');
$(info.genres).each(function (i) {
var genreval = this.genre;
var catval = this.genreGroup;
$(this.publishers).each(function (j) {
var publisherval = this.publisher;
var ulauthors = null;
var publisher = target.find('>li.publisher[data-value="' + publisherval + '"]');
var ulyears = null;
var publisherstring = '';
var targetstring = '';
var ulauthorstring = '';
var authorstring = '';
var ulyearstring = '';
//if publisher does not exist create it else find it
if (publisher.size() == 0) {
targetstring += '<li class="publisher" data-value="' + publisherval + '"><a onclick="gotoSubMenu">' + publisherval + '</a>';
target.append(targetstring)
publisherstring += '<ul class="sub-menuoos" data-title="publishers></ul>';
publisher.append(publisherstring)
} else {
ulauthors = publisher.find('>ul');
}
$(this.authors).each(function () {
var authorval = this.author + ' (' + genreval + ')';
var author_val = this.author;
var author = ulauthors.find('li.author[data-value="' + authorval + '"]');
if (author.size() == 0) {
ulauthorstring += '<li class="author" data-value="' + authorval + '"><a onclick="gotoSubMenu">' + authorval + '</a>';
ulauthors.append(ulauthorstring)
authorstring += '<ul class="sub-menuoos" data-title="authors></ul>';
author.append(authorstring);
} else {
ulyears = author.find('>ul');
}
$(this.publishedYears).each(function () {
var yearval = this;
var year = ulyears.find('li.year[data-value="' + yearval + '"]');
if (year.size() == 0) {
var id = ++count;
ulyearstring += '<li class="year" data-value="' + yearval + '"><a class="item" id="year"' + id + '"data-year="' + yearval + '" data-publisher="' + publisherval + '" data-author+"' + author_val + '" data-genre="' + genreval + '">' + yearval + '</a>';
ulyears.append(year);
}
});
});
});
});
});

Categories