I have a list when click on the button of each record in the list I delete it.
I use this HTML5 on Anroaid by PhoneGap wrapper, on a computer the Record is deleted, on Android not! What could be the reason?
Here my code:
My list:
<ul id="MyList" data-role="listview" data-divider-theme="b" data-inset="true">
</ul>
I fill the list with this function:
function FillBookMarkListByStation() {
var ul = $("#MyList");
for (var i = 0; i < Local.length; i++) {
var newLI = document.createElement("LI");
ul.appendChild(newLI);
newLI.innerHTML = '<a href="xxx.html" onclick="x();" > <p>...</p>' +
'<a id="btnClear' + i + '" data-role="button" data-icon="delete" data-theme="b"></a>
</a>';
$("#btnClear" + i).click(function () { Clear(ul, newLI); });
}
$('ul').listview('refresh');
}
Function clear:
function Clear(List, Delete) {
//Remove from the list
List.removeChild(Delete);
//Remove from the local storage
for (var i = 0; i < Local.length; i++) {
//Checking is variable for check the data in the item
if (Local[i].Checking == Delete.dataset.checking) {
if (Local.length == 1)
Local= [];
else {
for (var j = i; j < Local.length - 1; j++) {
Local[i] = Local[i] + 1;
}
Local.length--;
}
Local["loc"] = JSON.stringify(Local);
}
}
}
On computer works fine,
on Android is delete from the screen but not from loacl storage,
on presentation of the list is still showing the deleted item.
Problem solved, android will not know the dataset and therefore is stuck ..
Related
Alright so I hope Im just missing something easy. Basically I am making a todo list where I want to have a checkbox appear with each list item (this works). When users click on the checkbox, the textDecoration = "line-through" is supposed to go through the listItem class. Meaning a line goes through the todo task the person creates. Here is the code I am mainly working with:
function show() {
var todos = get_todos();
var html = '<ul>';
for(var i=0; i < todos.length; i++) {
html += '<span><li class="listItem" style="float:left;">' + todos[i] + '</li><input class="checkBox" type="checkbox">' + '<button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>';
};
html += '</ul>';
document.getElementById('todos').innerHTML = html;
var buttons = document.getElementsByClassName('remove');
for (var i=0; i < buttons.length; i++) {
buttons[i].addEventListener('click', remove);
};
////////////////////////////////////
//Everything above here works. Below is the checkbox issue
var checkBox = document.getElementsByClassName("checkBox");
var listItem = document.getElementsByClassName("listItem");
for (var i=0; i < checkBox.length; i++) {
if (checkBox.checked == true){
listItem.style.textDecoration = "line-through";
}else {
listItem.style.textDecoration = "none";
}
};}
Where I'm at now is if I create an onClick function in the original checkbox, I can use that if/else statement and it kind of works. It will not work if I set the checkBox/listItems variables using document.getElementsByClassName but it will work if I use document.getElementById. The problem is that it only works on the first task that the user creates and none of the other ones created after. Im assuming that is either because Ids only work for one element (unlike a class that works for multiple) or because its not cycling through a for loop like it is in the code above.
TL/DR Basically when I run the code above I keep getting "Uncaught TypeError: Cannot set property 'textDecoration' of undefined
at show (todo.js:57)
at todo.js:75".
I dont get this error when I make a separate function for the checkbox and use elementbyid instead of elementsbyclass (changing the id/class of the html section above too)
I really want to get those line-through effects working on all tasks, not just the first one. Any ideas are greatly appreciated. Thanks everyone!
I would accomplish this with css instead of javascript (that's generally my rule, when possible). In this case you have to make one small change to your markup: since there's no previous-sibling selector, you'll have to put the inputs before the corresponding lis, but since the lis are float:left it still renders exactly the same.
input:checked + li {
text-decoration:line-through;
}
<ul>
<span><input class="checkBox" type="checkbox"><li class="listItem" style="float:left;">foo</li><button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>
<span><input class="checkBox" type="checkbox"><li class="listItem" style="float:left;">bar</li><button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>
<span><input class="checkBox" type="checkbox"><li class="listItem" style="float:left;">baz</li><button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>
</ul>
function show() {
var todos = get_todos();
var html = '<ul>';
for (var i = 0; i < todos.length; i++) {
html += '<span><li class="listItem" style="float:left;">' + todos[i] + '</li><input class="checkBox" type="checkbox">' + '<button class="remove" id="' + i + '"><i class="fa fa-trash" aria-hidden="true"></i></button></span><br/>';
};
html += '</ul>';
document.getElementById('todos').innerHTML = html;
var buttons = document.getElementsByClassName('remove');
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', remove);
};
////////////////////////////////////
//Everything above here works. Below is the checkbox issue
var checkBox = document.getElementsByClassName("checkBox");
var listItem = document.getElementsByClassName("listItem");
for (var i = 0; i < checkBox.length; i++) {
if (checkBox[i].checked == true) {
listItem[i].style.textDecoration = "line-through";
} else {
listItem[i].style.textDecoration = "none";
}
};
}
You probably missed the index in the listItem and checkBox array
I think the problem is that checkBox is an array-like object. I think you know that as when you wrote the code you look at checkBox.length, however you then failed to index into the array.
You have:
var checkBox = document.getElementsByClassName("checkBox");
var listItem = document.getElementsByClassName("listItem");
for (var i=0; i < checkBox.length; i++) {
if (checkBox.checked == true){
listItem.style.textDecoration = "line-through";
}else {
listItem.style.textDecoration = "none";
}
};}
To make it clear I've pluralised the names where needed, as well as adding the index reference:
var checkBoxes = document.getElementsByClassName("checkBox");
var listItems = document.getElementsByClassName("listItem");
for (var i=0; i < checkBoxes.length; i++) {
if (checkBoxes[i].checked == true){
listItems[i].style.textDecoration = "line-through";
}else {
listItems[i].style.textDecoration = "none";
}
};}
I have a for loop which looks like this:
for (var i = 0; i < list.length; i++) {
It is looping through Firebase data in the database and returning all the data in the database.
However, I want it to only go up to the first 10 database items. So I changed the loop to:
for (var i = 0; i < 9; i++) {
But this fails to display any results when the there are less than 10 pieces of data in the database. However, if I set the number to however many objects I have in the database, for example 10 because I have 10 objects, it displays them all. But any less than this number and I just get a blank webpage.
Here is the webpage when I have 10 objects in my Firebase database:
And here it is when I remove one of those objects:
I have no idea why this is happening - The logic is correct - if i is less than 9 then display the data - But instead it only displays it when it equals 9.
Here is the full JS:
function refreshUI(list) {
var lis = '';
var lis2 = '';
var lis3 = '';
var lis4 = '';
for (var i = 0; i <= 9; i++) {
lis += '<li data-key="' + list[i].key + '" onclick="addText(event)">' + list[i].book + '</li>';
lis2 += genLinks(list[i].key, list[i].book)
};
for (var i = 10; i < list.length; i++) {
lis3 += '<li data-key="' + list[i].key + '" onclick="addText(event)">' + list[i].book + '</li>';
lis4 += genLinks(list[i].key, list[i].book)
};
document.getElementById('bookList').innerHTML = lis;
document.getElementById('bookList2').innerHTML = lis2;
document.getElementById('bookList3').innerHTML = lis3;
document.getElementById('bookList4').innerHTML = lis4;
};
function genLinks(key, bkName) {
var links = '';
links += '<img src="images/bin.png" style="width: 24px; height: 24px; transform: translateY(-7px); opacity: .4;"></img> ';
return links;
};
function del(key, bkName) {
var response = confirm("Are certain about removing \"" + bkName + "\" from the list?");
if (response == true) {
// build the FB endpoint to the item in movies collection
var deleteBookRef = buildEndPoint(key);
deleteBookRef.remove();
}
}
function buildEndPoint (key) {
return new Firebase('https://project04-167712.firebaseio.com/books/' + key);
}
// this will get fired on inital load as well as when ever there is a change in the data
bookList.on("value", function(snapshot) {
var data = snapshot.val();
var list = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
book = data[key].book ? data[key].book : '';
if (book.trim().length > 0) {
list.push({
book: book,
key: key
})
}
}
}
// refresh the UI
refreshUI(list);
});
If anybody has any help I'd greatly appreciate it!
When the list size is shorter than 10, you will get an error in the loop because you will eventually address a property (like key) that does not exist on list[i] (since it is undefined). If you would check the console, you would notice that this error is reported.
To fix this, change the condition of the first for loop like this:
for (var i = 0; i < Math.min(10, list.length); i++) {
This way, the loop will never iterate to an entry that does not exist. It will stop after 9 or after list.length-1 whichever comes first.
Alternatively, you can just put the two conditions with an && operator:
for (var i = 0; i < 10 && i < list.length; i++) {
Update: I've tried the suggestions in the comments and it's still not working. I really have no idea why. I've consolidated it to a single loop and fixed the syntax errors noted. Here's the code as it looks now:
$(function() {
$("#json-one").change(function() {
var $dropdown = $(this);
$.getJSON("washroutines.json", function(data) {
var vals = [];
var $jsontwo = $("#json-two");
$jsontwo.empty();
for (var i = 0; i < data.length; i++){
if (data[i].make === $dropdown.val()) {
$jsontwo.append("<option value=\"" + data[i].model + "\">" + data[i].model + "</option>");
}
}
});
});
});
Any additional help would be much appreciated!
Original question:
I'm trying to create dependent drop down menus using a json object, and I'm having trouble getting the second menu to populate based on the first. When the first menu changes, the second goes to a bunch of "undefined"s.
$.getJSON("washroutines.json", function(data) {
var vals = [];
for (i = 0; i < data.length; i++){
if (data.make = $dropdown.val()) {
vals.push(data.model);
}
}
var $jsontwo = $("#json-two");
$jsontwo.empty();
for (i = 0; i < vals.length; i++){
$jsontwo.append("<option value\"" + vals[i] + "\">" + vals[i] + "</option>");
}
Please use small words when explaining things to me, I'm new at this!
contents of the JSON:
[{"make":"Maytag","model":"Bravos","prewashCycle":"Whitest Whites"},
{"make":"Maytag","model":"Awesome","prewashCycle":"Awesome Whitest Whites"},
{"make":"Whirlpool","model":"Cabrio","prewashCycle":"Extra Heavy"},
{"make":"Kenmore","model":"Elite","prewashCycle":"Awesome"}]
Try changing your for loop for this
for (var i = 0; i < data.length; i++){
if (data[i].make === $dropdown.val()) {
vals.push(data[i].model);
}
}
Here's what I am trying to do:
Let user create category (done)
Add that category to local storage (done)
Add that category to a list on the screen (done)
Attach an event to that category, so when a user clicks on it, it will show all the posts in that category.
I want to have 1 function (or eventlistener, whatever you want to call it) that handles all the clicks. It has to know for which category it has to sort some posts and that is the point where I am stuck.
This is my code that does step 1 and 2:
document.getElementById("newCategoryButton").onclick = function ()
{
var input = document.getElementById("newCategoryInput");
var li = document.createElement('li');
li.innerHTML = "<a href='#' id='sort" + input.value + "'>" + input.value + "</a></li>";
localStorage.setItem(input.value, input.value);
document.getElementById("categories").appendChild(li);
}
This is the code for step 3. The important stuff happens at the else
for (var i = 0, len = localStorage.length; i < len; ++i) {
if (localStorage.key(i).indexOf("formObject") > -1) {
var value = JSON.parse(localStorage.getItem(localStorage.key(i)));
addRow(value);
} else {
var li = document.createElement('li');
li.className = "category";
li.innerHTML = "<a href='#' id='sort" + localStorage.getItem(localStorage.key(i)) + "'>" + localStorage.getItem(localStorage.key(i)) + "</a></li>";
document.getElementById("categories").appendChild(li);
And this is the code for step 4:
var categories = document.getElementsByClassName("category");
for (var i = 0; i < categories.length; ++i) {
categories[i].addEventListener("Click", SortPosts(categories[i].textContent));
}
function SortPosts(value)
{
alert(value);
//Sort coding here
}
When the page loads, it automatically alerts the value of SortPosts(), without clicking on anything. What is wrong with my code? Also, am I giving all the categories click events or am I doing that wrong, as well?
on the line:
categories[i].addEventListener("Click", SortPosts(categories[i].textContent));
you are calling the function Sort posts and binding the result to the click event. try this:
categories[i].addEventListener("Click", function(i){
return function(){
SortPosts(categories[i].textContent);
}
}(i));
note the closure around the i variable to keep it in scope
Edit: it occured to me after submitting this, while the code is fairly compact, it is not particularly easy to read especially if you are not familiar wih closures, so here is a slightly more verbose, easier to read version:
categories[i].addEventListener("Click", getPostSorter(i));
function getPostSorter(i) {
return function(){
SortPosts(categories[i].textContent);
}
}
Try this, you can get the textContent after the function is called.
function MyEvents(){
var categories = document.getElementsByClassName("category");
for (var i = 0; i < categories.length; ++i) {
categories[i].addEventListener("click", SortPosts,false);
}
}
function SortPosts(){
alert(event.target.textContent);
//Sort coding here
}
window.onload=MyEvents;
<div class="category">Click for category one</div>
<div class="category">Click for category two</div>
I'm trying to assign a id to each link in my list like this,
for (var j = start; j < stop; j++) {
link = linkBase + json[j].relatedItemId;
$('#citations').append('<li><a href="' + link + '" id="num" + j>' +
json[j].title + '</a></li>');
alert($('a').attr('id'));
}
it keeps giving me undefined or 0? Should I use $.each outside of the for loop instead?
I was trying to use the for loop for two purposes but maybe that's not such a great idea?
*EDIT***
If I put my for loop inside of a function like,
// Loop function for each section
var loopSection = function(start, stop) {
// Http setup for all links
var linkBase = "http://www.sciencebase.gov/catalog/item/";
// Link for citation information
var link = "";
for (var j = start; j < stop; j++) {
link = linkBase + json[j].relatedItemId;
var $anchor = $("<a>", {
href: link,
id: "id" + j,
text: json[j].title
})
// .parent() will get the <li> that was just created and append to the first citation
element
$anchor.appendTo("<li>").parent().appendTo("#citations");
}
}
I'm not able to access the id from outside of the function
$('#citations').on('click', function (e) {
e.preventDefault();
var print = ($(this).attr('id'));
alert(print);
});
This form is much cleaner:
for (var j = start; j < stop; j++) {
link = linkBase + json[j].relatedItemId;
$("<a>", {
href: link,
id:'num' + j,
text: json[j].title
}).appendTo("<li>")
.parent() // get the <li> we just made
.appendTo("#citations");
}
If you want a reference to the anchor tag you created, do this:
for (var j = start; j < stop; j++) {
link = linkBase + json[j].relatedItemId;
var $anchor = $("<a>", {
href: link,
id:'num' + j,
text: json[j].title
});
$anchor.appendTo("<li>").parent().appendTo("#citations");
}
You have a syntax error in your code (id="num" + j..)
However,You should do this by the code (avoiding syntax error and giving a better performance)
for (var j = start; j < stop; j++)
{
var link = linkBase + json[j].relatedItemId;
$('#citations').append($(document.createElement('li'))
.append($(document.createElement('a'))
.attr('href', link)
.attr('id', 'num' + j)
.html(json[j].title)));
}
Agree with the answer from Schmiddty but, for the sake of completeness
for (var j = 0; j < 10; j++) {
var link = "someLink.htm";
$('#citations').append('<li>'+ 'click here' + '</li>');
alert($('#citations a:last').attr('id'));
}
I've only changed your variable to make it work on its own on this fiddle as a demo