Programmatic (as opposed to link-based) navigation in jQueryMobile - javascript

The problem has been discussed several times, but I am yet to see a concrete answer.
Similar/same question : SO question
Suppose that I have index.html:
<div id="index1" data-role="page">
<div data-role="header"><h1>Index 1</h1></div>
<div data-role="content"></div>
<div data-role="footer">
<a data-role="button" id="toshop2">
To Shop 2
</a>
</div>
</div>
and shop.html:
<div id="shop1" data-role="page">
<div data-role="header"><h1>Shop 1</h1></div>
<div data-role="content"></div>
<div data-role="footer">
<a data-role="button" href="#shop2">To Shop 2</a>
<a data-role="button" href="index.html" rel="external">
To Index
</a>
</div>
</div>
<div id="shop2" data-role="page">
<div data-role="header"><h1>Shop 2</h1></div>
<div data-role="content"></div>
<div data-role="footer">
<a data-role="button" href="#shop1">To Shop 1</a>
<a data-role="button" href="index.html" rel="external">
To Index
</a>
</div>
</div>
and I want to do something like:
$('#toshop2').on('click', function() {
$.mobile.changePage("shop.html#shop2");
});
which, as we all know by now, won't work. It'll grab the first DOM page (#shop1 out of shop.html and append it into index.html DOM.
I know that something silly like:
$('#toshop2').on('click', function() {
window.open('shop.html#shop2', '_parent');
});
would work (yes, there won't be a transition).
Questions are (assuming there is no other solution, but to hack):
Can I/should I hack it differently?
Can I somehow still get transition to an external page?

You can request the external document manually and then only insert the portion that you want to the DOM:
//delegate event handler binding to links with a custom class
//(any link that links to a pseudo-page in an external document
$(document).delegate('.my-external-links', 'click', function () {
//get the location of the external document and the requested page (hash)
var theHREF = this.href,
theTarget = '#shop1';
if (theHREF.indexOf('#') > -1) {
theTarget = '#' + theHREF.split('#')[1];
theHREF = theHREF.split('#')[0];
}
//first see if this page is already in the DOM, if so just navigate to it
if ($(theTarget).length) {
$.mobile.changePage($(theTarget));
return;
}
//show the loading spinner
$.mobile.showPageLoadingMsg();
//do AJAX request to get new pages into the DOM
$.ajax({
url : theHREF,
success : function (response) {
//hide the loading spinner
$.mobile.hidePageLoadingMsg();
//find all the `data-role="page"` elements and add them to the DOM
$(response).find('[data-role="page"]').appendTo('body');
//now navigate to the requested page which should be in the DOM
$.mobile.changePage($(theTarget));
},
error : function (jqXHR, textStatus, errorThrown) { /*don't forget to handle errors*/ }
});
return false;
});
I'm pretty sure there is a plugin for this as well, but as you can see it's not that much code or complication.

why don't you try to use changepage twice?
$.mobile.changePage( "shop.html", { transition: "none"} );
$.mobile.changePage( "#shop2", { transition: "slideup"} );
or just use loadPage to load the shop.html into DOM in background and change to #shop2 after?
$.mobile.loadPage( "shop.html" );
$.mobile.changePage( "#shop2", { transition: "slideup"} );

Related

Jquery load method conflict current script with child page external script

I have a free template with dashboard menu and the main content section. I want that when a user clicks on menu link and the child page will be loaded into the main content section. I don't want to user embed tag or iframe because of some problems so I tried Jquery load method and $.ajax.
The problem is the menu included 2 external scripts (bootstrap and jquery); when child page loaded, they didn't understand scripts of the menu. But if I put 2 more same scripts tag to child page or using $.getScript(), the child page loaded but jquery.js and bootstrap.js were seemed to be conflicted and worked on the wrong way.
main code
<html>
<head>// Some css link</head>
<body>
<!-- Menu -->
<div class="menu">
<ul class="list">
<li class="header">MAIN NAVIGATION</li>
<li class="active">
<a href="index.html">
<i class="material-icons">home</i>
<span>Home</span>
</a>
</li>
<li>
<a href="javascript:void(0);" onclick="setPage('child.jsp')">
<i class="material-icons">text_fields</i>
<span>Child page</span>
</a>
</li>
</ul>
</div>
<section class="content" id="main-content">
</section>
<!-- Jquery Core Js -->
<script src="plugins/jquery/jquery.min.js"></script>
<!--Bootstrap Core Js-->
<script src="plugins/bootstrap/js/bootstrap.js"></script>
<!-- Select Plugin Js -->
<script src="plugins/bootstrap-select/js/bootstrap-select.js"></script>
<script>
function setPage(page) {
$.ajax({
url: page,
}).done(function (data) {
$("#main-content").html(data);
// $.getScript("plugins/jquery/jquery.min.js");
// $.getScript("plugins/bootstrap/js/bootstrap.js");
// $.getScript("plugins/bootstrap-select/js/bootstrap-select.js");
// $.getScript("plugins/jquery-countto/jquery.countTo.js")
});
}
</script>
</body>
child code
<div class="info-box bg-pink hover-expand-effect">
<div class="icon">
<i class="material-icons">playlist_add_check</i>
</div>
<div class="content">
<div class="text">NEW TASKS</div>
<div class="number count-to" data-from="0" data-to="125" data-speed="15" data-fresh-interval="20"></div>
</div>
</div>
If I run without $.getScript, child page loaded into section but just content and css, js didn't work. If I run with $.getScript ( or put external script inside child page) ,child page loaded with js but jquery and bootstrapsjs go wrong with some unexpected animation.
Thanks guys so much.
Once you have jQuery on the page (and bootstrap) no need to add those back in. Getting content that does contain script will execute once it is on the page. Notice I put a small bit to add a class to the menu, and it executes when loaded.
Here I "fake" the ajax using a jQuery Deferred - jQuery .ajax() returns a deferred so it really can be a good fake for that.
Note I commented out the console.log() to make this example cleaner but you can uncomment to see them to see what is there at each step.
Note just for clarity jQuery
$.getScript(myurl);
is an alias for
$.ajax({
url: myurl,
dataType: "script",
success: success
});
SO, given that I added a fake ajax for an independent script also.
// this is fake ajax content
var ccode = '<div class="info-box bg-pink hover-expand-effect"><div class="icon"><i class="material-icons">playlist_add_check</i></div><div class="content"><div class="text">NEW TASKS</div><div class="number count-to" data-from="0" data-to="125" data-speed="15" data-fresh-interval="20"></div></div></div><scr';
ccode += 'ipt>$(".menu").addClass("showAction")</scr';
ccode += 'ipt>';
// this is fake script content
var fakeScript = '<scr' + 'ipt>$("#main-content").addClass("showScriptLoaded")</scr';
fakeScript += 'ipt>';
// this is fake script content
var otherFakeScript = '<scr' + 'ipt>console.log("proof"+$(".goodchild").text());$(".goodchild").append(" says Howdy!");</scr';
otherFakeScript += 'ipt>';
// just for the demo, think of this as ajax
function getFakeAjax(deferred) {
//console.log('in fake ajax');
deferred.then(function(data) {
//console.log('fake stuff then');
return data;
})
.done(function(data) {
//console.log('fake ajax data', data);
$("#main-content").html(data);
// kick off fakescript load
var def2 = $.Deferred(getFakeScript);
// pass that fake ajax object
def2.resolve(fakeScript);
})
.fail(function() {});
}
// just for the demo, think of this as getScript
function getFakeScript(deferred2) {
//console.log('in fake ajax');
deferred2.then(function(data) {
//console.log('fake stuff then');
return data;
})
.done(function(data) {
if (jQuery) {
// jQuery is loaded
alert("Yeah! well duh we just used it");
} else {
// jQuery is not loaded
alert("Doesn't Work");
}
//console.log('fake ajazx script', data);
$(data).appendTo("#main-content");
})
.fail(function() {});
}
function setPage(page) {
//console.log('setPage', page);
// I used the fake for this
// $.ajax({
// url: page,
// }).done(function(data) {
// $("#main-content").html(data);
// });
// call the fake the ajax
var def = $.Deferred(getFakeAjax);
// fax ajax done (second one)
def.done(function(data) {
// pretend our server is slow to load first script
// 4 seconds later kick off second fakescript load
setTimeout(function() {
var def2 = $.Deferred(getFakeScript);
// pass that fake ajax object
def2.resolve(otherFakeScript);
}, 4000);
})
// pass that fake ajax object
def.resolve(ccode);
}
.showAction {
border: solid lime 2px;
}
.showScriptLoaded {
border: solid red 2px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap-theme.css" rel="stylesheet" />
<body>
<div class="menu">
<ul class="list">
<li class="header">MAIN NAVIGATION</li>
<li class="active">
<a href="index.html">
<i class="material-icons">home</i>
<span>Home</span>
</a>
</li>
<li>
<a href="javascript:void(0);" onclick="setPage('child.jsp')">
<i class="material-icons">text_fields</i>
<span class="goodchild">Child page</span>
</a>
</li>
</ul>
</div>
<section class="content" id="main-content">get content here
</section>
</body>

Disable close dropdown after click href

I would like to keep my dropdown opened after a page load. For example if I click on an item(href) into an dropdown, I would like to keep the dropdown opened after the redirection.
I've seen that there is a method jquery named stopPropagation, but it seems that this does not work for me
HTML
<div class="sidenav">
<div class="item_sn">
Groups
</div>
<div class="item_list_body">
<div class="link_sidenav">
<a href="#" class="sub_item">
group 1
</a>
</div>
<div class="link_sidenav">
<a href="#" class="sub_item">
group 2
</a>
</div>
</div>
<div class="item_sn">
Users
</div>
<div class="item_list_body">
<div class="link_sidenav">
<a href="#" class="sub_item">
user 1
</a>
</div>
<div class="link_sidenav">
<a href="#" class="sub_item">
user 2
</a>
</div>
</div>
</div>
JQuery
<script>
$(document).ready(function () {
$('.item_list_body').hide();
$('.item_sn').on('click', function (event) {
var content = $(this).next('.item_list_body')
content.slideToggle();
$('.item_list_body').not(content).slideUp();
});
});
</script>
Solution 1 (not working) :
$(document).on('click', '.sub_item', function (e) {
$(this).parent('.link_sidenav').parent('.item_list_body').toggle();
});
you can use sessionStorage to store the state of the menu and then open the menu on page load by checking the state see below
EDIT
rather than using state of the menu we should save the index of the clicked menu as discussed in the comment so updated my answer
$(document).ready(function () {
//sessionStorage.removeItem('opened');
$('.item_list_body').hide();
if (sessionStorage.getItem('opened') !== null) {
$('.sidenav>div:eq(' + sessionStorage.getItem('opened') + ')').next('.item_list_body').show();
}
$('.item_sn').on('click', function (event) {
var content = $(this).next('.item_list_body');
var elem = $(this);
content.slideDown(0, function () {
sessionStorage.setItem('opened', elem.index());
});
$('.item_list_body').not(content).slideUp();
});
});
Hope it helps

Can someone explain to me why this isn't working? Ajax Load + scripts on html

The script won't load after the ajax has loaded the html content, why is this simply step not working. Here is what I got:
MakoStart.html: (The main page that will change)
<div class="makoislandintro" id="makochange">
<div class="makochoicesfirst">
<img src="../img/makoislandspecial/makobeach.jpg" class="makoislandbeach" id="makoislandbeach" alt="current">
<br>
</div>
</div>
<script>
document.getElementById("makoislandbeach").onclick = function() {
$('#makochange').load('makoisland.html');
};
</script>
This works, when i click the image with the id: makoislandbeach, the content changes to whats in makoisland.html.
Here is what is in makoisland.html:
<div class="makochoices">
<div id="rightside">
<img src="../img/makoislandspecial/waterstream.jpg" class="makoislandchoice" id="waterstream" alt="right choice">
</div>
<div id="leftside">
<img src="../img/makoislandspecial/islandside.jpg" class="makoislandchoice" id="islandside" alt="left choice">
</div>
</div>
<script>
document.getElementById("waterstream").onclick = function() {
$('#makochange').load('waterstream.html');
};
document.getElementById("islandside").onclick = function() {
$('#makochange').load('islandside.html');
};
</script>
Once the content changed, the script doesn't execute when i click the 2 new images that have replaced the old content. I have made a waterstream.html, it is the same as makoisland.html but with different images, but the script won't work after the first transition.
Take a look at this answer. As it said:
When calling .load() using a URL without a suffixed selector expression, the content is passed to .html() prior to scripts being removed. This executes the script blocks before they are discarded. If .load() is called with a selector expression appended to the URL, however, the scripts are stripped out prior to the DOM being updated, and thus are not executed.
Maybe you could do something like this. Instead of using load, use ajax. It's slightly different.
<div class="makoislandintro" id="makochange">
<div class="makochoicesfirst">
<img src="../img/makoislandspecial/makobeach.jpg" class="makoislandbeach" id="makoislandbeach" alt="current">
<br>
</div>
</div>
<script>
document.getElementById("makoislandbeach").onclick = function() {
$.ajax({
url: "makoisland.html",
context: document.body,
success: function(responseText) {
$("#makoislandbeach").html(responseText);
$("#makoislandbeach").find("script").each(function(i) {
eval($(this).text());
});
}
});
};
</script>

How can I avoid an undesired URL address change after a form submission?

I am working on a bootsrap3 template, which is Ajax based.
My index file has a leftside menu and a conent block middle of the page, every time I click on a subelement of this left menu, an Ajax laod will put the page content in this block(ajax-content).*
Any time I call any page, my URL normally looks something like this /index.php#page-one.php, except when the page contains form submission.
The Problem happens when I add an action attribute (acion="page-one.php") to my form tag.
After the form submission my URL turns to /page-one.php ;
consequently I get a white page containing the page-one.php elements whitout any CSS styling and of course no index-file's elements.
What is the correct and best way to come a cross this issue?
index.php:
<body>
<!--Start Container-->
<div id="main" class="container-fluid">
<div class="row">
<div id="sidebar-left" class="col-xs-2 col-sm-2">
<ul class="nav main-menu">
<li class="dropdown">
<a id="configuration" href="#" class="dropdown-toggle">
<i class="fa fa-gears"></i>
<span class="hidden-xs">Menu-element</span>
</a>
<ul class="dropdown-menu">
<li><a class="ajax-link" href="page-one.php">Menu-Subelement-one</a></li>
<li><a class="ajax-link" href="page-wo.php">Menu-Subelement-two</a></li>
</ul>
</li>
</ul> <!-- end of main-menu-->
</div>
<!--Start Content-->
<div id="content" class="col-xs-12 col-sm-10">
<div class="preloader">
<img src="img.gif" class="loader" alt="preloader"/>
</div>
<!--inside this div a short description/introduction(simple text inside a <p> tag) about the Menu-element will be shown-->
<div id="content-header"></div>
<!--inside this div the page content of the Menu-subelement will be shown-->
<div id="ajax-content"></div>
</div>
<!--End Content-->
</div>
</div>
<!--End Container-->
<script src="plugins/jquery/jquery-2.1.0.min.js"></script>
<script src="plugins/jquery-ui/jquery-ui.min.js"></script>
<script src="plugin/jquery.form.js"></script>
<script src="js/script.js"></script>
And here is my script.js:
//
// Function for load content from url and put in $('.ajax-content') block
//
function LoadAjaxContent(url){
$('.preloader').show();
$.ajax({
mimeType: 'text/html; charset=utf-8', // ! Need set mimeType only when run from local file
url: url,
type: 'GET',
success: function(data) {
$('#ajax-content').html(data);
$('.preloader').hide();
},
error: function (jqXHR, textStatus, errorThrown) {
alert(errorThrown);
},
dataType: "html",
async: false
});
}
//////////////////////////////////////////////////////
document.ready
//////////////////////////////////////////////////////
$(document).ready(function () {
var ajax_url = location.hash.replace(/^#/, '');
if (ajax_url.length < 1) {
ajax_url = 'home.php';
}
LoadAjaxContent(ajax_url);
$('.main-menu').on('click', 'a', function (e) {
var parents = $(this).parents('li');
var li = $(this).closest('li.dropdown');
var another_items = $('.main-menu li').not(parents);
another_items.find('a').removeClass('active');
another_items.find('a').removeClass('active-parent');
if ($(this).hasClass('dropdown-toggle') || $(this).closest('li').find('ul').length == 0) {
$(this).addClass('active-parent');
var current = $(this).next();
if (current.is(':visible')) {
li.find("ul.dropdown-menu").slideUp('fast');
li.find("ul.dropdown-menu a").removeClass('active')
}
else {
another_items.find("ul.dropdown-menu").slideUp('fast');
current.slideDown('fast');
}
}
else {
if (li.find('a.dropdown-toggle').hasClass('active-parent')) {
var pre = $(this).closest('ul.dropdown-menu');
pre.find("li.dropdown").not($(this).closest('li')).find('ul.dropdown-menu').slideUp('fast');
}
}
if ($(this).hasClass('active') == false) {
$(this).parents("ul.dropdown-menu").find('a').removeClass('active');
$(this).addClass('active')
}
if ($(this).hasClass('ajax-link')) {
e.preventDefault();
if ($(this).hasClass('add-full')) {
$('#content').addClass('full-content');
}
else {
$('#content').removeClass('full-content');
}
var url = $(this).attr('href');
window.location.hash = url;
LoadAjaxContent(url);
}
if ($(this).attr('href') == '#') {
e.preventDefault();
}
});
$('#formSubmit').ajaxForm();
});
page-one.php:
<!--some php code here-->
<form class="validateForm" id="formSubmit" action="page-one.php" method="get">
<div class="form-group">
<label>Username</label>
<input type="text" class="form-control" name="username" />
</div>
<div class="form-group">
<div class="col-sm-offset-5 col-sm-8">
<button type="submit" class="btn btn-primary btn-label-left">
<span><i class="fa fa-save"></i> Save</span>
</button>
</div>
</div>
</form>
Thanks!
I had the same issue to solve for the intranet I work on.
For me, the good way to do this is to avoid using submit method and use instead an input button with a js function to send the form data.
In my case, I did this:
<!-- At the top of my webpage -->
<script language='Javascript'>
function loadingAjax(div_id,user,date1,date2)
{
$("#"+div_id).html('<br><center><img src="images/loading.gif"><br><br><font color="#006699" face="arial" size="4"><b>Loading data<br>VPlease wait ...</b></font></center>');
$.ajax({
type: "POST",
url: "activities.php?USER="+user+"&DATE1="+date1+"&DATE2="+date2,
success: function(msg){
$("#"+div_id).html(msg);
}
});
}
</script>
<!-- And here is my form -->
<form id='date_form'>
<input type='text' id='user'><input type='text' id='date1'><input type='text' id='date2'>
<input type='button' onclick="loadingAjax('myDiv',document.getElementById('user').value,document.getElementById('date1').value,document.getElementById('date2').value);">
</form>
This allow to send your form in a separate DIV without having to show to everyone your URL.
MORE: you can even use this function to manage your left side menu selection so that your URL would stay '/index.php' all the time.
Hope this help
Regards
Nico
How do you want to submit the form, using ajax?
If you want to use ajax, you should cancel the default action like you do with your links using e.preventDefault();. Post the javascript that handles the form submit if you need help with that.
If you want to post to page-one.php without using ajax, you could add a header() redirect after the php code that processes the form to redirect to the page that you would like to show after the form gets submitted.
As you are loading content by ajax,
You can post content to page-one.php and redirect user to it's previous page. But it will be difficult manage and show error, success, notification message like form validation errors etc.
Another and I think best solution is to use ajax form submission

On .click() event to .get() page and replace .html() in jquery

I have div class="contentBlock" which is treated as the container for updating
<div class="contentBlock"></div>
I have a script that I wrote that doesnt work :c
$(document).ready(function(){
$('.postLink').on('click', function () {
$.get("page.php", function (data) {
$(".contentBlock").html(data);
});
});
});
I have a anchor html
<div class="box">
<a class="postLink" "href="#">
<h1 title="Light me up"></h1>
<div class="innerbox">
<figure><img src="http://cpsr-rspc.hc-sc.gc.ca/PR-RP/servlet/ShowImage?photoId=1789" /></figure>
<ul class="categorySelect">
<li class="print"></li>
<li class="video"></li>
<li class="web"></li>
</ul>
</div>
</a>
</div>
The page.php is just an img tag amd some lorem.
I've never worked with .get() I'm sure I'm using it incorrectly. Additionally, where would I add a transition for a loading .gif and a fadein when loaded?
<a class="postLink" "href="#">
Should be
<a class="postLink" href="#">
You had an extra quote.
$(document).ready(function(){
$(".postLink").on('click', function () {
// load in animation.gif here
$(".contentBlock").load("page.php", function() {
// end loading animation now
});
});
});
Using a load in jQuery is meant for exactly this purpose.
Here's the jQuery doc for load: http://api.jquery.com/load/

Categories