Adding html / css within JavaScript toggle - javascript

$(function() {
$('#toggle3').click(function () {
$('.toggle').hide('1000');
$('.toggle').text('I would like to add a navigation menu here'); // <--
$('.toggle').slideToggle('1000');
return false;
});
});
I am wondering the best way to edit the above code snippet to be able to hold HTML / CSS as I plan on calling a custom menu within. I will be using this snippet multiple times and calling multiple menus to trigger with toggle.

If at all possible, try to avoid embedding html on javascript: you're likely to run into escaping issues and multiline strings, and the overall result usually isn't pretty.
You might want to store the HTML on the DOM itself:
<div>
<span class="toggle" data-toggle="foo">Toggle foo</span>
<span class="toggle" data-toggle="bar">Toggle bar</span>
</div>
<div id="navmenu-store">
<div class='navmenu' data-for-toggle="foo">
navmenu "foo"
</div>
<div class='navmenu' data-for-toggle="bar">
navmenu "bar"
</div>
</div>
On the CSS, hide the 'store':
#navmenu-store {
display: none;
}
And then, with javascript, add the navmenus when requested:
$(".toggle").each(function() {
var $toggle = $(this);
var toggleName = $toggle.data("toggle");
var $navmenu = $(".navmenu[data-for-toggle=" + toggleName + "]");
// Store the navmenu on the toggle for later access
$navmenu.remove();
$toggle.data("navmenu", $navmenu);
});
$(".toggle").on("click", function() {
var $toggle = $(this);
var $navmenu = $toggle.data("navmenu");
var isInTheDom = $.contains(document, $navmenu[0]);
if(isInTheDom) {
$navmenu.remove();
} else {
// Here I'm inserting the navmenu after the toggle;
// you can do whatever you want
$navmenu.insertAfter($toggle);
}
});
I've created a very simple jsbin as a proof of concept: http://jsbin.com/OwUWAlu/1/edit

Related

how to toggle <div> tags hidden and visible with <span> and JS?

I am building a site with a search bar, but there is too much search content and I need a way for people to toggle it being hidden
<div class="search">
<ul>Bash Shell Emulator</ul>
<ul>How to use bash shell </ul>
much more to this. But how can I toggle it being hidden and it being shown with JS and <span>?
Thank you very much,
Ring Games
Hi you can use toggle to add and remove a class, and with the class you can hide the elements inside the search, this is an example:
const searchElement = document.getElementById("search");
const toggleElement = document.getElementById("toggle-visibility");
toggleElement.addEventListener("click", toggleSearchVisibility);
function toggleSearchVisibility() {
searchElement.classList.toggle("hide-element")
}
.hide-element{
display: none;
}
<div id="search">
<ul>Bash Shell Emulator</ul>
<ul>How to use bash shell </ul>
</div>
<span id="toggle-visibility">Click me!</span>
I would strongly suggest you use the JQuery library. Its super easy, all you need to do as add the following script to your <head> tag:
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
Then it would be simple as:
$("#clickedElementThatWillHide").click(function(){
$("span").hide();
});
For more examples checkout W3Schools
Here is Vanilla Javascript without using big library
<p>
<a class="toggle" href="#example">Toggle Div</a>
</p>
<div id="example">
<ul>Bash Shell Emulator</ul>
<ul>How to use bash shell </ul>
</div>
<script>
var show = function (elem) {
elem.style.display = 'block';
};
var hide = function (elem) {
elem.style.display = 'none';
};
var toggle = function (elem) {
// If the element is visible, hide it
if (window.getComputedStyle(elem).display === 'block') {
hide(elem);
return;
}
// Otherwise, show it
show(elem);
};
// Listen for click events
document.addEventListener('click', function (event) {
// Make sure clicked element is our toggle
if (!event.target.classList.contains('toggle')) return;
// Prevent default link behavior
event.preventDefault();
// Get the content
var content = document.querySelector(event.target.hash);
if (!content) return;
// Toggle the content
toggle(content);
}, false);
</script>

Save toggleClass state of dynamically generated divs and store with Cookie/LocalStorage

I am trying to save my toggleClass state of multiple dynamically generated divs and store them with LocalStorage, so they're available either on page refresh or re-visiting the page. I stuck in the middle of my code and have no more ideas.
Any solutions i found here, will not work, either they refer to a single element or they use a mix of addClass/removeClass and save state.
Saving with Cookie would be an option too.
Html:
<div id="row_parent_41" class="parent">
<div id="page_41">
<span class="showhide" id="more_2"><img src="plus.png" /></span>
</div>
<div id="holder_41" class="child">stuff goes here</div>
jQuery:
var inactiveHolder = localStorage.getItem('child') == 'true';
$(".showhide").on('click', function() {
$(this).closest(".parent").find(".child").slideToggle().toggleClass('inactiveHolder');
$('.child').toggleClass('clicked', inactiveHolder );
return false;
});
Does this code work for you?
var inactiveHolder = localStorage.getItem('child');
// set initial state
if (inactiveHolder == 'true') {
$('.child').addClass('clicked');
}
// change localstorage and class
$('.showhide').on('click', function() {
var element = $(this).closest(".parent").find(".child");
$(element).slideToggle().toggleClass('clicked');
localstorage.setItem('child', $(element).hasClass('clicked'));
return false;
});

Bootstrap tabs with CodeMirror

I have a pretty complex page where I have a number of instances of CodeMirror in hidden tabs within tabs. To then make it even more complex I remember the last active tabs.
I've manage to get it half working (http://codepen.io/anon/pen/LheaF) the problems are with the Second Editor tabs:
Its loading the Second tabs before the main Code Mirror tabs has been clicked. When you do click the Code Mirror tab it doesn't load the editor correctly either, until you click twice.
I want the second tabs to call the refresh() method if its already been initiated, like I do for the main editor.
Bug where its duplicating the secondary editors
(function($) {
var mainEditor;
function initMainCodeEditor() {
if (mainEditor instanceof CodeMirror) {
mainEditor.refresh();
} else {
// Load main editor
var el = document.getElementById("codifyme");
mainEditor = CodeMirror.fromTextArea(el, {
lineNumbers: true
});
mainEditor.setSize('100%', 50);
}
}
function initSecondaryCodeEditor() {
var $active = $('#code_mirror_editors > .active > a');
var $sec_tab = $($active.data('target'));
CodeMirror.fromTextArea($sec_tab.find('textarea')[0], {
lineNumbers: true
});
}
$(document).ready(function() {
// Only load editors if tab has been clicked
$('#maintabs > li > a[data-target="#codemirror"]').on('shown.bs.tab', function(e) {
initMainCodeEditor();
});
$('#code_mirror_editors > li > a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
initSecondaryCodeEditor();
});
// Remember tabs
var json, tabsState;
$('a[data-toggle="tab"]').on('shown.bs.tab', function(e) {
tabsState = localStorage.getItem("tabs-state");
json = JSON.parse(tabsState || "{}");
json[$(e.target).parents("ul.nav.nav-pills, ul.nav.nav-tabs").attr("id")] = $(e.target).data('target');
localStorage.setItem("tabs-state", JSON.stringify(json));
});
tabsState = localStorage.getItem("tabs-state");
json = JSON.parse(tabsState || "{}");
$.each(json, function(containerId, target) {
return $("#" + containerId + " a[data-target=" + target + "]").tab('show');
});
$("ul.nav.nav-pills, ul.nav.nav-tabs").each(function() {
var $this = $(this);
if (!json[$this.attr("id")]) {
return $this.find("a[data-toggle=tab]:first, a[data-toggle=pill]:first").tab("show");
}
});
}); // doc.ready
})(jQuery);
The problems:
it might happen that you create the CodeMirror on an element which is not visible (one of it's parents has display: none). This breaks various calculations done by CodeMirror
by getting the CodeMirror instance right from the CodeMirror container element enables us to call refresh everytime you want (by finding the .CodeMirror next to your textarea)
fixed as a side effect of 2.
HTML
Here's a bootstrap tab frame, if you use jquery-UI, it's gonna be a little different.
<ul class="nav nav-tabs">
<li class="active">tab1</li>
<li>tab2</li>
</ul>
<div class="tab-content">
<div class="tab-pane fade in active" id="tab1"><textarea type="text" id="tab1Content" name="xxx"></textarea></div>
<div class="tab-pane fade" id="tab2"><textarea type="text" id="tab2Content" name="yyy"></textarea></div>
</div>
JS
var cm1, cm2;
$(document).ready(function () {
//when the bootstrap tab is fully shown, call codemirror's refresh().
//Also, if you use jquery-UI, it's gonna be different here.
$('.nav-tabs a').on('shown.bs.tab', function() {
cm1.refresh();
cm2.refresh();
});
cm1 = CodeMirror.fromTextArea(document.getElementById("tab1Content"), {
lineNumbers: true
});
cm2 = CodeMirror.fromTextArea(document.getElementById("tab2Content"), {
lineNumbers: true
});
});
Working Solution: http://codepen.io/anon/pen/hupwy
I addressed issues 2 and 3 as I could not replicated 1.
I used a hash table to store the second editor CodeMirror objects. Then I modified your existing mainEditor code to refresh the objects if they already exist.
var seccondEditor = new Object();
function initSecondaryCodeEditor(){
var $active = $('#code_mirror_editors > .active > a');
var $sec_tab = $($active.data('target'));
var sec_edi = ($sec_tab.find('textarea')[0]);
if(seccondEditor[sec_edi.id] instanceof CodeMirror){
seccondEditor[sec_edi.id].refresh();
} else {
seccondEditor[sec_edi.id] = CodeMirror.fromTextArea(sec_edi, {lineNumbers: true});
}
}
I'm not well versed in CodeMirror so this might no be the most elegant solution, but it looks like the code above prevents the duplicates you were seeing. Hope this helps.
if the problem occurs when codemirror render content within an hidden div, why not just diplay all the tab-panel div, then call codemirror, then hide unneeded tab ??
HTML:
<div role="tabpanel" class="tab-pane active" id="tp1">
<textarea class="code" data-lang="text/html">
<!--- content #1 here -->
</textarea>
</div>
<div role="tabpanel" class="tab-pane active hideAfterRendering" id="tp2">
<textarea class="code" data-lang="text/html">
<!--- content #2 here -->
</textarea>
</div>
<div role="tabpanel" class="tab-pane active hideAfterRendering" id="tp3">
<textarea class="code" data-lang="text/html">
<!--- content #3 here -->
</textarea>
</div>
SCRIPT:
<script>
$( document ).ready(function() {
//render codeMirror
$('.code').each(function() {
CodeMirror.fromTextArea(this, {
mode: "properties",
lineNumbers: true,
indentUnit: 4,
readOnly: true,
matchBrackets: true
});
});
//hide tab-panel after codeMirror rendering (by removing the extra 'active' class
$('.hideAfterRendering').each( function () {
$(this).removeClass('active')
});
});
</script>
Works well for me !!
Why not just to set timeout?.. just exec that code when tab clicked:
update_mirror = function() {
var codeMirrorContainer = $sec_tab.find(".CodeMirror")[0];
if (codeMirrorContainer && codeMirrorContainer.CodeMirror) {
codeMirrorContainer.CodeMirror.refresh();
}
}
// Attention! magic!
setTimeout(update_mirror, 100);
That helped me a lot while I had a battle against that problem. Thanks to Sekaryo Shin, he saved my time.

Javascript Collapsible Menu (hide the other elements)

I have the following working Javascript function:
function collapsible(zap) {
if (document.getElementById) {
var abra = document.getElementById(zap).style;
if (abra.display == "block") {
abra.display = "none";
} else {
abra.display = "block";
}
return false;
} else {
return true;
}
}
When I use the following in html code it displays or hides the "element" div:
<li>Element</li>
Thats working fine. But the problem is, that I want to use the function for multiple links, and then the other elements, that were clicked before, stay, open.
How can I reprogram the code, so that only one div stays open and the other gets closed if i click on another link?
Thanks beforehand!
If you could use jQuery and more importantly jQueryUI accordion I think it would accomplish exactly what you're looking for.
However, without using those two, here is how I would structure it. Like mentioned above, I would use classes to modify the styles of the divs you want shown or hidden. Then the js code can just toggle those classes on each of your elements. The slightly more difficult part (without jquery) is modifying class values since in your final application you may have lots of classes on each div. This is just a very crude example to get you going.
Working JSFiddle Example
Sample DOM
<div >
<li>Element1</li>
<div id='elem1' class='myelem visible'>
Element 1 contents
</div>
</div>
<div >
<li>Element2</li>
<div id='elem2' class='myelem'>
Element 2 contents
</div>
</div>
<div >
<li>Element3</li>
<div id='elem3' class='myelem'>
Element 3 contents
</div>
</div>
Sample JS
window['collapsible'] = function(zap) {
if (document.getElementById)
{
var visDivs = document.getElementsByClassName('visible');
for(var i = 0; i < visDivs.length; i++)
{
visDivs[i].className = visDivs[i].className.replace('visible','');
}
document.getElementById(zap).className += " visible";
return false;
}
else
return true;
}
Sample CSS:
.myelem {
display: none;
}
.visible {
display: block;
}
The way to go is to create a class(or maybe two), like collapsible and active or open that has this style(display: block or none) and then you working adding or removing the class.
The logic would be:
Links that has the class collapsible when clicked would add the active or open class which would give the behavior that remains opens(or active) by css.
If you want to hide others elements you would look for the elements with the class collapsible and then remove the active(or open) class if has any.
Here is my solution: http://jsfiddle.net/g5oc0uoq/
$('.content').hide();
$('.listelement').on('click', function(){
if(!($(this).children('.content').is(':visible'))){
$('.content').slideUp();
$(this).children('.content').slideDown();
} else {
$('.content').slideUp();
}
});
show() and hide() can be used instead of slideUp() and slideDown() if you have performance issues.

Selecting a single class from a multi class element

I'm trying to select a specific class (in this case page1, page2, page3 etc.)
I've written this code that works fine for a single class, i've tried using .match() to exclude the .plink class picked up in dis but can't get it working.
$(function(){
$("a.plink").click(function() {
var dis = $(this).attr("class"); // This is the problem line, I need it to contain 'page1' ONLY. Not 'page1 plink'.
$("#page1,#page2,#page3").hide();
$("#" + dis).show();
return false;
});
});
The HTML that is associated with this is:
<div id="page-links">
<a class="page1 plink" href="#">About</a>
<a class="page2 plink" href="#">History</a>
<a class="page3 plink" href="#">Backstage</a>
</div>
EDIT:
These are the DIV's being shown and hidden:
<div id="page1">
<?php include_once("page1.php");?>
</div>
<div id="page2">
<?php include_once("page2.php");?>
</div>
<div id="page3">
<?php include_once("page3.php");?>
</div>
Is there a simple way to achieve this without regular expression matching?
$(function(){
var pages = $('div[id^=page]');
$("a.plink").click(function() {
var dis = $(this).attr("class").replace(' plink', '');
pages.hide().filter('#' + dis).show();
return false;
});
});
This should be
$("." + dis).show();
for class and in your example there are all classes.
As you mentioned simple way so it could be
$("a.plink").click(function() {
$(".plink").hide();
$(this).show();
return false;
});
According to your question after edit
$("a.plink").click(function() {
$('div[id^="page"]').not('#page-links').hide();
pid=$(this).attr('class').split(' ')[0];
$('#'+pid).show();
return false;
});
Here is a fiddle.
The JavaScript code is not correct. With the "#" you select ids from the html-element.
As you have only classes, the right way is to do it with "."
So this would be correct:
$(function(){
$("a.plink").click(function() {
var dis = $(this).attr("class");
$(".page1,.page2,.page3").hide();
$("." + dis).show();
return false;
});
});
I didn't test it, but I think you have to change something with the var dis.
If you click on .page1, the variable dis would contain "page1 plink".
$("." + dis).show();
would be
$(".page1 plink").show();
So I recommend to split the two classes, as it should be like
$(".page1 .plink").show();
You are trying to associate functionality of a click by appending classes. It would make more sense to put id of the div you want to show in the href
html:
<div id="page-links">
<a class="plink" href="#page1">About</a>
<a class="plink" href="#page2">History</a>
<a class=" plink" href="#page3">Backstage</a>
</div>
<div id="page1">
Content 1
</div>
<div id="page2">
Content 2
</div>
<div id="page3">
Content 3
</div>
​javascript:
jQuery(function ($) {
var pages = [];
function showPage(page) {
var i;
for(i = 0; i < pages.length; i++)
{
if(page === pages[i]) {
$(pages[i]).show();
} else {
$(pages[i]).hide();
}
}
}
// Store each href in a pages array and add handlers
$('.plink').each( function() {
var page = $(this).attr('href');
pages.push(page);
$(this).attr('href', '#');
$(this).click(function () {
showPage(page);
});
});
// show the first page
if(pages.length > 0) {
showPage(pages[0]);
}
});​
Example:
http://jsfiddle.net/38qLB/
And just so I don't avoid the actual question, which is how do you select a class from a multi class element, you should follow this example of splitting up the class name Get class list for element with jQuery if you truly insist on using classes to make your link/div association
You don't really want to exclude the plink class, because that will bring you confusion and trouble when you need to add another class. Instead you want to extract just the pageX class:
// Regex for extracting pageXX
var reg = /^(.*\s)?(page\d+)([^\d].*)?$/;
dis = reg.exec(dis)[2];
I haven't testet this 100%, but put these two lines in right after var dis = $(this).attr("class"); and you should hopefully be good to go.
i down't know if i get your question right
to get all classes with class plink u can use
var klasses $("a.plink");
now u can loop true the items
var yourClasses = Array();
for(var klass in klasses)
{
var word = klass.attr('class').replace(" plink", "");
yourClasses.push(word);
}
now you have all the classes wich have the class plink
hope this was where u where looking for
If I was just doing a minor tweak to fix your existing structure I would do something like this:
$(document).ready(function() {
$('a.plink').click(function() {
var id = $.trim(this.className.replace('plink', ''));
/*adding a "page" class to each of the page divs makes hiding the visible one a bit easier*/
$('div.page').hide();
/*otherwise use the version from sheikh*/
//$('div[id^="page"]').not('#page-links').hide();
$('div#' + id).show();
});
});
The main change I would recommend to your existing markup would be to add a common "page" class to each of the page divs. Here is a fiddle
If I was starting on this from scratch I would probably take a slightly different approach in which I define an "active" class and toggle which elements have it rather than using show/hide on the divs. And that would end up looking something like this:
Markup:
<div id="page-links">
<a class="plink active" href="#page1">About</a>
<a class="plink" href="#page2">History</a>
<a class="plink" href="#page3">Backstage</a>
</div>
<div id="page1" class='page active'> </div>
<div id="page2" class='page'> </div>
<div id="page3" class='page'> </div>
CSS:
div.page
{
height: 300px;
display:none;
}
div.page.active
{
display:block;
}
a.plink
{
padding-left:5px;
padding-right:5px;
}
a.plink.active
{
background-color:#ddd;
}
div#page1
{
background-color:blue;
}
div#page2
{
background-color:green;
}
div#page3
{
background-color:red;
}
Script:
$(document).ready(function() {
$('a.plink').click(function() {
var id = $(this).attr('href');
$('.active').removeClass('active');
$(this).addClass('active');
$('div' + id).addClass('active');
});
});
Or the fiddle here.
Oh and to answer the title question rather than just the end behavior described...
var classes = this.className.split(' ');
var id;
for (var i = 0; i < classes.length; i++) {
if(classes[i].substring(4) === classes[i].replace('page', '')) {
id = classes[i];
break;
}
}
should end up with id containing the "page#" value associated with the link that was clicked regardless of its position in the list of classes.

Categories