I have a list of question in my javascript file. Each question has a question number and question description and options. A question can be added anywhere in the list of questions. So if a question is added into the top of all questions, then i need to change the question numbers of all the below ones. How can achieve this. Can i use javascript for this?
I would suggest using an <ol> for each question, and let the page handle reflowing the numbers.
Otherwise you'll need to set a target number before inserting, and for each element in the list you'll check to see if it's number is greater than the target, and then if so increment the number by one.
var Target = //new number that I want the inserted question to be
foreach (element in list) {
if (element.Number > Target) element.Number += 1;
}
list.add( //new question with # set to Target );
This works.
<ol id="questions_list"></ol>
var questions = ["A foo walks into a bar. What happens?", "Why did foo cross the road?"];
addQuestion("foo", 1);
function addQuestion(question, position)
{
if(position > 0 && position < questions.length)
{
var firstHalf = questions.slice(0, position);
var secondHalf = questions.slice(position, questions.length);
firstHalf.push(question);
questions = firstHalf.concat(secondHalf);
console.log("slice");
}else if(position <= 0)
{
questions.unshift(question);
console.log("beginning");
}else if(position >= questions.length)
{
questions.push(question);
console.log("end");
}
updateQuestionList();
}
function updateQuestionList()
{
var questions_list = document.getElementById("questions_list");
questions_list.innerHTML = "";
for(var i=0;i<questions.length;i++)
{
var question = document.createElement("LI");
question.innerHTML = questions[i];
questions_list.appendChild(question);
}
}
http://jsfiddle.net/jPxwW/1/
Array prototype ( fun! =) ):
// zero-based insert
Array.prototype.insert = function(index, item) {
var i = 0, list = [];
if (this.length == index) {
list = this;
list.push(item);
return list;
}
for(; i < this.length; i++) {
if (index == list.length) {
list.push(item);
i--;
} else {
list.push(this[i]);
}
}
return list;
};
Array.prototype.print = function (base) {
base = base || 1;
for (var i = 0, out = []; i < this.length; i++) {
out.push((base + i) + '. ' + this[i]);
}
return out.join("\n");
};
list = ['when?', 'where?', 'why?'];
list = list.insert(0, 'who?'); // first: ["who?", "when?", "where?", "why?"]
list = list.insert(3, 'how?'); // 4th: ["who?", "when?", "where?", "how?", "why?"]
list = list.insert(list.length, 'last?'); // last: ["who?", "when?", "where?", "how?", "why?", "last?"];
list.print();
/**
"1. who?
2. when?
3. where?
4. how?
5. why?
6. last?"
**/
You could do something like this using ordered lists (ol) and jQuery:
<html>
<head>
<script src="http://code.jquery.com/jquery-1.4.4.min.js" type="text/javascript"></script>
<script type ="text/javascript">
$(function(){
var n = 2;
$('button').delegate('click', function(){
$(this).parents('li').after('<li><p><span>Question'+n+'</span><button>Create new question</button></p></li>');
n += 1;
})
})
</script>
</head>
<body>
<ol>
<li>
<p><span>Question 1</span><button>Create new question</button></p>
</li>
</ol>
</body>
</html>
Related
This question already has answers here:
How to count duplicate value in an array in javascript
(35 answers)
Closed 7 years ago.
I have two arrays of zip codes. The first array has many zip codes including duplicates. The second array has the duplicates removed to show only the unique zip codes.
How can I check how many times each unique zip code appears in the zip code containing duplicates?
For example, if I have two values for 21218, how can I check that there are two values? I would like to iterate through the unique name array if possible to check against the duplicate name array.
Edit: This question is similar to this previously asked question here. However, it differs because the goal is to use the existing code and incorporate it into the solution.
var url = 'https://data.baltimorecity.gov/resource/uds6-qsb6.json?$limit=50000';
var manyZipArray = [];
var zipArray = [];
$(document).ready(function() {
$.getJSON(url, function(data) {
for (var i = 0; i < data.length; i++) {
manyZipArray.push(data[i].zip);
};
$.each(manyZipArray, function(i, el) {
if ($.inArray(el, zipArray) === -1) zipArray.push(el);
});
zipArray.sort();
for (var i = 0; i < zipArray.length; i++) {
$('#myList').append("<li>" + zipArray[i] + "</li>");
};
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3 style="text-align: center" ;>Unique Zip Codes </h3>
<ul id="myList"></ul>
You can use a javascript object to store the number of occurences of each zip code by setting a new key of the object using the zip code.
See code below:
var url = 'https://data.baltimorecity.gov/resource/uds6-qsb6.json?$limit=50000';
var manyZipArray = [];
var zipArray = [];
var numberOfZips = {};//object to hold the counters
$(document).ready(function() {
$.getJSON(url, function(data) {
for (var i = 0; i < data.length; i++) {
manyZipArray.push(data[i].zip);
if (data[i].zip in numberOfZips){
numberOfZips[data[i].zip] += 1;
}else{
numberOfZips[data[i].zip] = 1;
}
};
$.each(manyZipArray, function(i, el) {
if ($.inArray(el, zipArray) === -1) zipArray.push(el);
});
zipArray.sort();
for (var i = 0; i < zipArray.length; i++) {
$('#myList').append("<li>" + zipArray[i] +","+numberOfZips[zipArray[i]]+ "</li>");
};
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3 style="text-align: center" ;>Unique Zip Codes </h3>
<ul id="myList"></ul>
I would do a loop that iterates the non-duplicate array, and for each zip value, iterate the full array and count it's appearances. In my example code below I store the values in a new array, but you can do whatever you need with them.
var zipOcurrences = array();
var i = 0;
zipArray.each(function(){
zipOcurrences[i] = 0;
var zip = $(this);
manyZipArray.each(function(){
if ($(this)==zip){
zipOcurrences[i]++;
}
});
i++;
});
You can replace the codes in your zipArray array with objects containing the zipcode and the number of occurences
var url = 'https://data.baltimorecity.gov/resource/uds6-qsb6.json?$limit=50000';
var manyZipArray = [];
var zipArray = [];
$(document).ready(function() {
$.getJSON(url, function(data) {
for (var i = 0; i < data.length; i++) {
manyZipArray.push(data[i].zip);
};
$.each(manyZipArray, function(i, el) {
// custom search in array
var index = arrayObjectIndexOf(zipArray, el, "code");
if (index === -1) {
zipArray.push({ code: el, occur: 1 });
}
else {
zipArray[index].occur++;
}
});
// custom sort to sort according to 'code' attribute
zipArray.sort(function(a, b) {
if (a.code< b.code) return -1;
if (a.code > b.code) return 1;
return 0;
});
for (var i = 0; i < zipArray.length; i++) {
$('#myList').append("<li>" + zipArray[i].code + " (" + zipArray[i].occur + ")</li>");
};
});
});
function arrayObjectIndexOf(myArray, searchTerm, property) {
for(var i = 0, len = myArray.length; i < len; i++) {
if (myArray[i][property] === searchTerm) return i;
}
return -1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h3 style="text-align: center" ;>Unique Zip Codes </h3>
<ul id="myList"></ul>
I thought this would be easier, but running into a weird issue.
I want to split the following:
theList = 'firstword:subwordone;subwordtwo;subwordthree;secondword:subwordone;thirdword:subwordone;subwordtwo;';
and have the output be
firstword
subwordone
subwordtwo
subwordthree
secondword
subwordone
thirdword
subwordone
subwordtwo
The caveat is sometimes the list can be
theList = 'subwordone;subwordtwo;subwordthree;subwordfour;'
ie no ':' substrings to print out, and that would look like just
subwordone
subwordtwo
subwordthree
subwordfour
I have tried variations of the following base function, trying recursion, but either get into infinite loops, or undefined output.
function getUl(theList, splitOn){
var r = '<ul>';
var items = theList.split(splitOn);
for(var li in items){
r += ('<li>'+items[li]+'</li>');
}
r += '</ul>';
return r;
}
The above function is just my starting point and obviously doesnt work, just wanted to show what path I am going down, and to be shown the correct path, if this is totally off base.
It seems you need two cases, and the difference between the two is whether there is a : in your string.
if(theList.indexOf(':') == -1){
//Handle the no sublist case
} else {
//Handle the sublist case
}
Starting with the no sublist case, we develop the simple pattern:
var elements = theList.split(';');
for(var i = 0; i < elements.length; i++){
var element = elements[i];
//Add your element to your list
}
Finally, we apply that same pattern to come up with the implementation for the sublist case:
var elements = theList.split(';');
for(var i = 0; i < elements.length; i++){
var element = elements[i];
if(element.indexOf(':') == -1){
//Add your simple element to your list
} else {
var innerElements = element.split(':');
//Add innerElements[0] as your parent element
//Add innerElements[1] as your child element
//Increment i until you hit another element with ':', adding the single elements each increment as child elements.
//Decrement i so it considers the element with the ':' as a parent element.
}
}
Keep track of the current list to add items to, and create a new list when you find a colon in an item:
var baseParent = $('ul'), parent = baseParent;
$.each(theList.split(';'), function(i, e) {
if (e.length) {
var p = e.split(':');
if (p.length > 1) {
baseParent.append($('<li>').append($('<span>').text(p[0])).append(parent = $('<ul>')));
}
parent.append($('<li>').text(p[p.length - 1]));
}
});
Demo: http://jsfiddle.net/Guffa/eWQpR/
Demo for "1;2;3;4;": http://jsfiddle.net/Guffa/eWQpR/2/
There's probably a more elegant solution but this does the trick. (See edit below)
function showLists(text) {
// Build the lists
var lists = {'': []};
for(var i = 0, listKey = ''; i < text.length; i += 2) {
if(text[i + 1] == ':') {
listKey = text[i];
lists[listKey] = [];
} else {
lists[listKey].push(text[i]);
}
}
// Show the lists
for(var listName in lists) {
if(listName) console.log(listName);
for(var j in lists[listName]) {
console.log((listName ? ' ' : '') + lists[listName][j]);
}
}
}
EDIT
Another interesting approach you could take would be to start by breaking it up into sections (assuming text equals one of the examples you gave):
var lists = text.match(/([\w]:)?([\w];)+/g);
Then you have broken down the problem into simpler segments
for(var i = 0; i < lists.length; i++) {
var listParts = lists[i].split(':');
if(listParts.length == 1) {
console.log(listParts[0].split(';').join("\n"));
} else {
console.log(listParts[0]);
console.log(' ' + listParts[1].split(';').join("\n "));
}
}
The following snippet displays the list depending on your requirements
var str = 'subwordone;subwordtwo;subwordthree;';
var a = []; var arr = [];
a = str;
var final = [];
function split_string(a){
var no_colon = true;
for(var i = 0; i < a.length; i++){
if(a[i] == ':'){
no_colon = false;
var temp;
var index = a[i-1];
var rest = a.substring(i+1);
final[index] = split_string(rest);
return a.substring(0, i-2);
}
}
if(no_colon) return a;
}
function display_list(element, index, array) {
$('#results ul').append('<li>'+element+'</li>');
}
var no_colon_string = split_string(a).split(';');
if(no_colon_string){
$('#results').append('<ul><ul>');
}
no_colon_string.forEach(display_list);
console.log(final);
working fiddle here
Hi I am trying to compare two arrays to each other and then hide a list element if any of the values match.
One array is tags that are attached to a list item and the other is user input.
I am having trouble as I seem to be able to cross reference one user input work and can't get multiple words against multiple tags.
The amount of user input words might change and the amount of tags might change. I have tried inArray but have had no luck. Any help would be much appreciated. See code below:
function query_searchvar() {
var searchquery=document.navsform.query.value.toLowerCase();
if (searchquery == '') {
alert("No Text Entered");
}
var snospace = searchquery.replace(/\s+/g, ',');
event.preventDefault();
var snospacearray = snospace.split(',');
$('li').each(function() {
var searchtags = $(this).attr('data-searchtags');
//alert(searchtags);
var searcharray = searchtags.split(',');
//alert(searcharray);
var searchtrue=-1;
for(var i = 0, len = searcharray.length; i < len; i++){
if(searcharray[i] == searchquery){
searchtrue = 0;
break;
}
}
if (searchtrue == 0) {
$(this).show("normal");
}
else {
$(this).hide("normal");
}
});
}
Okay so I've tried to implement the code below but have had no luck. It doesn't seem to check through both arrays.
function query_searchvar()
{
var searchquery=document.navsform.query.value.toLowerCase();
if(searchquery == '')
{alert("No Text Entered");
}
var snospace = searchquery.replace(/\s+/g, ' ');
event.preventDefault();
var snospacearray = snospace.split(' ');
alert(snospacearray[1]);
$('li').each(function() {
var searchtags = $(this).attr('data-searchtags');
alert(searchtags);
var searcharray = searchtags.split(' ');
alert(searcharray[0]);
jQuery.each(snospacearray, function(key1,val1){
jQuery.each(searcharray,function(key2,val2){
if(val1 !== val2) {$(this).hide('slow');}
});
});
});
}
Working code:
function query_searchvar()
{
var searchquery=document.navsform.query.value.toLowerCase();
if(searchquery == '')
{alert("No Text Entered");
}
var queryarray = searchquery.split(/,|\s+/);
event.preventDefault();
$('li').each(function() {
var searchtags = $(this).attr('data-searchtags');
//alert(searchtags);
var searcharray = searchtags.split(',');
//alert(searcharray);
var found = false;
for (var i=0; i<searcharray.length; i++)
if ($.inArray(searcharray[i], queryarray)>-1) {
found = true;
break;
}
if (found == true )
{
$(this).show("normal");
}
else {
$(this).hide("normal");
}
});
}
var snospace = searchquery.replace(/\s+/g, ',');
var snospacearray = snospace.split(',');
Note that you can split on regular expressions, so to the above would equal:
var queryarray = searchquery.split(/,|\s+/);
To find whether there is an item contained in both arrays, use the following code:
var found = searcharray.some(function(tag) {
return queryarray.indexOf(tag) > -1;
});
Although this will only work for ES5-compliant browsers :-) To support the others, use
var found = false;
for (var i=0; i<searcharray.length; i++)
if ($.inArray(searcharray[i], queryarray)>-1) {
found = true;
break;
}
In plain js, without jQuery.inArray:
var found = false;
outerloop: for (var i=0; i<searcharray.length; i++)
for (var j=0; j<queryarray.length; j++)
if (searcharray[i] == queryarray[j]) {
found = true;
break outerloop;
}
A little faster algorithm (only needed for really large arrays) would be to sort both arrays before running through them linear.
Here's psuedo code that should solve your problem.
get both arrays
for each item in array 1
for each element in array 2
check if its equal to current element in array 1
if its equal to then hide what you want
An example of this coude wise would be
jQuery.each(array1, function(key1,val1){
jQuery.each(array2,function(key2,val2){
if(val1 == val2) {$(your element to hide).hide();}
});
});
If there's anything you don't understand please ask :)
Here's the deal. The task is to write a function which should be able determine the number of checkboxes checked for each question and prompt a user if more than 3 answers were selected.
I have a total of 8 questions and each question has 4 to 8 answers, in the checkbox format.
This is what I came up with:
function countChecks(){
var m = 0;
var n = 0;
chk = document.getElementsByName("DSelectionID");
for(var i=0; i<myitems.length i=""></myitems.length>
var value = myItems[i];
for(n = 0; n < value.length; n++) {
if(value[n].checked) {
m++;
}
}
return m;
}
the above function works fine for one question and returns 'm' to the main function, which handles it this way:
var check = countchecks();
if (check > 3)
alert ("more than 3 checkboxes were selected");
else {
//do the thing
}
to traverse all the 8 questions this is what I came up with:
function countChecks(){
var m = 0;
var n = 0;
//this captures id's for the right questions
chk = document.getElementsByName("DSelectionID");
chk2 = document.getElementsByName("DSelectionID2");
chk3 = document.getElementsByName("DSelectionID3");
chk4 = document.getElementsByName("DSelectionID4");
chk5 = document.getElementsByName("DSelectionID5");
chk6 = document.getElementsByName("DSelectionID6");
chk8 = document.getElementsByName("DSelectionID8");
chk9 = document.getElementsByName("DSelectionID9");
var myItems = new Array();
myItems[0]= chk;
myItems[1]= chk2;
myItems[2]= chk3;
myItems[3]= chk4;
myItems[4]= chk5;
myItems[5]= chk6;
myItems[6]= chk8;
myItems[7]= chk9;
//loops through all the questions
for(var i=0; i
var value = myItems[i];
//loops through the checkboxes for each question
for(n = 0; n < value.length; n++)
{
if( value[n].checked)
{
m++;
if (m > 3) {
return false;
}
}
}
}
}
and the main body handles it like this:
var check = countChecks()
if (check == false)
alert ("more than 3 checkboxes were selected");
else {
//do the thing
}
It is something very simple I'm missing in the countChecks() function
Any ideas?
Using jquery would make this pretty trivial
if ($('#yourform input[type=checkbox]:checked').length() > 3) {
alert('More than 3 checked');
}
chk = document.getElementsByName("DSelectionID"); does not grab the ID, it grabs a reference to the element in the DOM.
To get the ID you need to use:
chk = document.getElementsByName("DSelectionID").getAttribute("id")
Is there a way to have a self referencing 'list item' in html so when I reference a number or letter in an ordered list it keeps track of changes. Therefore, when I add or remove list items it automatically change the references to update to the new ordered list number or letter.
If this type of self referencing is not possible in older html versions how about in html5?
Also is this type of referencing available in javascript or a javascript framework like jQuery?
Given HTML like
<ol title="Figure 1">
<li id="poundcake">Pound Cake</li>
<li id="spongecake">Sponge Cake</li>
</ol>
<p>The most delicious from the list above is <label for="spongecake">.</p>
and then at the bottom (or onload),
<script>(function () {
// From http://stackoverflow.com/questions/5395177/ordered-list-index
function itemIndex(listItem) {
var index = 0;
for (var sibling = listItem; sibling;
sibling = sibling.previousSibling) {
if (sibling.tagName == "LI") {
var value = +sibling.value;
if (value) {
return value + index;
}
++index;
}
}
var start = +listItem.parentNode.start || 1;
return start + index - 1;
}
var labels = document.getElementsByTagName("label");
for (var i = 0, n = labels.length; i < n; ++i) {
var label = labels[i];
var id = label.getAttribute("for");
if (!id) { continue; }
var target = document.getElementById(id);
if (!target || target.tagName !== "LI") { continue; }
var replacementText = (target.parentNode.title || "")
+ " item " + itemIndex(target);
label.parentNode.replaceChild(
document.createTextNode(replacementText), label);
}
}())</script>
Maybe this will help: Ordered List Index