How to catch a state change event ONCE with history.js? - javascript

I have an example code below where if you click the links, then use back and forward, each state change will cause more and more hits on the statechange event. Instead of the one that I expect.
Links:
https://github.com/browserstate/history.js
http://docs.jquery.com/Downloading_jQuery
Code:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>History start</title>
</head>
<body>
<h1>Headline</h1>
<hr>
<div id="menu">
<ul>
<li>
Page 1
<div style="display:none;">
<h2>Page 1</h2>
<p>Content 1</p>
</div>
</li>
<li>
Page 2
<div style="display:none;">
<h2>Page 2</h2>
<p>Content 2</p>
</div>
</li>
</ul>
</div>
<hr>
<div id="content">
<h2>Start page</h2>
<p>Paragraf</p>
</div>
<script src="external/jquery-1.6.2.min.js"></script>
<script>if ( typeof window.JSON === 'undefined' ) { console.log("Loaded json2"); document.write('<script src="external/json2.js"><\/script>'); }</script>
<script src="external/history.adapter.jquery.js"></script>
<script src="external/history.js"></script>
<script>
$(document).ready(function() {
History.enabled = true;
$('a').each(function() {
$(this).click(function(e) {
e.preventDefault();
var $link = $(e.target),
state = {'href': $link.attr('href'), 'title': $link.html()},
$div = $link.siblings('div'),
content = $div.html();
$('#content').html(content);
History.pushState(state, state.title, state.href);
return false;
});
});
History.Adapter.bind(window, 'statechange', function() {
var State = History.getState();
// remove double hit on event
console.log(State);
});
});
</script>
</body>
</html>

It's because you're calling the pushState function when you load the page, which also causes a statechange. I was in a similar situation and used a but a boolean before my pushStates so I knew I was doing a pushState. It looks like this...
historyBool = true;
History.Adapter.bind(window,'statechange',function(){ // Note: We are using statechange instead of popstate
var State = History.getState(); // Note: We are using History.getState() instead of event.state
//don't run our function when we do a pushState
if(historyBool){
historyBool = false;
tempFunction = new Function(State.data.ajaxRunFunction);
tempFunction();
}
historyBool = true;
});
historyBool = false;
historySet = {ajaxRunFunction: "upc('" + pageID + "','')"};
History.pushState(historySet,"","");

While not relevant to your specific problem, I had a scenario where I needed to unbind the event handler from the History Adapter. To do so you can unbind the "statechange" event from window, which is what History.Adapter binds to when you call History.Adapter.bind() :
$(window).unbind('statechange.namespace');
You can added a namespace to the event to avoid unbinding other unrelated event handlers as above, or use a named function to unbind that function specifically.
To use the above namespace, you would need to bind the handler using the same namespace, ie
History.Adapter.bind(window,'statechange.namespace',function(){...}

Related

how to access value of variable which exists inside of click handler, and store outside of it in variable

Question may sound tricky because I'm new in JS programming. First let me show you code,
<ul id="myid4" class="c_select_ul">
<li>
<div class="option op_cl">
<div class="color"></div>
<p>White</p>
</div>
</li>
<li>
<div class="option op_cl">
<div class="color black"></div>
<p>Black</p>
</div>
</li>
</ul>
and JS code is
$("ul[id*=myid4] li").click(function () {
var color = $(this).text();
color = color.replace(/^\s+|\s+$/g, "");
console.log(color);
});
So what I want do is, access the value of variable "color" outside of click handler and and store in another variable. It can be logged inside of it as I have shown in code. I want to use it in other functions also like to send with ajax call.
I can make ajax call inside of it but, I have three other selections to make in same way and send the four values via ajax call and receive result.
thanks in advance.
This question is about the scope of the variable, Global vs local variable. You have declared variable inside the callback of click event, so it dies once the execution is over.
To solve this, you need to declare variable globally. You can declare that outside the callback handler.
<html>
<head>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"></script>
</head>
<body>
<ul id="myid4" class="c_select_ul">
<li>
<div class="option op_cl">
<div class="color"></div>
<p>White</p>
</div>
</li>
<li>
<div class="option op_cl">
<div class="color black"></div>
<p>Black</p>
</div>
</li>
</ul>
<button type="button" onclick="submit()">submit</button>
<script>
var color;
$("ul[id*=myid4] li").click(function () {
color = $(this).text();
color = color.replace(/^\s+|\s+$/g, "");
console.log(color);
});
function submit() {
console.log('printing from other function-->', color);
}
</script>
</body>
</html>
Now, you can access the variable everywhere inside the JS file.
If you want to call AJAX once all 4 selections are made, use class selector instead of ID:
var state = {};
var handleSelect = function (index, selected) {
state[index] = selected;
if (Object.keys(state).length === 4) {
console.log('All 4 selection are made', state);
// Call ajax
}
};
$(".c_select_ul li").click(function () {
var color = $(this).text();
color = color.replace(/^\s+|\s+$/g, "");
console.log(color);
var index = $(this).closest("ul").index("ul");
handleSelect(index, color);
});
I assume you are using Jquery. You can also do sth like this.
window.color = ""; //notice the window.
$(function(){
....
})
function myfunction(){
$("ul[id*=myid4] li").click(function () {
var color = $(this).text();
color = color.replace(/^\s+|\s+$/g, "");
console.log(color);
});
}

Getting the child img inside a div using $(this); [on click event]

I'm trying to get the child image of a clicked div.
I want to get it's src value. But it's returning undefined.
Could someone point me in the right direction?
Tried using Jquery .find() https://api.jquery.com/find/
Tried using Jquery .children() https://api.jquery.com/children/
Both return undefined.
for (let i = 0; i < $('#draw-raster > div').length; i++) {
$(document).on('click', '#raster-item'+i, () => {
let image = $(this).children('img').attr('src'); //undefined
let image2 = $(this).find('img').attr('src'); //undefined
if (image) {
console.log(image);
return alert("image child found!");
}
return setTimeout(() => {
$('#raster-item'+i).children('img').hide();
}, 4500);
});
$('#image'+i).hide();
}
load html:
for(let i = 0; i < 16; i++)
{
let image = displayImages();
$('#draw-raster').prepend(
"<div id=raster-item" + i + " class='imageh"+i+"' data-id=" + i + "><img src='"+ displayImages() +"' class='image "+i+"' id='image"+ i +"' alt='Failed to load image' width='173.19' height='107.3'></div>"
);
}
html page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Memory</title>
<script src="inc/js/jquery.min.js"></script>
<link rel="stylesheet" href="inc/css/boostrap.min.css">
<link rel="stylesheet" href="inc/css/memory.css">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<div class="container justify-content-center">
<div class="wrapper">
<div class="row">
<div class="col-lg-9">
<div class="card">
<div class="card-header bg-dark" style="color:white;">
<h2>Memory</h2>
</div>
<div class="card-body">
<section class="col-12 mx-auto" id="draw-raster">
</section>
</div>
</div>
</div>
<div class="col-lg-3">
<div class="card">
<div class="card-header bg-dark" style="color:white;">
<h2>Turns</h2>
</div>
<div class="card-body">
<div id="turns">Turns: 0</div>
<div id="sets">Sets: 0</div>
</div>
</div>
<div class="form-group">
<button class="btn btn-success col-12" type="button" id="reset">Reset scores</button>
</div>
</div>
</div>
</div>
</div>
<script src="inc/js/memory.js"></script>
</body>
</html>
Both attempts return undefined, i'm uncertain what would work.
Yes, I've been spamming google too. :'^)
A couple of notes on your code:
1) If you want to use this you'll need to switch from an arrow function back to a regular anonymous function. Arrow functions don't have a this of their own and will borrow the context from their outer lexical environment. It's why your code keeps return undefined.
2) You don't need a loop. The benefit of using jQuery is that you can operate on collections of elements all at once. In your case you're attaching a single event listener to a parent element (here: document) and waiting for events to bubble up from the .raster-item imgs and be "captured". This is called event delegation and is useful when you want to process new elements added to the DOM after it has loaded.
2) You will find it easier to use a class instead of many ids.
Here's an example based on your code with these changes:
// Use event delegation to add an event listener to the element with
// the container class that watches out for click events on **all**
// elements with the raster-item class that contain images
$('.container').on('click', '.raster-item img', function () {
// `$(this)` will be the image element, so simply grab its src
// from the attribute
console.log($(this).attr('src'));
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="raster-item"><img src="https://dummyimage.com/50x50/555/fff.png" /></div>
<div class="raster-item"><img src="https://dummyimage.com/50x50/777/fff.png" /></div>
<div class="raster-item"><img src="https://dummyimage.com/50x50/999/fff.png"/></div>
<div class="raster-item"><img src="https://dummyimage.com/50x50/bbb/fff.png" /></div>
</div>
You don't need jQuery for this. You can harness the power of event bubbling with vanilla JavaScript.
In the web page below, the code inside the script tags, listen for a click event and runs some code if that event happens, i.e. bubbles, through a DIV element:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Clicked div img</title>
</head>
<body>
<div class="catcher">
<p>This is a div with an image inside</p>
<img src="image-to-pick.jpg" alt="image to pick" ()>
</div>
<script>
document.addEventListener('click', function (event) {
if (event.target.tagName == 'DIV') {
var imgToPick = event.target.querySelector('img');
console.log(imgToPick.src); // add your code here
}
}, false);
</script>
</body>
</html>
In other words, you trigger a "click event" whenever you click on that page, that event bubbles up until it reaches the root of the HTML document (which you can imagine as an upside-down tree where the root is the html tag).
If you don't need or don't want to let it bubble to the elements "above" you DIV, you can also stop the propagation of that click event by using event.stopPropagation(), right after you handle the img src.
You can find more info about how this works here on MDN (Mozilla Dev. Network)
I'm not quite sure in what context you need to do this, but with jquery it's pretty straight forward.
If you have multiple images within a parent div, you can set the child images as the selecters for the click event, and return each image src when clicked on directly.
The resulting jquery is only three lines long this way, and you can add as many images as you like to the parent div:
<div class="image-container">
<img id="first" src="first-source-goes-here.jpg" alt="img text" />
<img id="second" src="second-source-goes-here.jpg" alt="img text" />
<img id="third" src="third-source-goes-here.jpg" alt="img text" />
</div>
$(".image-container > img").click(function() {
// replace 'alert' with what ever you need it to be
alert( $(this).attr("src") )
})
EDIT:
In response to Andy's comment on my answer below, if you are loading images once the DOM has been loaded, then you could run a check on the click parent div to see if there are any images within it before returning the source:
$(".image-container").click(function() {
if( $(this).children("img").length > 0 ) {
alert( $(this).find("img").attr("src") )
} else {
alert('there are no images here')
}
})

use Jquery to click hyperlink

I am trying to create a jquery to click a hyperlink but nothing seems to be working.
HTML
<main id="main" class="main-content">
<div class="container">
<div class="warning" role="alert">
no avail
Show all
</div>
what I was trying
$(".warning a").click()
Any suggestions?
Note that jQuery-initiated "click" events will fire the event but will not cause navigation to occur.
Instead you can read the link's HREF attribute and directly set the window location:
// The click event:
$('a').on("click", function() {
console.log("Click event fired");
})
var demo1 = function() {
// This will trigger the click event, but will not navigate.
$(".warning a").click()
}
var demo2 = function() {
// This will navigate but will not trigger the click event. (If you need both to happen, trigger the click event first, and consider delaying the window location update if necessary.)
var url = $(".warning a").attr("href")
window.location = url;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<main id="main" class="main-content">
<div class="container">
<div class="warning" role="alert">
Show all
</div>
</div>
</main>
<!-- for demo: -->
<button onclick="demo1()">Won't work</button>
<button onclick="demo2()">Will work</button>
jQuery's .click() (without arguments) is a shortcut for .trigger("click"):
function(a,c) {
return arguments.length > 0 ? this.on(b, null, a, c) : this.trigger(b)
}
Therefore, it will not actually click the element, but just call the click event handlers attached to it, as you can see here:
const $link = $("a");
$link.on("click", () => {
console.log("Clicked? Not really...");
});
$link.click();
$link.trigger("click");
Show all
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You need to get a reference to the actual DOM element and then call HTMLElement.click() on that:
$("a")[0].click();
Show all
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
You can user the vanilla click method:
document.querySelector('.warning > a').click()
// equivalent jquery
//$('.warning > a')[0].click()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="warning" role="alert">
no avail
Show all
</div>
Whenever you select div class with hyperlink there you get array because you can have multiple hyperlinks so you need to add somthing like below
Code
$('.warning a')[0].click();
For reference link
Get working example for click event
If I need to redirect, I typically use window.location.href
window.location.href=$(".warning a").attr('href');

Show/Hide javascript query

I made this html test website to test show/hide javascript.
When I load the page, I would like to show the first page but in my website everything is hidden 'till I click on a button'.
<html>
<head><title>Test</title>
<script>
function toggle(target){
var artz = document.getElementsByClassName('article');
var targ = document.getElementById(target);
var isVis = targ.style.display=='block';
for(var i=0;i<artz.length;i++){
artz[i].style.display = 'none';
}
targ.style.display = isVis?'none':'block';
return false;
}
</script>
</head>
<body>
About Us
Contact
Products
<div class="article" id="about" style="display:none;">ABOUT PAGE...</div>
<div class="article" id="contact" style="display:none;">CONTACT PAGE...</div>
<div class="article" id="products" style="display:none;">PRODUCTS PAGE...</div>
</body>
</html>
Well, that's because all your elements are hidden and the toggle-function is only invoked on click.
Use this:
window.onload = function(){
toggle('about'); //or whichever page you'd like to show on startup
}
This function is invoked on page-load and calls the toggle-function, providing the content that shoud be shown.
Alternatively, you could just change your style="display:none;" to style="display:block;" in the HTML for the content that should be shown on page-load.

How to submit a form when tab is click

I would like to submit a form, when a tab is clicked. This is what I have so far:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Submit a Form on Tab Click</title>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<style type="text/css">
</style>
<script>
$(function() {
$( "#Main" ).tabs();
});
</script>
<script>
$(document).ready(function(){
$('#Tab1').click(function(){
$('#Form_1').submit();
});
</script>
</head>
<body>
<div id="Main">
<ul>
<li>Tab1</li>
<li>Tab2</li>
<li>Tab3</li>
<li>Tab4</li>
<li>Tab5</li>
<li>Tab6</li>
</ul>
<form id="Form_1" action="Tab_Click_v00.html" method="post">
<input type="hidden" name="Nb_var99" value="1">
</form>
<div id="Tab1">
<p>Tab1</p>
</div>
<div id="Tab2">
<p>Tab2</p>
</div>
<div id="Tab3">
<p>Tab3</p>
</div>
<div id="Tab4">
<p>Tab4</p>
</div>
<div id="Tab5">
<p>Tab5</p>
</div>
<div id="Tab6">
<p>Tab6</p>
</div>
</div>
</body>
</html>
Each tab will submit a different form. I hope this helps to identify what I am trying to
achieve. I am new to all this so please be specific.
Thank you.
You can use this jQuery:
jsFiddle here
$(document).ready(function() {
$( "#Main" ).tabs();
$('[id^=ui-id-]').click(function() {
var tabId = $(this).attr('id');
alert('Tab clicked: ' + tabId );
if (tabId == 'ui-id-1') {
$('#LoginForm').submit();
}else if (tabId == 'ui-id-2') {
$('#form2').submit();
}else if (tabId == 'ui-id-3') {
$('#form3').submit();
}
});
});
jQueryUI tabs all have IDs beginning with ui-id-#, where # is the tab number (for example, ui-id-3.
The selector $('[id^=ui-id-]') means: For any element whose ID attribute begins with ui-id-, trap the click event and do this...
Note that the <form> tag must have an ID attribute, as specified in the above code. For example, for the form on Tab 3:
<form id="form3" action="whatever.php" method="POST">
Suppose each tab has a form on it and, for example, the forms all have IDs that are sequentially numbered according to the tab they are on, such as Form-1, Form-2, Form-5, etc. Then you could use the line var tabId = $(this).attr('id') to do this:
$(document).ready(function() {
$( "#Main" ).tabs();
$('[id^=ui-id-]').click(function() {
var tabId = $(this).attr('id'); //ui-id-4
var tabNum = tabId.split('-')[2]; //4
$('#Form-' + tabNum).submit();
});
});
For example, suppose the tab's ID is ui-id-4, then you would want to give the <form> for tab 4 an ID: <form id="Form-4">. The above code would then submit that form when the tab was clicked.
Note that the above code expects that your form tags will have an ID, such as:
<form id="myFormId" action="somepage.php" method="POST" >
Assuming your form will have an id of 'myform', you can put a click event listener on the tabs.
Add a class to your tabs class='tab'
$('.tab').on('click', function(){
$('#myform').submit();
});
The tabs widget has some events you can use. For example, when a tab is activated, you can have a handler for the activate event. You can use standard jQuery event handling, and specify the tabsactivate event. Something like this:
$('#Main').on('tabsactivate', function (event, ui) {
// your logic here
$('#someForm').submit();
});
You can inspect the ui argument passed to that event handler for information about the tab. For example, the specific tab being moved from/to. Like:
if (ui.oldPanel.selector == '#Tab1') {
// The user just left Tab1
}
So within that handler you'd perform whatever task you need to perform when a tab changes.
First each tab could have a reference to each form that must be submitted on tab click.
<ul>
<li>Tab1</li>
<li>Tab2</li>
<li>Tab3</li>
<li>Tab4</li>
<li>Tab5</li>
<li>Tab6</li>
</ul>
Then bind a click event to each tab:
$("#Main").on("click", "a", function() {
var formId = $(this).data("form");
$(formId).submit();
});
The easy way, asign an id attribute to each <a> and <form> and then do this:
<script type="text/javascript">
$(document).ready(function(){
$('#tab1').click(function(){
$('#form1').submit();
});
$('#tab2').click(function(){
$('#form2').submit();
});
$('#tab3').click(function(){
$('#form3').submit();
});
});
</script>
A fiddle example here

Categories