I am building a hybrid application out of Jquery Mobile, Cordova and WordPress. My current question is regarding my navigation between "pages" in index.html that have the data-role="page" attribute.
Current Setup: I am using data-role="navbar" inside data-role="header" and EACH page has the following header:
<div data-role="navbar">
<ul>
<li><a class="blue-button home-button" href="#" data-transition="slidefade">HOME</a></li>
<li><a class="blue-button artist-refresh artist-button" href="#" data-transition="slidefade">ARTIST</a></li>
<li><a class="blue-button show-button" href="#" data-transition="slidefade">SHOW INFO</a></li>
</ul>
</div><!-- /navbar -->
main.js file I am trying to add event listeners to each of the navigation elements by class name and .ui-page-active class I am also bundling in a few other unique elements that have clickEvents but I reference them by ID:
function setupMainNav() {
console.log("Settign Up SUB NAV");
$('.ui-page-active .show-button').on('click', function () {
console.log("In the show info click");
$.mobile.changePage("#show-info", {
transition: "slide"
});
});
$('.ui-page-active .home-button').on('click', function () {
console.log("In the show info click");
$.mobile.changePage("#home", {
transition: "slide"
});
});
$('#artistContactButton').on('click', function () {
console.log("Show Contact Form");
$.mobile.changePage("#artist-contactpage", {
transition: "slide"
});
});
$('div.ui-page-active a.artist-button').on('click', function () {
console.log("artist button click");
$.mobile.changePage("#cyan-home", {
transition: "slide"
});
});
$('#show_link').on('click', function () {
$.mobile.changePage("#cyan-home", {
transition: "slide"
});
});
$('#shop_link').on('click', function () {
$.mobile.changePage("#shop-home", {
transition: "slide"
});
});
}
What I do is try to all the setupMainNav() function every-time a page changes using the .on('pagecreate') but only the first page that is loaded which has the #show_link and #shop_link elements with those ID's and of course those are the only two.
What are best practices for setting up navigation that is controlled via the JS and not the <a href>
Disclaimer: these are a few of what I think of as "best practices." Others may disagree; YMMV. Also this is assuming you don't want to use libraries or frameworks like Vue.js or React.js, which in general will do things quite differently. Depending on circumstances these libraries can have both advantages and drawbacks.
But within those limits, the general idea is this:
Keep the event handler generic, so that one function can do multiple things.
Pass in stuff that differs between links as attributes. This keeps things related to the activity together at the link.
I like to attach the event listener higher up in the DOM and then handle the events as they bubble. In this case we're attaching the event to the ul tag, and catching any click events that bubble up from a tags. IMHO this has a few advantages:
if you mutate the list, new links will automatically use the current event handler.
you only have one event handler attached to the DOM, instead of 3 (however many a tags you have)
this also gives you the chance to add other event listeners directly to specific a tags if you want to do something special before (or instead of) the default action. Because events attached directly happen first, and then the event bubbles. If you want it to happen instead of, you would just call e.stopPropagation() to prevent the event from bubbling.
Also what I've done sometimes in the past is to have a single generic page with header and navbar, and then load the main content div via ajax. This has the very visually pleasing effect that when you go to a different page the navbar stays put, and doesn't reload. You could easily do this in the example code below, if changePage was doing an XHR/fetch, and then loading the contents into a main content div.
In this greatly simplified example, I show how we can use the href, innerText, and a data attribute to do different things depending on which link is clicked. Of course you can do as much (or as little) as you want/need in this regard.
$('ul.navbar').on('click', 'a', function(e) {
var t = e.target;
var info = t.dataset.info || '';
console.log("click " + t.innerText + ' ' + info);
$.mobile.changePage(t.href, {
transition: "slide"
});
e.preventDefault();
return false;
});
// stub of $.mobile.changePage
$.mobile = {
changePage: function(href, opts) {
console.log('changePage', href);
}
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class='navbar'>
<li>HOME</li>
<li>ARTIST</li>
<li>SHOW INFO</li>
</ul>
Related
I am building a hybrid application out of Jquery Mobile, Cordova and WordPress. My current question is regarding my navigation between "pages" in index.html that have the data-role="page" attribute.
Current Setup: I am using data-role="navbar" inside data-role="header" and EACH page has the following header:
<div data-role="navbar">
<ul>
<li><a class="blue-button home-button" href="#" data-transition="slidefade">HOME</a></li>
<li><a class="blue-button artist-refresh artist-button" href="#" data-transition="slidefade">ARTIST</a></li>
<li><a class="blue-button show-button" href="#" data-transition="slidefade">SHOW INFO</a></li>
</ul>
</div><!-- /navbar -->
main.js file I am trying to add event listeners to each of the navigation elements by class name and .ui-page-active class I am also bundling in a few other unique elements that have clickEvents but I reference them by ID:
function setupMainNav() {
console.log("Settign Up SUB NAV");
$('.ui-page-active .show-button').on('click', function () {
console.log("In the show info click");
$.mobile.changePage("#show-info", {
transition: "slide"
});
});
$('.ui-page-active .home-button').on('click', function () {
console.log("In the show info click");
$.mobile.changePage("#home", {
transition: "slide"
});
});
$('#artistContactButton').on('click', function () {
console.log("Show Contact Form");
$.mobile.changePage("#artist-contactpage", {
transition: "slide"
});
});
$('div.ui-page-active a.artist-button').on('click', function () {
console.log("artist button click");
$.mobile.changePage("#cyan-home", {
transition: "slide"
});
});
$('#show_link').on('click', function () {
$.mobile.changePage("#cyan-home", {
transition: "slide"
});
});
$('#shop_link').on('click', function () {
$.mobile.changePage("#shop-home", {
transition: "slide"
});
});
}
What I do is try to all the setupMainNav() function every-time a page changes using the .on('pagecreate') but only the first page that is loaded which has the #show_link and #shop_link elements with those ID's and of course those are the only two.
What are best practices for setting up navigation that is controlled via the JS and not the <a href>
Disclaimer: these are a few of what I think of as "best practices." Others may disagree; YMMV. Also this is assuming you don't want to use libraries or frameworks like Vue.js or React.js, which in general will do things quite differently. Depending on circumstances these libraries can have both advantages and drawbacks.
But within those limits, the general idea is this:
Keep the event handler generic, so that one function can do multiple things.
Pass in stuff that differs between links as attributes. This keeps things related to the activity together at the link.
I like to attach the event listener higher up in the DOM and then handle the events as they bubble. In this case we're attaching the event to the ul tag, and catching any click events that bubble up from a tags. IMHO this has a few advantages:
if you mutate the list, new links will automatically use the current event handler.
you only have one event handler attached to the DOM, instead of 3 (however many a tags you have)
this also gives you the chance to add other event listeners directly to specific a tags if you want to do something special before (or instead of) the default action. Because events attached directly happen first, and then the event bubbles. If you want it to happen instead of, you would just call e.stopPropagation() to prevent the event from bubbling.
Also what I've done sometimes in the past is to have a single generic page with header and navbar, and then load the main content div via ajax. This has the very visually pleasing effect that when you go to a different page the navbar stays put, and doesn't reload. You could easily do this in the example code below, if changePage was doing an XHR/fetch, and then loading the contents into a main content div.
In this greatly simplified example, I show how we can use the href, innerText, and a data attribute to do different things depending on which link is clicked. Of course you can do as much (or as little) as you want/need in this regard.
$('ul.navbar').on('click', 'a', function(e) {
var t = e.target;
var info = t.dataset.info || '';
console.log("click " + t.innerText + ' ' + info);
$.mobile.changePage(t.href, {
transition: "slide"
});
e.preventDefault();
return false;
});
// stub of $.mobile.changePage
$.mobile = {
changePage: function(href, opts) {
console.log('changePage', href);
}
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class='navbar'>
<li>HOME</li>
<li>ARTIST</li>
<li>SHOW INFO</li>
</ul>
I have a web application that is expected to run on iPad. I do not wish to create a "dropdown" HTML element for navigation (ie. a select element) since I have plenty of real estate. I want to use my existing desktop-style "hover over then select" type navigation, but replace the hover event with a tap.
I only need to support mobile Safari for iPad, though other browser support could be a plus.
Here's how the nav is structured:
<nav id="main_navigation">
<ul>
<li>
<a id="nav_home" href="/index.jsp">home</a>
</li>
<li class="menuHasDrop" id="selected">
<a id="parent" href="/parent.jsp">parent</a>
<span class="navArrow"></span>
<ul>
<li><a id="foo" href="/foo.jsp">foo</a></li>
<li><a id="bar" href="/bar.jsp">bar</a></li>
</ul>
</li>
<li>
<a id="baz" href="baz.jsp">baz</a>
</li>
</ul>
</nav>
And here's how I'm detecting and enabling touch:
fc.enableTouch = function() {
(function() {
try {
document.createEvent('TouchEvent');
fc.touchEnabled = true;
} catch(e) {}
})();
if (fc.touchEnabled) {
$(document).ready(function() {
// disable clicks on parents
var $menus = $('.menuHasDrop');
$menus.on('click', '>a', function(e){
return false;
})
// listen for clicks on others
$('#main_navigation').on('click', $menus, function(e) {
e.stopImmediatePropagation();
var $this = $(this);
if ($this.parent().children('ul').length > 0) {
$menus.find('ul').hide();
$this.toggleClass('expanded');
if($this.hasClass('expanded')) {
$this.find('ul').show();
}
}
});
});
} else {
// console.log('not detecting touch');
}
}();
The "expanded" class is just a flag. I could set a flag another way, but it shouldn't matter much.
So, this all "works"... but there are two things bugging me:
There's a flicker of a shadow of some sort over the parent nav when I click it. I'm sure it's an OS "clicked a link" indicator, but it's not explicitly provided by CSS or the JavaScript. If anybody has seen such a thing, do you know how to disable it?
Every now and then on a fluke it seems, the UL representing the sub-menu seems to appear, go away, and appear again. Again, I don't THINK the logic itself would be able to cause this, so it might be browser-specific.
Other useful background information: there are always one or more content areas being refreshed via ajax calls, but the page itself is not being refreshed and the navigation area does not have any functions acting on it during the request.
I guess what I'm asking more than a code review is: "Are these just iOS quirks that I have to live with?" and "is there a definitive better practice for touch-enabling dropdowns?" Secondarily, all "I see a problem with your code" advice will be welcomed and appreciated. :)
To get rid of tap colour
-webkit-tap-highlight-color:rgba(0,0,0,0);
For binding, use touchstart/touchend what I have done in my current project is to detect touch, if touch enabled bind only touchstart and end, if not then bind click
I would also add a class to the anchor that you are targeting using ">a", that's really slow
$(#el).on('touchstart', function() {
// if class exist
// go to link
// else
// add class and open dropdown
});
For my current project we set up a virtual event handler to detect if the touch is a touchmove or just a regular touchstart
You can also do something like this
$(#el).on('touchstart', function() {
$(this).trigger('click');
// or you can use prevent default and stopPropagation
return false;
});
or bind on touchend, whatever works better for you
I am trying to complete some action when a link is clicked in my application.
For example, I am creating a manual that has multiple internal links within the document. Currently, I would be handling them like so:
function waitForClick()
{
$('#about').click(function()
{
$('#container').slideDown();
});
$('#using').click(function()
{
changeContent...
});
<!-- etc, etc -->
}
Is there a better way to handle multiple click events, so that I don't need an event for every single item. I'm sure there has to be a way to delegate which item was clicked.
HTML:
<li><a id="about" href="#">About this Application</a></li>
<li><a id="using" href="#">Using this Manual</a></li>
<li><a id="pages" href="#">Pages:</a></li>
<!-- etc, etc -->
This is supposed to be a table of contents for the manual. So there are going to be a lot of local links.
Personally I'd use something like the below. It avoids a ton of events being cast individually and is scalable enough for your purpose. All you do is add a class of "clickEventClasss" (or whatever takes your fancy) to each element that should have an event an add an id so you can recognise each one.
function waitForClick()
{
$('.clickEventClass').click(function() {
var id = $(this).attr('id');
switch(id) {
case 'about':
//Logic
break;
case 'using':
//Logic
break;
}
});
}
You could bind click events to classes rather than ID's.
<a class="navigationLink" href="home.com">Home</a>
<a class="navigationLink" href="about.com">About</a>
<a class="navigationLink" href="contactus.com">Contact Us</a>
$(".navigationLink").click(function() {
//Do something cool
});
You could use a class where you assign the click event to.
After this the following is possible:
$(".class").click(function()
{
if($(this).attr("id") == "about")
{
//code here
}
else if($(this).attr("id") == "using")
{
//code here
}
}
what my current Code do :
i have this HTML
<li>
<span>Logged in as</span>
<a class="user" href="#"><?php echo $this->loggedas ?></a>
<a id="loginarrow" href="javascript: void(0);"></a>
</li>
this is my JS for above loginarrow id
$("#loginarrow").click(function() {
$("#logindrop").toggle("slow");
return false;
});
its working great but i can close it by clicking it again.
i dont want so i want that if its open and i click on background so it must close.
for that i did so
$("#loginarrow,body").click(function() {
$("#logindrop").toggle("slow");
return false;
});
now its working cool,But Got another problem.
1 = i have many other html elements in Page (Body) in which there are other events to call.so in this case whenever i click other elements in my page so its Toggling my this div loginarrow.
i want the same functionality but not on my other elements only on background.
Any Hint
close it only when it visible.
$("body").click(function() {
if ($("#logindrop").is(":visible"))
$("#logindrop").hide("slow");
});
A fundamental design principle for good browser performance is to only capture events while you're interested in them.
So put your .click() handler on the #loginarrow element, but in that handler register a one-off event handler on the body that will close it again. Something like (untested):
$('#loginarrow').click(function() {
$('#logindrop').show('slow');
$('body').one('click', function() {
$('#logindrop').hide('slow');
});
return false;
});
This will ensure that you're not unnecessarily intercepting every click on the body except when you really need to.
​See http://jsfiddle.net/alnitak/vPHaj/
I have a small chunk of code, like this:
$("div.footerMenu li").click(
function () {
$("div.onScreen").hide();
$(this).children("div.onScreen").fadeIn('fast');
},function(){
$("div.onScreen").hide();
});//click
And when I click on <li> the div .onScreen shows nicely, but when i click on this div, that just showed up the functions is hiding in and showing again, but I don't want it to execute this function again. So my question is: How can I somehow "detach/exclude/hide" this div from Javascript?
update:
The thing is that with this method and with others with .one() the rest of menu is not working. There is the site with the problem here . I want this div that shows up stay there, when I click on it, but when I click on their items <li> I want to other div's (submenus) to show up (warning - big images on that site).
The html looks like this:
<div class="footerMenu"> <ul> <li>HOME<div class="onScreen"><div style="padding:50px;"><img src="fillTxt.png"></div></div></li> <li>PLENER<div class="onScreen"> <div style="padding:50px;"><img src="fillTxt2.png"></div></div> </li> <li>STUDIO<div class="onScreen"> <div style="padding:50px;"><img src="fillTxt.png"></div></div> </li> <li>INNE<div class="onScreen"> <div style="padding:50px;"><img src="fillTxt2.png"></div></div> </li> </ul> </div>
The simple solution is:
$('div.footerMenu li').unbind('click');
But should you have multiple click handlers on the selector, you may want to only remove one at a time. The way to do that is to store a reference to the function being passed:
function hideItem()
{
...code...
//unbind the click event
$(this).unbind('click', hideItem);
}
$('div.footerMenu li').click(hideItem);
If you want to handle an event only once, you can use the one() method:
$("div.footerMenu li").one("click", function() {
$("div.onScreen").hide();
$(this).children("div.onScreen").fadeIn("fast");
});
You can use .one():
$("div.footerMenu li").one('click', function(){
things_to_happen_only_once();
// unbinding happens automatically
});