Converting inline Javascript to an onclick event - javascript

I'll be blunt. Most of my skill is in pure HTML and CSS. I'm trying more and more to expand into JavaScript and JQuery and have some experience, enough to understand many simple tutorials and implement them with my own changes, but not enough to do much on my own without a cheatsheet or a similar example to work from. Anyway:
I wanted to try THIS tutorial I found to use Ajax to replace the contents of a div, but the implementation requires poor markup (inline JS). He doesn't suggest a way to utilize an onclick event instead, and I would much prefer that to inline JS.
This is "Ajax Engine" he provides, which I choose to import/link because I feel it's silly to dump all that in the HTML:
<script type="text/javascript">
// Version 1.1 of May 16, 2013
function RequestContent(url,id) {
var http;
if (window.XMLHttpRequest) {
try { http = new XMLHttpRequest(); }
catch(e) {}
}
else if (window.ActiveXObject) {
try { http = new ActiveXObject("Msxml2.XMLHTTP"); }
catch(e) {
try { http = new ActiveXObject("Microsoft.XMLHTTP"); }
catch(e) {}
}
}
if(! http) {
alert('\n\nSorry, unable to open a connection to the server.');
return false;
}
http.onreadystatechange = function() { PublishContent(http,id); };
http.open('GET',url,true);
http.send('');
}
function PublishContent(content,id) {
try {
if (content.readyState == 4) {
if(content.status == 200) { document.getElementById(id).innerHTML=content.responseText; }
else { alert('\n\nContent request error, status code:\n'+content.status+' '+content.statusText); }
}
}
catch(error) { alert('Error: '+error.name+' -- '+error.message); }
}
</script>
In order to use the function RequestContent, he only offers the option to plop inline JS like so:
<ul>
<li>
<a href="javascript:RequestContent('/library/ajaxcontent1.html','fill-me3')">
Click here</a> to fill the div below with the Master Form .PHP logo.
</li>
<li>
<a href="javascript:RequestContent('/library/ajaxcontent2.html','fill-me3')">
Click here</a> to fill the div below with the Master Form V4 logo.
</li>
<li>
<a href="javascript:RequestContent('/library/ajaxcontent3.html','fill-me3')">
Click here</a> to fill the div below with the Most Popular logo.
</li>
</ul>
I understand how the inline JS works, I'm just not sure how to write it in a way to allow for an onclick event.
How would I go about converting the inline JS? I really appreciate the help.

Just change href to onclick, and get rid of javascript:.
<ul>
<li>
<a onclick="RequestContent('/library/ajaxcontent1.html','fill-me3')">
Click here</a> to fill the div below with the Master Form .PHP logo.
</li>
<li>
<a onclick="RequestContent('/library/ajaxcontent2.html','fill-me3')">
Click here</a> to fill the div below with the Master Form V4 logo.
</li>
<li>
<a onclick="RequestContent('/library/ajaxcontent3.html','fill-me3')">
Click here</a> to fill the div below with the Most Popular logo.
</li>
</ul>

Using a data attribute to hold the value would allow you to add more links without having to write more javascript.
HTML
<ul>
<li>
<a href="#" class="someLink" data-request-content="ajaxcontent1">
Click here</a> to fill the div below with the Master Form .PHP logo.
</li>
<li>
<a href="#" class="someLink" data-request-content="ajaxcontent2">
Click here</a> to fill the div below with the Master Form V4 logo.
</li>
<li>
<a href="#" class="someLink" data-request-content="ajaxcontent3">
Click here</a> to fill the div below with the Most Popular logo.
</li>
</ul>
Javascript
$('.someLink').on('click', function(e) {
var content = $(e.currentTarget).data('request-content');
RequestContent('/library/' + content + '.html', 'fill-me3');
});

To use the onclick event in external javascript, your elements will need to have IDs:
<ul>
<li>
<a id="one">
Click here</a> to fill the div below with the Master Form .PHP logo.
</li>
<li>
<a id="two">
Click here</a> to fill the div below with the Master Form V4 logo.
</li>
<li>
<a id="three">
Click here</a> to fill the div below with the Most Popular logo.
</li>
</ul>
And in your external javascript you will use Document.getElementById() and the .onclick property:
document.getElementById("one").onclick = function() {
RequestContent('/library/ajaxcontent1.html','fill-me3');
}
document.getElementById("two").onclick = function() {
RequestContent('/library/ajaxcontent2.html','fill-me3');
}
document.getElementById("three").onclick = function() {
RequestContent('/library/ajaxcontent3.html','fill-me3');
}

Here's a more generic and simple way to call the function using jquery. You should add the link and other attribute as part of the anchor tag.
<ul>
<li>
<a href="#" link='/library/ajaxcontent1.html' class='fill-me3'>
Click here</a> to fill the div below with the Most Popular logo.
</li>
<li>
<a href="#" link='/library/ajaxcontent2.html' class='fill-me3'>
Click here</a> to fill the div below with the Most Popular logo.
</li>
<li>
<a href="#" link='/library/ajaxcontent3.html' class='fill-me3'>
Click here</a> to fill the div below with the Most Popular logo.
</li>
</ul>
<script>
$(document).ready(function(){
$('a').click(function()
{
RequestContent($(this).attr("link"),$(this).attr("class"));
});
});
function RequestContent(url,cls)
{
alert(url);
alert(cls);
}
</script>
Example : https://jsfiddle.net/DinoMyte/Lkb0s60n/1/

Only use an <a> element when you intend to navigate, either this frame or another one, to a destination page. Use any other element for javascript events, and add CSS to make it look clickable if you like. (Note that there are ways to shorten the below script using JQuery or other JS toolkits)
function NavigateTo(dest) {
// ...
}
var navTos = document.querySelectorAll('.navTo');
for (var i = 0; i < navTos.length; i++) {
navTos[i].addEventListener('click', function(evt) {
NavigateTo(evt.target.dataset.navPage);
});
}
.link {
color: blue;
cursor: pointer;
}
.link:hover {
text-decoration: underline;
}
<span class="link navTo" data-nav-page="place.htm">Go here</span>

Related

Change div content on mouse hover with default content fallback

I've implemented the accepted answer to Change div content based on mouse hover on different divs across a lot of links, so I don't really want to go with another solution if it can be avoided. I'm trying to figure out one more piece of the puzzle though...
I can't seem to get it to where it defaults back to the original text of the content div when not hovering over an item.
<div id="content">
Stuff should be placed here.
</div>
<br/>
<br/>
<br/>
<ul>
<li onmouseover="hover('Apples are delicious')">Apple</li>
<li onmouseover="hover('oranges are healthy')">Orange</li>
<li onmouseover="hover('Candy is the best')">Candy</li>
</ul>
<script>
function hover(description) {
console.log(description);
document.getElementById('content').innerHTML = description;
}
</script>
You need to store the original text and bring it back when the mouse leaves.
var element = getElementById('content'),
storedText;
function hover(description) {
console.log(description);
storedText = element.innerHTML;
element.innerHTML = description;
}
function leave() {
element.innerHTML = storedText;
}
<div id="content">
Stuff should be placed here.
</div>
<br/>
<br/>
<br/>
<ul>
<li onmouseover="hover('Apples are delicious')" onmouseleave="leave()">Apple</li>
<li onmouseover="hover('oranges are healthy')" onmouseleave="leave()">Orange</li>
<li onmouseover="hover('Candy is the best')" onmouseleave="leave()">Candy</li>
</ul>
It is generally recommended to add event listeners in the JS code and not in the HTML, but put that aside for now.
i dont think in your code there was anything to make the content to go back to the default but i have made the least changes in your code to make the content to go back to default and i have used onmouseout event for that.
<div id="content">
Stuff should be placed here.
</div>
<br/>
<br/>
<br/>
<ul>
<li onmouseover="hover('Apples are delicious')" onmouseout="hover('Stuff should be placed here.')">Apple</li>
<li onmouseover="hover('oranges are healthy')" onmouseout="hover('Stuff should be placed here.')">Orange</li>
<li onmouseover="hover('Candy is the best')" onmouseout="hover('Stuff should be placed here.')">Candy</li>
</ul>
<script>
function hover(description) {
console.log(description);
document.getElementById('content').innerHTML = description;
}
</script>
You can achieve the same without any Javascript:
li::before { content: attr(data-text); }
li:hover::before { content: attr(data-text-hover); }
<ul>
<li data-text-hover="Apples are delicious" data-text="Apple"></li>
<li data-text-hover="Oranges are healthy" data-text="Orange"></li>
<li data-text-hover="Candy is the best" data-text="Candy"></li>
</ul>

React on click over an area as long as it was not an <a> tag

I have a large area that I need to make clickable. Imagine I have a list of items:
<ul class="my-area">
<li>...</li>
<li>...</li>
</ul>
The items <li> have a lot of stuff inside including working links or links that trigger modal windows etc. As long as someone clicks on one of the links inside, it should do whatever it is designated to do - redirect, open modal window, etc. However, if the click was not on a link but just a <div>, <span> etc, then I need to redirect to a specific location.
I've tried this:
$("ul.my-area li:not(a)").click(function (event) {
location.href='SOME_LOCATION';
});
However, it's not working. I considered using .stopPropagation() as well but then the modal windows stop working so that's not an option. Any ideas?
edited: There is two posible solutions:First solution:event.stopPropagation() *(not an option for this specific question because of modals)*- this would look like:
$("ul.my-area li").on('click',function (event) {
//location.href='SOME_LOCATION';
});
$("ul.my-area li a").on('click',function(e){
e.stopPropagation();
});
Second solution: Since you have nested DIV, IMG... inside the anchors, here it is checking if clicked element is not an anchor or if it don't have any ancestor anchor, and inside you can change location.href/do some action:
$("ul.my-area li ").on('click', function(event) {
if (!((event.target.tagName == "A") || $(event.target).closest('a').length)) {
console.log("This is not an anchor");
//location.href='SOME_LOCATION';
}
else{ //it's an anchor }
});
Check the below snippet
$("ul.my-area li ").on('click', function(event) {
if (!((event.target.tagName == "A") || $(event.target).closest('a').length)) {
console.log("This is not an anchor");
//location.href='SOME_LOCATION';
}
else{ //it's an anchor }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="my-area">
<li>
<p>This is Paragraf This is Anchor
</p>
<div>This is DIV</div>
</li>
<li>
<p>This is another Paragraf</p>
<a href="#">
<div>This Div inside Anchor<span> This is span inside div inside the anchor</span>
</div>
<img src="" alt="Image part of the anchor">
</a>
<p>Some paragraf</p>
</li>
</ul>

Change max height element after it being clicked

I'm writting a dropdown menu and I wanted to have the dropdown being controlled by javascript.
My dropdown has the sub menu hidden of sight max-height: 0px; and when the correspondent anchor tag is clicked, I change its max-height parameter to 400px, using the following function:
function drop_down(name) {
document.getElementById(name).style.maxHeight = "400px";
}
So far so good. The problem is that the element's max-height, stays at 400px and the sub menu does not hide. So I thought that I should target the click of the mouse and when this happens check if there is any element with 400px and change it back to 0.
$('html').click(function() {
var max_h = document.getElementsByClassName("nav_content");
var i;
for(i = 0 ; i < max_h.length ; i++)
{
if(max_h[i].style.maxHeight == "400px")
{
max_h[i].style.maxHeight = "0px";
}
}
});
What happens is that this function tracks every click, even the one used to display the sub menu. So my question is: is there a way to only activate the second function after I clicked my sub-menu? Because I always want the click that comes after the menu is displayed to close the sub menu.
HTML:
<body>
<div class="nav_container">
<nav class="nav_main">
<div class="logo">
<a href="#">
<img src="../majo.png" alt="logo">
</a>
</div>
<ul class="nav" id="nav">
<li>
Home
</li>
<li>
Consultas
<div id="nav_consul" class="nav_content">
<div class="nav_sub">
<ul>
<li>
Informação Dia a Dia
</li>
<li>
Totais Mensais
</li>
<li>
Tarifário Atual da Rede
</li>
<li>
Data específica
</li>
<li>
Atividade do Sistema
</li>
<li>
Coimas
</li>
</ul>
</div>
</div>
</li>
<li>
Simulações
<div id="nav_simul" class="nav_content">
<div class="nav_sub">
<ul>
<li>
Criar tarifa Simples
</li>
<li>
Criar tarifa Complexa
</li>
<li>
Simular com Nova Tarifa
</li>
</ul>
</div>
</div>
</li>
<li>
Preferências
<div id="nav_prefs" class="nav_content">
<div class="nav_sub">
<ul>
<li>
Lista de acessos
</li>
<li>
Alterar Password
</li>
<li>
Alterar Dados de Conta
</li>
</ul>
</div>
</div>
</li>
<li>
Log Out
</li>
</ul>
</nav>
</div>
<div id="content_main">
</div>
<footer></footer>
<script src="../js/jQuery.js"></script>
<script src="../js/user_menu.js"></script>
<script src="../js/user_nav.js"></script>
<script src="../js/user_clear_sub_menu.js"></script>
</body>
Here is an easy solution:
Create the following CSS-Styles:
.nav_content.visible {
max-height: 400px;
}
.nav_content.invisible {
max-height: 0px;
}
Set the overflow property for your nav_content to hidden:
.nav_content{
overflow: hidden;
}
Now add the class invisible to your submenus, if you want them to be invisible by default (you can do this manually in the markup or by js code):
Manually e.g.:
<div id="nav_prefs" class="nav_content invisible">
or by code (after the elements have been loaded):
$(".nav_content").addClass("invisible);
Now, if you just need to adjust your drop_down function to toggle the element's invisible/visible class:
function drop_down(dropdownID){
$('#'+dropdownID).toggleClass("visible invisible");
}
UPDATE: To make all visible submenus disappear when clicked elsewhere use this piece of code, when the window is loaded:
$(document).on('click', function (e) {
if (!$(e.target).is('.nav_item') && !$(".nav_item").has(e.target).length !== 0) {
$('.nav_content.visible').toggleClass("visible invisible");
}
});
If you only want to have one submenu visible at a time, you can use this version of your drop_down function:
function drop_down(dropdownID) {
$('.nav_content.visible').toggleClass("visible invisible");
$('#' + dropdownID).toggleClass("visible invisible");
}
A working fiddle can be found here
EDIT: Since you used jQuery in your original code, I assumed the answer can use jQuery too
You'll want to create a click handler on your document, then check the target of the click. If the target of the click has a certain class, use the menu behavior. If not, or if it's a sub-menu, close the menu.
Here's a question with multiple examples:
How do I close menu on click and when the user clicks away?
Also, I'd recommend not using max-height to hide and show. Since you're using jquery already, you could just use hide() and show().
One more thing: since you're using jquery already, you don't need to use these calls: document.getElementById(name). You can do a $("#yourId") or for document.getElementsByClassName("nav_content"); you can use $(".your-class")
It looks like you attached click event to entire document. I think you need to change only $('html').click(function() { to something like $('sub-menu-selector').click(function() { to
only activate the second function after I clicked my sub-menu
Aside to that, since it's only piece of jQuery and if you're not using it elsewhere, I would replace this with addEventListener and attachEvent, but maybe that's just me :)
In that case you can use jQuery.not() method to exclude the dropdown menu from your jQuery selection, here's what you need :
$('html').not(document.getElementsByClassName("nav_container")[0]).click(function() {
//As you can pass an element to it
You can also use the :not in your first selector like this:
$('html:not(div.nav_container))

Having different click areas on sidenav

I am using bootstrap and in that I am using side nav to serve collapsible list on the left side of the page. Below is my code.
<ul class="nav navbar-nav side-nav">
<li>
<a class="active" href="#" onclick="loadelementsonpage(); return false" data-toggle="collapse" data-target="#licomp1">
<i class="fa fa-fw fa-arrow-v"></i>Parent1
</a>
<ul id="licomp1" class="collapse">
<li>Child1</li>
<li>Child2</li>
<li>Child3</li>
</ul>
</li>
</ul>
Instead of fixed <i class="fa fa-fw fa-arrow-v"></i> I want to use toggle plus and minus. As it is shown in code, I am calling one function when parent1 is clicked. But when I try to expand the ul, the function loadelementsonpage() is called everytime. So, I want list to collapse only when that toggle image is clicked. In the same way I want to call loadelementsonpage() only when the outer area of that toggle image is clicked. I changed this data-toggle and data-target to i class, but the problem is the function is still getting called and if I move the i class out of a tag, the style is messed up.
So can someone please shed some light on how to have different click areas on the parent li? One is for collapse and another is for calling function to load right side content page.
P.S: Trying to implement this http://cssmenumaker.com/menu/modern-jquery-accordion-menu kind of side nav list where + or - should be clickable for only expanding and collapsing. Please click on build online in that link to see the side nav. Other area(apart from + and - icons) should act as link href to load the page.
Instead of giving the data-toggle attribute to the anchor, give it to the icon element so that toggle works only for the icon. You can use the classes here for plus and minus and toggle between the classes glyphicon-plus and glyphicon-minus
<a class="active" href="#">
<span data-toggle="collapse" class="glyphicon glyphicon-plus" data-target="#licomp1"></span>Parent1
</a>
$('.side-nav a span').on('click', function () {
$(this).toggleClass('glyphicon-plus glyphicon-minus');
});
Now on click of the anchor you can check if the element is A and if true then only call the custom function loadelementsonpage.
$('.side-nav a').on('click', function (e) {
console.log(e.target.tagName);
if (e.target.tagName == "A") {
loadelementsonpage();
return true;
}
})
function loadelementsonpage() {
alert('Load elements on page');
}
See fiddle
jsbin demo
Remove the inline JS you have in your HTML:
<a class="active" href="#" data-toggle="collapse" data-target="#licomp1">
<i class="fa fa-fw fa-arrow-v"></i>Parent1
</a>
And simply add this to your jQuery:
function loadelementsonpage(){
alert("LOADED ELEMENTS! YIIHA"); // Or whatever goes here
}
$(".side-nav").on("click", "a[data-target]", function(e) {
e.preventDefault(); // Prevent default Browser anchor-click behavior
if( !$(e.target).hasClass("fa") ){ // If the clicked el. target was not `.fa`
// means it was the parent `a` to get the click event. Therefore...
e.stopPropagation(); // prevent the click to propagate
// to underneath layers triggering stuff and...
return loadelementsonpage(); // execute (return) our desired function.
}
});
(Make sure you have it in document.ready function)
What the above does
Proof of concept:
function loadelementsonpage(target) {
// example stuff
$(target).toggle();
}
$(".side-nav").on("click", "a[data-toggle]", function(event) {
event.preventDefault(); // Prevent default Browser anchor-click behavior
var icon = $(event.target).find('.collapseIcon');
if (icon.text() === '+') {
icon.text('-');
} else {
icon.text('+');
}
loadelementsonpage(event.target.getAttribute('data-target'));
return false;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="nav navbar-nav side-nav">
<li>
<a class="active" href="#" data-toggle="collapse" data-target="#licomp1">
<span class="collapseIcon">-</span> Parent1
</a>
<ul id="licomp1" class="collapse">
<li>Child1
</li>
<li>Child2
</li>
<li>Child3
</li>
</ul>
</li>
</ul>

Onmouseover/out

Two issues I am having.
The mouseover function is very FAST and it's definitely not working properly. I made a separate function for the onmouseout state, but it didnt help.
The class changes properly, however it stays changed and doesn't go back to it's original class. It depends if the link is on the selected page. Any help would be GREATLY appreciated
JAVASCRIPT:
function changeRollover(rollover) {
var rollItems = document.getElementById(rollover);
var rollLinks = rollItems.getElementsByTagName('a');
var noOfLinks = rollLinks.length;
for (var r = 0; r < noOfLinks; r++) {
var normalText = rollLinks[r].innerHTML;
var rolloverText = rollLinks[r].title;
var rolloverItem = document.getElementById(rollover);
rolloverItem.innerHTML = "<a href='#' title='" + normalText + "'>" + rolloverText + "</a>";
rolloverItem.class = rollover + "rollover";
}
}
HTML:
<div class="nav">
<ul id="NavItems">
<li id="item0" class="selected" onClick="changeClass(this.id)"
onmouseover="changeRollover(this.id)">
Collections
</li>
<li id="item1" onClick="changeClass(this.id)"
onmouseover="changeRollover(this.id)">
<a href="#" title="Shop Everything" >All Jewlery</a>
</li>
<li id="item2" onmouseover="changeRollover(this.id)"
onClick="changeClass(this.id)">
As Seen On
</li>
<li id="item3" onmouseover="changeRollover(this.id)"
onClick="changeClass(this.id)">
Collaborations
</li>
<li id="item4" onmouseover="changeRollover(this.id)"
onClick="changeClass(this.id)">
Designer Pop Ups
</li>
</ul>
<div class="shipping">
<a href="#">start your free orders today<br>
*** click here for more information ***</a>
</div>
</div>
<!-- .nav -->
The effect you want (dubious from a usability perspective, but that aside) is better achieved using some simple CSS:
#NavItems .hover {
display: none;
}
#NavItems:hover .hover {
display: inline;
}
#NavItems:hover .normal {
display: none;
}
Which requires markup like this:
<ul id="NavItems">
<li id="item0">
<a href="#">
<span class="normal">Collections</span><span class="hover">Shop Trends</span>
</a>
</li>
</ul>
Depending on your browser compatability requirements, I'd recommend using onmouseenter instead as the trigger for your function.
DOM Events - Browser Compatability
But for one thing, you're missing an onmouseout function that can reset the class for you. Once you attach a class to an element, it has to be removed manually as well if you want it to go away depending on what the user does. So create something like a resetRollover function, like the one below, and attach an onmouseout DOM listener that fires that function:
function resetRollover(rollover) {
var className = document.getElementById(rollover).className;
document.getElementById(rollover).className = className.substring(0, indexOf(' rollover'));
}
The problem is your onmouseover handler is on the lis. When the mouse hovers over the <a>s in the <li> and "reenters" onmouseover of the <li> is triggered again.
Example here: this is the same code as yours, I added some colors. If you move the mouse only on the black part (the <li>), the rollover happens as desired. But when you move the mouse on the green part (the <a>s).
As a solution, you can either handle the rollover on the <a>s or change your basic design (see #Thomas' answer)

Categories