I have made a simple to-do list. But I want to make a list element have a text-decoration = line-through
When I click the button, the list item will be styled with a line-through and it will remain line-through even when I refresh the page or come back to it in a new request (I think local storage is needed).
I thought I could add a class with javascript but I couldn't find how I can do that with local storage.
Below is what I have tried:
HTML:
<ul id="a2">
<li>Make a ramen</li>
</ul>
<button type="button" id="ka" onclick="laylay()" class="" name="button">A</button>
CSS:
.done {
text-decoration: line-through;
}
JS:
function laylay() {
var as = document.getElementById("a2");
as.classList.add("done");
}
If you want to store the state of the list across session or requests and you have no backend storage for the list (meaning it is all stored on the client aka via the browser) you will need to use local storage.
Try this.
localStorage.setItem('a2', 'done');
Then when the page loads get the item from local storage and set the needed class.
localStorage.getItem('a2');
You will need to have an event that fires as soon as the document is ready that will look into your local storage and see if it finds the record it needs and if it does it updates the CSS style.
window.onload(function() {
var itemStyle = localStorage.getItem('a2');
var as = document.getElementById("a2");
as.classList.add(itemStyle);
}
This is not a very scalable solution but for your learning and simple example, it will work.
Try taking the HTML of the element, document.querySelector("#a2").innerHTML;, and saving it as a string in localStorage. And when you need to load it again, try checking if it exists in localStorage, then the string will be set as the innerHTML of #a2
You should have array of object stored in localstorage that look like something this:
[
{todo:'Do something', complete:false},
{todo:'Do something', complete:false},
]
Then when you render todos to page you make conditions based on object what styling your todo should have.
Eg.
let todos=localStorage.getItem('todos');
todos.map(item=>{
if(item.complete){
//code to add this item to page and put .style.textDecoration='line-trough'
}
else{
//code to put item to page
}
})
in order to store this kind of object you will need to stringify it when u set it and than when u use it u need to parse it.You can google it out how to do it.
If you are using some framework it will be much easier to render it on page the way you want, but it can be done with js it is just longer code.
Eg.
//Way to get items from localStorage
let todos=JSON.parse(localStorage.getItem("todos") || "[]");
//Way to set item
localStorage.setItem("todos",JSON.stringify(todos));
Related
First of all a disclaimer, I'm not a dev. I'm halfway through The Odin Project and have covered some HTML and CSS, but, have not yet started on JS. In order to help with my learning I've created my own blog. My aim is for each blog post to have its own stylesheet (so with each new post I learn a little more about CSS).
Anyway, I plan to write a post about the benefits of using an eReader, specifically the Kindle. I've styled the page to look like a Kindle Oasis, and I'd like the reader to be able to step through the article contents via the Kindle's next/prev buttons, but, as I'm not a dev, this is where I'm stuck. Via Stack overflow I've managed to add some JS that will display page 1, 2 and 3 via dedicated buttons for each dive element, but, what I really need is to step through x number of pages via the prev/next buttons.
Here's what I have so far: https://codepen.io/dbssticky/pen/yLVoORO. Any help would be much appreciated. What I should do of course is finish The Odin Project and come up with a solution on my own, but, I'd really like to get this Kindle article published sooner rather than later. Hence my rather cheeky request for assistance.
Here's the JS I'm currently using:
function swapContent(id) {
const main = document.getElementById("main_place");
const div = document.getElementById(id);
const clone = div.cloneNode(true);
while (main.firstChild) main.firstChild.remove();
main.appendChild(clone);
}
You have the right idea and it just needs a few adjustments to get the previous/next functionality.
Currently your div IDs are following the format operation1, operation2, and so on. Since you want the previous/next functionality you'll need to change your 'swapping' function, which currently takes the full ID, to use the numeric portion only.
Add a new function which appends the number to 'operation' instead of using the whole thing:
function goToPage(pageNumber){
const main = document.getElementById("main_place");
const div = document.getElementById("operation" + pageNumber);
const clone = div.cloneNode(true);
while (main.firstChild) main.firstChild.remove();
main.appendChild(clone);
}
And then change your Page 1/2/3 buttons to use goToPage(1), goToPage(2) and so on.
Now for the previous/next functionality you'll need a way to track which page you're on, so that you can figure out which page to load.
Add a variable at the top (outside functions)
var currentPage = 0;
Then add a line in your goToPage function to track the page you're on.
currentPage = pageNumber;
Now that you're tracking you can add a previous and next function.
function goNextPage(){
goToPage(currentPage-1);
}
function goPreviousPage(){
goToPage(currentPage+1);
}
Then call it from the previous and next buttons.
<button onClick="goNextPage()" class="next-button"></button>
<button onClick="goPreviousPage()" class="previous-button"></button>
Here's a codepen: https://codepen.io/srirachapen/pen/WNZOXQZ
It's barebones and you may have to handle things like non existent div IDs.
HTML
<button class="next-button" onclick="nextContent()"></button>
<button class="previous-button" onclick="prevContent()"></button>
JS
var pageid = 0;
var maxpage = 3;
function nextContent() {
if(pageid == maxpage) return
pageid++
swapContent(`operation${pageid}`)
}
function prevContent() {
if(pageid == 1) return
pageid--
swapContent(`operation${pageid}`)
}
you can try this to switch between pages. But you may need to edit the "swapContent" method more sensibly.
Track the Current Page
Whatever solution you use to render pages & links (manual hardcoded links & content vs externally-stored & auto-generated), one thing is unavoidable: You need to track the current page!
var currentPage = 0
Then, any time there's a page change event, you update that variable.
With the current page being tracked, you can now perform operations relative to it (e.g. +1 or -1)
I'd suggest making a goToPage(page) function that does high-level paging logic, and keep your swapContent() function specifically for the literal act of swapping div content. In the future, you may find you'd want to use swapContent() for non-page content, like showing a "Welcome" or "Help" screen.
Example:
function goToPage(page) {
// Update `currentPage`
currentPage = page
// ... other logic, like a tracking event or anything else you want you occur when pages change
// Do the actual content swap, which could be your existing swapContent()
swapContent('operation'+page)
}
You'd invoke the function like so:
goToPage(3) // Jump to a specific page
goToPage(currentPage + 1) // Go to the next page
goToPage(currentPage - 1) // Go to the prev page
You can make separate helper functions like "goToNextPage()" if you desire, but for sure you start with a fundamental page-change function first.
Dynamically swapping BODY content using jQuery html function works as expected with 'static' content.
But if forms are being used, current state of inputs is lost.
The jQuery detach function, which should keep page state, seems to be blanking out the whole page.
The following code is the initial idea using jQuery html but of course the text input value will always empty.
function swap1( ) {
$("body").html('<button onclick="swap2();">SWAP2</button><input type="text" placeholder="swap2"/>');
}
function swap2( ) {
$("body").html('<button onclick="swap1();">SWAP1</button><input type="text" placeholder="swap1"/>');
}
With not knowing what form inputs there are, how would one swap in and out these forms in the BODY and keep track of the form states?
Demo of two text inputs which should keep state when they come back into the BODY:
https://jsfiddle.net/g7hksfne/3/
Edit: missunderstood use case. This covers saving the state while manipulating the DOM, instead of switching between different states.
Instead of replacing the <body>'s content by serializing and parsing HTML, learn how to use the DOM. Only replace the parts of the DOM you actually change, so the rest of it can keep its state (which is stored in the DOM).
In your case: you might want to use something like this:
function swap1( ) {
document.querySelector("button").onclick = swap2;
document.querySelector("button").textContent = "SWAP2";
document.querySelector("input").placeholder = "swap2";
}
function swap2( ) {
document.querySelector("button").onclick = swap1;
document.querySelector("button").textContent = "SWAP1";
document.querySelector("input").placeholder = "swap1";
}
<button onclick="swap1();">SWAP1</button><input type="text" placeholder="swap1"/>
(This is not optimized and should only serve as an example.)
Put the content you want to save in a node below <body>, like a simple ยด` if you don't already have a container. When you want to save and replace the container, use something like:
var saved_container = document.body.removeChild(document.querySelector("#app_container");
// or document.getElementById/getElementsByClassName, depends on container
The element is now detached and you can add your secondary to document.body. When you want to get back, save the secondary content (without overwriting the first container of course), then reattach the primary content it with:
document.body.appendChild(savedContainer);
I was able to find a solution on Stackoverflow that display HTML "li" elements based on a filter (see attachement). Essentially based on css class'es defined in HTML elements, it populates the drop down list that you can select from.
I would like to be modify javascript below so that when you navigate to one of the "li" elements pages (as seen here: https://jsfiddle.net/quwfmepL/2/ e.g. Note: Chose one Test1 element and it goes to the page1.html page) ..but when you hit the back button on the page1.html to page where filter resides, it doesn't remember last filter choice. As it does now, you are required to filter same choice again. I think what I need to do is look at the browser history, but not sure if there is an easier option. I was hoping it could be in the format of query string or like.
<script type="text/JavaScript">
$(document).ready(function() {
var $tagList = $('#tag-list'),
optionArr = [];
$("#demo-list li a").each(function(index, item) {
$.each($(this).attr('class').split(' '), function(i, option){
if ($.inArray(option, optionArr) == -1) {
$tagList.append('<option value="'+option+'">'+option.replace('-', ' ').replace('_', ' ')+'</option>');
optionArr.push(option);
}
});
});
// Look at the URL for filter and modify here #
$tagList.on('change', function() {
var selection = $tagList.val();
if (selection == "all") {
$('#demo-list li a').show();
} else {
$('#demo-list li a').hide();
$('#demo-list li a.'+selection).show();
}
});
});
</script>
Any suggestions or hints? Any help is appreciated.
Fiddle is acting a bit strangely (not working) for me.
You may want to just set a cookie inside of the .change function, that'd probably be the easiest way to do it. When the filter page loads, check to see if the cookie is set, and if it is, run the filter based on the stored cookie value.
Try out: https://github.com/js-cookie/js-cookie
Alternatively, and probably even better, you can use webstorage (localstorage) to accomplish the same thing.
http://www.w3schools.com/html/html5_webstorage.asp
I am using two buttons to toggle css classes that either show or hide a background. I would like to save the current state of each class in local storage and display (or not display) them when the user returns. I have made an attempt with the wrapping class in this jsFiddle, but I don't have it working yet:
http://jsfiddle.net/eqrk6fak/1/
Setting it like so:
$("#switch2").click(function() {
wrap.fadeToggle(600);
if($('div').hasClass(wrap)){
localStorage.setItem('background', wrap);
}
});
And then trying to get it when the user returns:
$(document).ready(function(){
var background = localStorage.getItem('background');
if(background !== ''){
$('#wraping').addClass(background);
}
});
Any help would be appreciated. Thanks!
The problem is in the following line:
$('div').hasClass(wrap)
Reviewing your JSFiddle code, at that point wrap is a jQuery result:
var wrap = $(".wraping");
According to the documentation, jquery.hasClass receives a className which should be a String.
I'm a first time poster and I'm learning jQuery, so I'll try to formulate my words as best as possible.
On my site I have multiple pages that dynamically add up the lis and gives me a number.
That number is displayed this way: var totalOverallString = $("#overallTotal").html(total);
Currently I have two similar variables in two functions.
Everything is working correctly on the individual pages.
Now I want to take those two numbers, add them, and display that new number in my home page.
I want this to work dynamically like in my other pages.
The problem I run into is getting those numbers from the other pages.
I've tried .load and .getScript to extract the numbers. I've also tried doing a callback function, but the script loads and gives me the original declared variable: total = 0. This makes sense to me. It's not adding up the lis from the original page. Both variables are global.
I'm trying my best to wrap my head around how to do this. How do I get that dynamically added .html(total) from the other page?
Thanks for your time!
This is the only way I can think to do it without storing all the list items in a database or similar.
Example page 1 containing some list items, here called list-1.html:
<html>
<body>
<ul>
<li>One</li>
<li>Two</li>
</ul>
</body>
</html>
Example page 2 containing some list items, here called list-2.html:
<html>
<body>
<ul>
<li>Three</li>
<li>Four</li>
<li>Five</li>
</ul>
</body>
</html>
Example page where you want the count of list items to be displayed, in this case, your homepage:
<html>
<body>
<!-- Element to contain the total -->
<p>Total list items: <span id="count">counting...</span></p>
<!-- Include jQuery -->
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script>
(function() {
// Update this array of URLs to the pages containing <li>s that you want to count.
var urls = ["list-one.html", "list-two.html"];
var $hidden = $("<ul />").hide();
var total = 0;
// use jQuery's selective loading functionality to load LIs from each URL, count them, and add the count to a running total
for(var i = 0; i < urls.length; i++) {
$hidden.load(urls[i] + " li", function(responseText) {
total = total + $hidden.find("li").length;
// complete - update the count element.
if(i == urls.length) {
$("#count").html(total);
}
});
}
})();
</script>
</body>
</html>
So essentially we are requesting each page containing list items to count, counting all list items on those pages and keeping a running total.
N.B. depending on the number of pages and lists you need to count, this may not be particularly efficient. But it will work, and I think is the only realistic way you can achieve this without using a DB or complex scraping/caching systems.
you can store your individual values into localStorage or sessionStorage which availlbe with HTML5
There are two new objects for storing data on the client:
localStorage - stores data with no expiration date
sessionStorage - stores data for one session
you can use localStorage or sessionStorage is client side cookies to store your individual value, then you are going to show your total into different page retrieve the value from localStorage and show it :)
Again if you dont want to cache total values set expire time of localStorage 0 which will be expired when browser closed.
for more details on localStorage http://www.w3schools.com/html/html5_webstorage.asp