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>...
Related
this is probably an easy question for you guys but I'm very new to coding and can't figure out this. I have a code that I want to randomize the given choices in the questions, and I've found a script online that does that but it's not working. I don't know what the
// shuffle only elements that don't have "group" class
$ul.find("li[class!='single_question', 'question', 'title', 'text']").each(function() {
means so I tried to put all id that I don't need to randomize in it but it's still not working.
Can someone help me this please? Also is there anyway I can add choice "A", choice "B", choice "C", and choice "D" in front of each given options so even after the options(answers) are randomized, the A,B,C,D options will still be in order? Thank you. Here's the code:
HTML:
<!DOCTYPE html>
<html>
<body>
<script src="JQ.js"></script>
<script src="function.js"></script>
<link href="style.css" rel="stylesheet" />
<div id="quiz_container">
<ul class="quiz_container">
<li class="single_question" data-question-id="1" data-correct-answer="1">
<div class="question">
<h1 class="title">P.1 Grammar Review</h1>
<p class="text">1. "What is your name__"</p>
</div>
<ul class="options">
<li value="1">?</li>
<li value="2">.</li>
<li value="3">,</li>
</ul>
<div class="result"></div>
</li>
<li class="single_question" data-question-id="2" data-correct-answer="b">
<div class="question">
<p class="text">2. "Do you like the banana__"</p>
</div>
<ul class="options">
<li value="a">.</li>
<li value="b">?</li>
<li value="c">,</li>
</ul>
<div class="result"></div>
</li>
</div>
</body>
</html>
JS:
$(document).ready(function () {
/*
* shuffles the array
* #param {Array} myArray array to shuffle
*/
function shuffleArray(myArray) {
for (var i = myArray.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = temp;
}
return myArray;
}
var $ul, $li, li_content, li_list;
// find all lists to shuffle
$("#quiz_container > ul").each(function () {
$ul = $(this);
li_list = [];
// shuffle only elements that don't have "group" class
$ul.find("li[class!='single_question', 'question', 'title', 'text']").each(function () {
// add content to the array and remove item from the DOM
li_list.push($(this).html());
$(this).remove();
});
// shuffle the list
li_list = shuffleArray(li_list);
while (li_content = li_list.pop()) {
// create <li> element and put it back to the DOM
$li = $("<li />").html(li_content);
$ul.append($li);
}
});
$("#contact_div").show();
});
$(document).on('click', '.single_question .options li', function () {
// Save the question of the clicked option
question = $(this).parents('.single_question');
// Remove If Anyother option is already selected
question.find('.selected').removeClass('selected');
// Add selected class to the clicked li
$(this).addClass('selected');
// selected option value
selected_answer_value = $(this).attr("value");
// Value of correct answer from '.single-question' attribute
correct_answer_value = question.attr("data-correct-answer");
correct_answer_text = question.find('.options').find("li[value='" + correct_answer_value + "']").text();
if (correct_answer_value == selected_answer_value)
result = "<div class='correct'> Correct ! </div>";
else
result = "<div class='wrong'> Correct answer is -> " + correct_answer_text + "</div>";
// Write the result of the question
$(this).parents('.single_question').find('.result').html(result);
// Calculate the score
score_calculator();
});
/**
* It loops through every question and increments the value when "data-correct-answer" value and "option's value" are same
*/
function score_calculator() {
score = 0;
$('.single_question').each(function () {
question = $(this);
if (question.attr('data-correct-answer') == question.find('.selected').attr("value")) {
score++;
}
});
$('.correct_answers').html(score);
}
It looks like you're using jQuery, even though the question isn't tagged as such. If that's the case, you can use a code snippet written by Chris Coyier of CSS-Tricks called shuffle children.
Here's an example of the code in action.
$.fn.shuffleChildren = function() {
$.each(this.get(), function(index, el) {
var $el = $(el);
var $find = $el.children();
$find.sort(function() {
return 0.5 - Math.random();
});
$el.empty();
$find.appendTo($el);
});
};
$("ul.randomized").shuffleChildren();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Static List:</h4>
<ul>
<li>First element</li>
<li>Second element</li>
<li>Third element</li>
<li>Fourth element</li>
</ul>
<h4>Randomized List:</h4>
<ul class="randomized">
<li>First element</li>
<li>Second element</li>
<li>Third element</li>
<li>Fourth element</li>
</ul>
In order to apply it to your own code, all you'd need to do is modify the CSS selector at the bottom of the jQuery snippet. In your case, ul.options might be a good choice.
Here are a couple of examples using your markup:
jsFiddle
Self-Contained HTML Doc
<ul id='parent_of_all'>
<li>
<span class='operator'>&&</span>
<ul>
<li>
<span class='operator'>||</span>
<ul>
<li>
<span class='operator'>&&</span>
<ul>
<li>
<span class='condition'>1 == 1</span>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<ul>
<li>
<span class='condition'>1 != 0</span>
</li>
</ul>
</li>
</ul>
to
{"&&":[{'||':[ {'&&':[ {"lhs": "1", "comparator": "==", "rhs":"1"} ]} ] } , {"lhs": "1", "comparator": "!=", "rhs":"0"}]}
As of now, I know the basics of jQuery, JavaScript. I need to know where to start thinking in order to accomplish the above conversion.
And the html tree could be more complex with more children.
You can do this with each and map
var obj = {}
var span = $('li > span').not('ul li span').text();
$('ul li span').each(function() {
var text = $(this).text().split(' ');
obj[span] = (obj[span]||[]).concat({lhs: text[0], comparator: text[1], rhs: text[2]});
});
console.log(obj)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li>
<span>&&</span>
<ul>
<li>
<span>1 == 1</span>
</li>
</ul>
<ul>
<li>
<span>1 != 0</span>
</li>
</ul>
</li>
You will need a way to select the first level of li, I assumed you have a parent element with an id such as list. I wrote the following code using basic jquery so you can understand it.
var result = {};
var $all_li = $('#list').children('li'); // selecting the first level of li
for(var i in $all_li){ // iterating all_li using for (you may use forEach )
var $current_li = $( $all_li[i] ); // getting operator from first span
var operator = $current_li.children('span').html(); // the text of the operator
var $inner_spans = $current_li.find('>ul >li >span'); // getting list of children spans (from path $list>li>ul>li>span)
var li_spans = []; // an array where we will put the inner span objects
for(var j in $inner_spans){ // iterating the inner spans
var text = $($inner_spans[j]).html().split(" "); // splitting the html
li_spans.push({
lhs: text[0],
comparator: text[1],
rhs: text[2]
}); // adding the splitted html to an object. Note: error if text didn't have 2 white spaces
}
result[operator] = li_spans; // adding the operator key and li_spans value to the result json
}
This code will parse the html and construct the result json, it should work for the html format you provided. Keep in mind that it does not handle errors (such as bad tree format).
simmiar html formats.
Thanks #Alexandru and #Nenad for giving a start. I have been able to complete this on my own.
Below is the function that generates json.
function prepare_json(current_node){
var object = {}
var span = $(current_node).children('span')
if (span.hasClass('condition')){
var text = span.html().split(" ");
object = {lhs: text[0], comparator: text[1], rhs: text[2]}
}
else if(span.hasClass('operator')){
var operator = span.text()
object[operator] = (object[operator] || [])
var children = $(current_node).children('ul').children('li')
for(var i = 0; i < children.length; i++){
var child_pql = prepare_json([children[i]])
object[operator].push(child_pql)
}
}
return object
}
Below is the code that calls that function:
var parent_node = $('#parent_of_all').children('li')
var json = JSON.stringify(prepare_pql_json(parent_node), null, 2)
I am basically trying to check if my submenu has more than five list items, and if it does grab the remaining list item's and place them inside a new ul that is outside of the current parent ul using jquery. it gets complicated because of the structure of the list.
Here is the DOM structure:
<ul id="nav" class="se test">
<li id="menu1" class="page-1307 parent-menu parent">
<div class="nav-inner">
<a class="menulink" id="menuitem1" onclick="return false" href="#">test<span class="toggle"></span></a>
<ul id="ie1" class="plain">
<li class="parent-menu parent">test<span class="toggle"></span>
<div class="submenu-wrapper">
<ul class="plain">
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
</ul>
</div>
</li>
<li class="parent-menu parent">test<span class="toggle"></span>
<div class="submenu-wrapper">
<ul class="plain">
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
<li id="menu2" class="menulink page-7">
<div class="nav-inner">
test
</div>
</li>
</ul>
Basically i need to grab those remaining list items and place them in a new li.parent-menu.parent that includes the children div.sub-menu-wrapper and the ul.plain. the actual remaining list items would go inside the ul.plain of the new li.parent-menu. i hope thi makes since. i have been stuck on this for a day or two and unble to figure it out. any help would be greatly apprecitated, thank you.
This is what i am striving for, keep in mind it is dynamic.
you can:
Loop all ul in your document
foreach element count children
if found li number under an ul element is > 5
create a new list with the html of the required list
$(document).ready(function(){
$('.submenu-wrapper').each(function(){
var count_li=0;
var i=1;
$(this).children('ul').children('li').each(function(){
count_li++;
if(count_li>5 && i==1){
$(document.body).append('<ul id="newlist"></ul>');
$('#newlist').append($(this).nextUntil($(this).last()).andSelf());
i++;
}
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul id="nav" class="se test">
<li id="menu1" class="page-1307 parent-menu parent">
<div class="nav-inner">
<a class="menulink" id="menuitem1" onclick="return false" href="#">test<span class="toggle"></span></a>
<ul id="ie1" class="plain">
<li class="parent-menu parent">test<span class="toggle"></span>
<div class="submenu-wrapper">
<ul class="plain">
<li>test11</li>
<li>test12</li>
<li>test13</li>
<li>test14</li>
<li>test15</li>
<li>test16</li>
<li>test17</li>
</ul>
</div>
</li>
<li class="parent-menu parent">test<span class="toggle"></span>
<div class="submenu-wrapper">
<ul class="plain">
<li>test21</li>
<li>test22</li>
<li>test23</li>
<li>test24</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
<li id="menu2" class="menulink page-7">
<div class="nav-inner">
test
</div>
</li>
</ul>
Here is the final answer I was looking for:
megaMenu: function(){
function addNewList(current, newItems) {
var newList = $('<li class="parent-menu parent newLi">');
var div = $('<div class="submenu-wrapper">');
newList.append(div);
var ul = $('<ul class="plain">');
div.append(ul);
for (var i = 0; i < newItems.length; i++) {
ul.append(newItems[i]);
}
current.after(newList);
return newList;
}
function splitLists() {
var allLists = $(".plain > li.parent-menu");
for (var i = 0; i < allLists.length; i++) {
var currentList = $(allLists[i]);
var items = currentList.find("li");
if (items.length > 5) {
var temp = [];
for (var j = 5; j < items.length; j++) {
temp.push($(items[j]));
if (temp.length == 5) {
currentList = addNewList(currentList, temp);
temp = [];
}
}
if (temp.length > 0) {
currentList = addNewList(currentList, temp);
}
}
}
}
splitLists();
}
After some clarification via comments it seems you are looking for something like this. I have commented the code to explain the logic behind the process:
// function for adding a new LI item.
function addNewList(current, newItems) {
// Create the new li node.
var newList = $('<li class="parent-menu parent">');
// Add the initial a link.
newList.append('test<span class="toggle"></span>');
// Create and append the submenu-wrapper div to our new list item.
var div = $('<div class="submenu-wrapper">');
newList.append(div);
// Create and append the new ul node to our submenu-wrapper div.
var ul = $('<ul class="plain">');
div.append(ul);
// Loop the 5 (or less) items that have been specified and add them to our new list.
for (var i = 0; i < newItems.length; i++) {
// Using append will move the elements that already exist in the original place.
ul.append(newItems[i]);
}
// Add our new list item to the DOM.
current.after(newList);
return newList;
}
// Base function to split the lists as required.
function splitLists() {
// Get all the lists that we want to process.
var allLists = $(".plain > li.parent-menu");
// Loop each list and process.
for (var i = 0; i < allLists.length; i++) {
var currentList = $(allLists[i]);
// Get the sub-items that we need to split.
var items = currentList.find("li");
// We only care about lists that are more than 5 items.
if (items.length > 5) {
// Create array to store the items that we want to move (any after first 5)
var temp = [];
// Start at the 6th item an start moving them in blocks of 5.
for (var j = 5; j < items.length; j++) {
// Add the item to move to our temp array.
temp.push($(items[j]));
// If we have 5 in our temp array then move them to new list.
if (temp.length == 5) {
// Move items with helper function.
currentList = addNewList(currentList, temp);
// Clear the temp array ready for the next set of items.
temp = [];
}
}
// If we have any spare ones that didn't get handle in the length == 5 check, then process them now.
if (temp.length > 0) {
currentList = addNewList(currentList, temp);
}
}
}
}
// Run the process.
splitLists();
Here is a working example
I want to append the <li> from one <ul> to another <ul> that's created on the fly. I want to group the list-items into new sub-lists based on their data-group attribute.
<ul id="sortable1">
<li data-group="A">test</li>
<li data-group="A">test1</li>
<li data-group="B">test2</li>
<li data-group="B">test3</li>
<li data-group="C">test4</li>
</ul>
Basically I'm trying to loop through this list and grap all <li> from each group, and then move it to another <ul>.
This is what I have so far, but I'm not getting the expected results. I have done this in Excel in the past but can't get it to work with jQuery.
var listItems = $("#sortable1").children("li");
listItems.each(function (idx, li) {
var product = $(li);
//grab current li
var str = $(this).text();
if (idx > 0) {
//append li
str += str;
if ($(this).data("group") != $(this).prev().data("group")) {
//I should be getting test and test1.
//but alert is only giving test1 test1.
alert(str);
//need to break into groups
//do something with groups
}
}
});
How about something like this:
$(function() {
var sortable = $("#sortable1"),
content = $("#content");
var groups = [];
sortable.find("li").each(function() {
var group = $(this).data("group");
if($.inArray(group, groups) === -1) {
groups.push(group);
}
});
groups.forEach(function(group) {
var liElements = sortable.find("li[data-group='" + group + "']"),
groupUl = $("<ul>").append(liElements);
content.append(groupUl);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="sortable1">
<li data-group="A">test</li>
<li data-group="A">test1</li>
<li data-group="B">test2</li>
<li data-group="B">test3</li>
<li data-group="C">test4</li>
</ul>
<div id="content">
</div>
I hope I didn't misunderstand you.
I know this is a pretty basic question I just seem to be having some issues doing it. I have a HTML structure like below.
<ul>
<li>
<ul class=t2 id=15>
<li class='item'>a<span class='val'>b</span></li>
<li class='item'>c<span class='val'>d</span></li>
<li class='item'>e<span class='val'>f</span></li>
<li class='item'>parameters : </li>
<li>
<ul class=t3 id=16>
<li>
<ul class=t4 id=17></ul>
</li>
<li>
<ul class=t4 id=18></ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
I have the UL with the id of 16 selected and I want to select all its child ul nodes and grab there id. I am able to select the ul with an id of 17 but I cannot grab it's sister node. Here is the JavaScript I am using to get the child nodes.
if (document.getElementById(this.toDelete[i]).getElementsByTagName('ul').length >= 1) {
var tag = document.getElementById(this.toDelete[i]).getElementsByTagName('ul');
for (var k = 0; k <= tag.length; k++) {
console.log("tag name: " + tag[k].id + " these will be pushed to Delete");
}
}
So the logic should be, the the selected UL has child ULs get the ID of those ULs and print them to the console.
The above code does not work. I believe that is because it is grabbing the which does not have a id. But it also if I change it to k < tag.length it works, but still only gets 17 and I want to it get 18 as well.
Please help. Thanks in advance.
UPDATED, full function. the items array is an array of objects with html and id properties, toDelete is an array with just numbers (ids of items to be deleted. The html in items.html corresponds to one line of html. IE 'ab'. The function is a bit of a mess since I am just trying to get it to work properly. I know I can make it cleaner, that is why I did not post the whole function.
deleteItems: function () {
for (var i = 0; i < this.toDelete.length; i++) {
console.log("Item to be deleted: " + this.toDelete[i]);
for (var j = 0; j < this.items.length; j++) {
if (this.items[j].id == this.toDelete[i]) {
this.items[j] = ""; //this should be a slice
if (document.getElementById(this.toDelete[i]).getElementsByTagName('ul').length >= 1) {
var tag = document.getElementById(this.toDelete[i]).getElementsByTagName('ul');
for (var k = 0; k <= tag.length; k++) {
console.log("tag name: " + tag[k].id + " these will be pushed to Delete");
}
this.toDelete.push(document.getElementById(this.toDelete[i]).getElementsByTagName('ul')[0].id);
//check to see if it has those there sister nodes.
}
}
}
}
},
You can use children to get each child node, and then you can check to ensure the found node is a ul by using JavaScript's nodeName. To be extra safe I used toLowerCase() to guarantee that the nodeName looks like ul and not UL
deletedItems();
function deletedItems() {
var ulChildren = document.getElementById('ul16').children;
var childrenLength = ulChildren.length;
alert(childrenLength);
for(var i = 0; i < childrenLength; i++){
if(ulChildren[i].children[0].nodeName.toLowerCase() === 'ul'){
alert("found one, the id is: " + ulChildren[i].children[0].id);
}
}
}
Live Example
Also, I modified your HTML a bit:
<ul>
<li>
<ul class=t2 id=15>
<li class='item'>a<span class='val'>b</span></li>
<li class='item'>c<span class='val'>d</span></li>
<li class='item'>e<span class='val'>f</span></li>
<li class='item'>parameters : </li>
<li>
<ul class="t3" id="ul16">
<li>
<ul class=t4 id="ul17"></ul>
</li>
<li>
<ul class="t4" id="ul18"></ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>