I have an unordered list of elements organized in rows. When a user clicks on a row, I want the text in the row to be appended into a separate text field. The issue with my current code is that I if the user clicks multiple boxes, all of the associated text with each of those boxes will be appended into the textfield. I would like to append the text from only the last row element that the user clicked.
Here is my javascript:
function clickEvents() {
// Day List Selector
$('#DC_id_1').click(function() {
$('#whenTextField').attr('value', 'Today');
});
$('#DC_id_3').click(function() {
$('#whenTextField').attr('value', 'Tomorrow');
});
$('#DC_id_5').click(function() {
$('#whenTextField').attr('value', 'Later');
});
// Time List Selector
$('#DC_id_37').click(function() {
var day = $('#whenTextField').attr('value');
$('#whenTextField').attr('value', day + ', Right Now');
});
$('#DC_id_39').click(function() {
var day = $('#whenTextField').attr('value');
$('#whenTextField').attr('value', day + ', Morning');
});
$('#DC_id_41').click(function() {
var day = $('#whenTextField').attr('value');
$('#whenTextField').attr('value', day + ', Midday');
});
$('#DC_id_43').click(function() {
var day = $('#whenTextField').attr('value');
$('#whenTextField').attr('value', day + ', Afternoon');
});
$('#DC_id_45').click(function() {
var day = $('#whenTextField').attr('value');
$('#whenTextField').attr('value', day + ', Evening');
});
}
Basically, I think I want to use an "if" statement to control the clicking in the Time List Selector elements list.
example:
if (DC_id_37 is clicked) {
append('text');
}
else if (DC_id_39 is clicked) {
append('some other text');
Here is the associated HTML:
<ul id="dayList">
<li id="DC_id_1">
Today
</li>
<li id="DC_id_3">
Tomorrow
</li>
<li id="DC_id_5">
Later
</li>
</ul>
<ul id="timeList">
<li id="DC_id_37">
Right Now
</li>
<li id="DC_id_39">
Morning
</li>
<li id="DC_id_41">
Midday
</li>
<li id="DC_id_43">
Afternoon
</li>
<li id="DC_id_45">
Evening
</li>
</ul>
<textField id="whenTextField">
*Note I just created this HTML by hand, as I'm building the web app in Dashcode, and its putting out some very ugly HTML
Actual HTML created by Dashcode:
<ul id="timeList">
<li>
<div id="foo"></div>
<div id="DC_id_37">Right Now</div>
<div></div>
</li>
<li>
<div id="foo2"></div>
<div id="DC_id_39"></div>
<div></div>
</li>
</ul>
Instead of simply appending the new value, you need to replace the old value. I would do it this way:
// Based on the HTML you posted, we only need two click functions.
$("#dayList > li > div:eq(1)").click(function() {
var newDate = $(this).text();
var currentValues = $("#whenTextField").attr("value").split(", ");
// Initialize this as an empty string in case the user has not yet selected
// a time.
var time = "";
// Get the previous time, if one has already been appended.
if (currentValues.length == 2) {
time = ", " + currentValues[1];
}
// Update the value of the text field.
$("#whenTextField").attr("value", newDate + time);
});
$("#timeList > li > div:eq(1)").click(function() {
// Get the current date value.
var date= $("#whenTextField").attr("value").split(", ")[0];
// Get the text from the 'li' element that raised the event.
var time = $(this).text();
// Update the value of the text field, keeping the previously selected date.
$("#whenTextField").attr("value", date + ", " + time);
});
This approach also saves the selected time if a user later changes the selected date.
Update:
I updated my example to match the second nested <div /> element under each <li /> using the :eq(n) selector (the selector is zero-based). This solution assumes that the target <div /> elements will always be the second one, based on your comment.
You have a few other options, too:
You could use the :parent selector to affect only <divs /> that contain text (or any child elements).
$("#timeList > li > div:parent").click(function() { });
Or, you could use the Attribute Starts With Selector to affect only <div /> elements with IDs that start with "DC_id_".
$("#timeList > li > div[id^='DC_id_']").click(function() { });
I'm not sure which solution performs the best. Personally, I would recommend going with the third option (the Attribute Starts With selector) since generated IDs are usually more predictable than an element's index or contents.
I believe this is what you're looking for:
$('#DC_id_37').click(function() {
var day = $('#whenTextField').attr('value').split(",")[0];
$('#whenTextField').attr('value', day + ', Right Now');
});
The .split(",")[0] will grab the first part of what's in the text box.
You could simplify your code with something like this:
$('#dayList li').click(function() {
$('#whenTextField').attr('value',$(this).text());
});
$("#timeList li").click(function() {
var day = $('#whenTextField').attr('value').split(",")[0];
$('#whenTextField').attr('value', day + ', '+$(this).text());
});
Roughly
html: (adjust to taste, prolly have to do some css)
<div class="appointment">
<div class="options">
<ul class="day">
<li>Today</li>
<li>Tomorrow</li>
<li>Later</li>
</ul>
<ul class="time">
<li>Right Now</li>
<li>Morning</li>
<li>Midday</li>
<li>Afternoon</li>
<li>Evening</li>
</ul>
</div>
<input class="when" type="text" />
</div>
jquery
$('.appointment').each(function(){
var self = $(this)
, whenField = self.find('.when')
, day = 'choose a day'
, time = 'choose a time';
self.delegate('.options li', 'click', function(e){
var li = $(this), ul = li.closest('ul');
if(ul.hasClass('day')) {
day = li.text();
} else if(ul.hasClass('time')) {
time = li.text();
}
whenField.val(day + ' - ' + time);
});
});
Reusable on a page, so you can have more appointment boxes on a page.
I personally avoid using element ID's like the plague, better abstract it and shorten code substantially if you generalize.
Related
I'm having trouble inserting child elements to a list in HTML using jQuery. I'm a beginner when it comes to anything JavaScript related so my code is probably very clunky and unoptimized. Even if you can't help me with the original issue I always appriciate pointers to improve my code and learn.
I have a function that runs every second (it's called from my CefSharp application, not sure if it's relevant). This is my function:
function updateOrderQueue(index, reference, pickedup, deliveredto, robotId, statuscode, statustext) {
var list = $('#orderQueueList');
var count = $("#orderQueueList li").length;
if (!document.getElementById('order' + reference) && statuscode < 4 && count < 10) {
var data = $(`<li class="list-group-item d-flex justify-content-between align-items-center border border-dark" id="order` + reference + `">
<h3 class="mt-1" id="text`+ reference + `">
[`+index+`] `+ pickedup + ` ➔ ` + deliveredto + ` (` + statustext + `)
</h3>
<small class="badge badge-dark rounded" style="font-size:24px;" id="robotQueue`+ reference + `">` + robotId + `</small>
</li>`);
list.append(data).hide().fadeIn(500);
} else {
var locations = jQuery("#text" + jq(reference));
var assignedrobot = jQuery("#robotQueue" + jq(reference));
locations.text('['+index+'] '+ pickedup + ' ➔ ' + deliveredto + ' (' + statustext + ')');
assignedrobot.text(robotId);
}
var elems = $('#orderQueueList li').detach().sort(function (a, b) {
if (isNaN($(a).text()) || isNaN($(b).text())) {
return $(a).text() > $(b).text() ? 1 : -1;
}
return $(a).text() - $(b).text();
});
list.append(elems);
}
And this is the HMTL code
<div id="orderQueue" class="">
<ul class="list-group" id="orderQueueList">
</ul>
</div>
I'm going to try to quickly explain what I intend on it doing and what it actually does.
So basically, this code is supposed to add, sort and add relevant classes to items in a list. To be added, the item needs to pass a set of requirements (not already added, statuscode under 4 and not more than 10 items total). I then append the item into the list, which I assumed would put it at the end of the list (compared to prepend, which should do the opposite).
The problem is, whenever a new item is added, it is added to the top of the list. My guess is that is has something to do with the fact that I'm appending it to the ul. I tried doing something like $('#orderQueueList li:last') but I didn't get it to work. I've also tried to do $('#orderQueueList).children() and $('#orderQueueList).last() before appending without success.
What am I missing? Have I completely misunderstood what append does? Have I written the code wrong?
Appriciate any pointers,
Thank you in advance.
The issue here is not the .append() but the .sort() which comes after.
Sorting text is affected by whitespace, so the solution is to .trim() the text when doing a text comparison:
$("ul").append("<li>new</li>").hide().fadeIn(500);
var elems = $('ul li').detach().sort(function(a, b) {
if (isNaN($(a).text()) || isNaN($(b).text())) {
return $(a).text().trim() > $(b).text().trim() ? 1 : -1;
}
return $(a).text() - $(b).text();
});
$("ul").append(elems);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
<li> 2</li>
<li>1555</li>
<li>xyz</li>
<li>3</li>
<li>
abc
</li>
</ul>
I am being able to provide option's in the menu bar but when I click on any of the option it's working absolutely fine,but if I tried to select twice it is changing at all places.
For Ex.
I want to make a ordered list such as:
1.Some Text here
a.option 1 b.option 2
c.option 3 d.option 4.
When I am trying to select some text its also converting 1 to A.
Please help.Thanks in advance
document.execCommand('insertUnorderedList',true,null);
let selectedStyle = event.target.parentNode.classList.value;
$('li').attr('id', function(i) {
return 'unorder'+(counter+1);
});
$('ol > li').css({'list-style-type':selectedStyle});
You can ignore the counter part its not required.I was trying to put id at every element and use jquery to update only that part.
let counter = 0;
document.querySelectorAll (".unorder-list-select .unorder-list-main .unorder-container ul").forEach((elem)=>{
elem.addEventListener("click",(event)=>{
counter++;
$('li').attr('id', function(i) {
return 'unorder'+(counter+1);
});
$('ul > li').css({'list-style-type':selectedStyle});
}
HTML
<div class="order-list-select" id="orderList" draggable="true">
<div>
<span class="jodit_popup_triangle"></span>
<div class="math-toolbar-top" id="orderlistHeader"></div>
<div class="order-list-main">
<div class="order-list-container"></div>
<div class="order-container">
<ol class="upper-roman">
<li><hr></li>
</ol>
<ol class="decimal">
<li><hr></li>
</ol>
</div>
</div>
</div>
</div>
Actual
1.text
2.text
Some text here
1.Txt
2.Txt
Expected
1.text
2.text
Some text here
a.Txt
b.Txt
I did it by Jquery don't know if its right approach but it has made me achieve my task.
Below is the code for my this.
document.querySelectorAll(".unorder-list-select .unorder-list-main .unorder-container ul").forEach((elem)=>{
elem.addEventListener("click",(event)=>{
counter++;
document.execCommand('insertUnorderedList',true,null);
let selectedStyle = event.target.parentNode.classList.value;
let select = window.getSelection().focusNode.parentElement.parentElement;
let ul_id = ""
$(select).attr('id', function(i) {
ul_id = "unorder"+(counter);
return ul_id;
});
if(selectedStyle == "right-arrow"){
$('#'+ul_id).css({'list-style-image':`url('icons/list-right-editor.svg')`});
}else if(selectedStyle == "open-square"){
$('#'+ul_id).css({'list-style-image':`url('icons/square-open-editor.svg')`});
}else{
$('ul').attr('type',function(){
return selectedStyle;
})
$('#'+ul_id).css({'list-style-type':selectedStyle});
}
document.querySelector(".unorder-list-select").remove();
})
});
Please change the classess accordingly to get the tag and click.
Hi i'm building a project which has a page navigation and search bar in jQuery.
I can't get my search function to work correctly and I'm not certain if it's a problem with the ID element or the each function. I'm getting the ("Sorry, no student's found!") message for anything that is or isn't a match. So i think there could be a problem with the if statement looking for a match in search function--but not sure.
I'm dynamically adding a search box to my html like this:
function appendSearchBox(){
var search = "<div class='student-search'><input id='search' placeholder='Search for students...'><button>Search</button></div>"
$(".students").after(search);
// Add click event handler
$("button").click(function() {
searchList();
});
}
this is what my html looks like for a list of students:
<div class="page">
<div class="page-header cf">
<h2 class="students">Students</h2>
</div>
<ul class="student-list">
<li class="student-item cf">
<div class="student-details">
<img class="avatar" src="https://randomuser.me/api/portraits/thumb/women/67.jpg">
<h3>iboya vat</h3>
<span class="email">iboya.vat#example.com</span>
</div>
<div class="joined-details">
<span class="date">Joined 07/15/15</span>
</div>
</li>
</ul>
And then here is the actual search function:
var listStudents = $(".student-list li");
var numStudents = listStudents.length;
function searchList() {
var matched = [];
// Obtain the value of the search input
input = $("#search").val()
// remove the previous page link section
$('.pagination').hide();
// Loop over the student list, and for each student…
listStudents.each(function(){
// ...obtain the student’s name…
var name = $(this).find("h3").val();
// ...and the student’s email…
var email = $(this).find(".email").val();
// ...if the search value is found inside either email or name…
if (name.includes(input) || email.includes(input)) {
// ...add this student to list of “matched” student
matched.push($(this).parent());
}
});
// If there’s no “matched” students…
if (matched.length === 0){
// ...display a “no student’s found” message
var message = ("Sorry, no student's found!");
$(".student-list").hide();
$(".student-list").after(message);
if (matched.length > 10) {
// ...call appendPageLinks with the matched students
appendPageLinks(matched);
}
// Call showPage to show first ten students of matched list
showPage(1, matched);
}
}
adding functions which actually show the students and add navigation
function showPage(pageNum, listStudents) {
// first hide all students on the page
pageNum = parseInt(pageNum);
listStudents.hide();
// Then loop through all students in our student list argument
listStudents.each(function(index){
// if student should be on this page number
if ((index >= ((pageNum*10)-9)) && (index <= (pageNum*10))) {
// show the student
$(this).show();
}
});
}
function getNumPages(numStudents){
numPages = Math.ceil(numStudents/10);
return numPages;
}
function appendPageLinks(numStudents) {
// determine how many pages for this student list
pages = getNumPages(numStudents);
// create a page link section
var nav = "<div class='pagination'><ul>"
for (i=1; i<pages+1; i+=1){
nav += ("<li>" + "" + i + "" + "</li>");
};
nav += ("</ul></div>");
$(".student-list").after(nav);
// define what happens when you click a link
var active = $('.pagination a').click(function(){
// Use the showPage function to display the page for the link clicked
var id = $(this).attr('id');
showPage(id,listStudents);
// mark that link as “active”
active.removeClass('active');
$(this).addClass("active");
});
}
here is how i am calling the functions:
appendSearchBox();
showPage(1, listStudents);
appendPageLinks(numStudents);
UPDATE -- I have changed the code to remove the val and put in to grab the text.
Not sure what issue is but it appears if i have a correct match--it is working (since pagination disappears) but the students do not change on the page. If there is no match then I get the error message, but the error console is saying
Uncaught TypeError: listStudents.hide is not a function
at showPage (main.js:8)
I'm not sure if this is somehow related to how I am passing the 'matched' list?
h3 and span tags have no value, but text content, so replace:
var name = $(this).find("h3").val();
// ...and the student’s email…
var email = $(this).find(".email").val();
with:
var name = $(this).find("h3").text();
// ...and the student’s email…
var email = $(this).find(".email").text();
You are using val() method to read inner text of h3 and span (email). It should be text(). Also you are appending message after the student list every time you couldn't find a student. You could have used one span tag and hide/show based on the search results.
function appendSearchBox() {
var search = "<div class='student-search'><input id='search' placeholder='Search for students...'><button>Search</button></div>"
$(".students").after(search);
// Add click event handler
$("button").click(function () {
searchList();
});
}
$(document).ready(function () {
appendSearchBox();
});
function searchList() {
var listStudents = $(".student-list li");
var numStudents = listStudents.length;
$(".student-list").show();
$("#message").hide();
var matched = [];
// Obtain the value of the search input
input = $("#search").val()
// remove the previous page link section
$('.pagination').hide();
// Loop over the student list, and for each student…
listStudents.each(function () {
// ...obtain the student’s name…
var name = $(this).find("h3").text();
// ...and the student’s email…
var email = $(this).find(".email").text();
// ...if the search value is found inside either email or name…
if (name.includes(input) || email.includes(input)) {
// ...add this student to list of “matched” student
matched.push($(this).parent());
}
});
// If there’s no “matched” students…
if (matched.length === 0) {
// ...display a “no student’s found” message
var message = ("Sorry, no student's found!");
$(".student-list").hide();
$("#message").show();
if (matched.length > 10) {
// ...call appendPageLinks with the matched students
appendPageLinks(matched);
}
// Call showPage to show first ten students of matched list
showPage(1, matched);
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<div class="page">
<div class="page-header cf">
<h2 class="students">Students</h2>
</div>
<ul class="student-list">
<li class="student-item cf">
<div class="student-details">
<img class="avatar" src="https://randomuser.me/api/portraits/thumb/women/67.jpg">
<h3>iboya vat</h3>
<span class="email">iboya.vat#example.com</span>
</div>
<div class="joined-details">
<span class="date">Joined 07/15/15</span>
</div>
</li>
</ul>
<span id="message" style="display:none;"><br/>Sorry, no student's found!</span>
</div>
I have a function that adds game results to a schedule.
I want to have the score of a winning team in yellow - add ".winner" class to (<%=score1%> or <%=score2%>).
I wonder what is the correct way to specify needed element, using jQuery.
My current code isn't working. All elements get ".winner" class, regardless of whether a team won or not.
addGame: function(gameInfo) {
var sHtml = window.JST["schedule/gamelist/inner_row"](gameInfo);
var tableRow = $("<tr>").append(sHtml);
tableRow.data("id", gameInfo.id);
return tableRow;
}
addNewTable: function(date, gameInfos, number) {
...
...
for (var ind = 0; ind < gameInfos.length; ++ind) {
gameInfo = gameInfos[ind].attributes;
var element = this.addGame(gameInfo);
$("#schedule_mytable_tbody" + number).append(element);
if (gameInfo.score1 > gameInfo.score2)
$("li:nth-child(5)").find("p:first-child").addClass("winner");
else
$("li:nth-child(5)").find("p:last-child").addClass("winner");
}
My template looks like this.
window.JST["schedule/gamelist/inner_row"] = _.template(
'<td width="668px">\
<ul>\
<li class="schedule_..."></li>\
<li class="schedule_..."></li>\
<li class="schedule_...."></li>\
<li class="schedule_..."></li>\
<li class="schedule_boxscore">\
<p><%=score1%></p>\
<p><%=score2%></p>\
</li>\
...
Rendered HTML part:
<li style="font-size:16px" class="schedule_boxscore">
<p class="winner">2</p>
<p class="winner">10</p>
</li>
So, because of the "for" loop, all paragraphs get the ".winner" class, not just <p class="winner">10</p>...
This question is similar to this one (but not exact):
Count immediate child div elements using jQuery
I have a bunch of lists that represent christmas presents for different people.
As an example, this is a list of presents for one person. Note that new people can be added
<ul id = "presents">
<li id = "person1" >
<ul id = "presentsforperson1">
<li id = "present1" >
<ul id = "present1info">
<li> Present 1 </li>
<li> A New Pair of Shoes </li>
<li> $19.99 </li>
</ul>
</li>
<!-- More presents for person 1 can be added here dynamically-->
</ul>
</li>
<!-- More people can be added here -->
</ul>
Unlike the question posted, I have the object presentsforperson1 in a variable called drop (droppable). I was wondering what the correct syntax is for finding the number of presents person 1 has (in this case 1) with this variable?
This is what I have tried so far:
var numberofPresents = $(drop + "ul > li").length; //drop holds li#presentsforperson1 .droppable
var numberofPresents = $(dropid + "ul > li").length; //dropID is $(drop).attr("id");
If the person id is the id of the ul containing their presents then simply:
$('#personId > li').length
will do it.
Update
Or if the id is in a variable:
$('#' + personId).children('ul').length
You obviously could append the child selector to the selector string eg:
$('#' + personId + ' > ul').length
But personally I find the version with the .children call more readable.
Assuming your drop variable references a jQuery object:
var quantity = drop.children().length;
If it has the raw DOM element:
var quantity = $(drop).children().length;
If it is merely a string with the ID, with no ID selector syntax:
var quantity = $('#' + dropid).children().length;
Or you can do concatenation like you were:
var quantity = $('#' + dropid + " > li").length;
You can do something as follows (give your lis that represent a present a css class):
var presents = $('ul[id="person1"]').children('li.presentClass');
alert(presents.length);