load dynamic website pages with out page refresh - javascript

I have created a shell like html page which loads other pages into div on link clicks.The issue i am having is to rewrite the url with out a page re-load.
Also checking for hash events to add and rewrite them.
Firstly the links;
<a href = "myexample" onclick="menuPage(this);return false;" >
//result www.mywebsite.com/myexample
function loadPage(){
var tempURL = window.location.hash.substring(1);
$(".nav li").removeClass("active");
$("a[data-role="+tempURL+"]").parent().addClass('active');
if(!tempURL){
$('#pages').animate({opacity: '0.0'},function(){
$("a[data-role='Home']").parent().addClass('active');
$.get('Home/index.html', function(response){
$('#pages').html(response);
scrollOnTop();
$('#pages').animate({opacity: '1.0'});
})
});
}else{
$('#pages').animate({opacity: '0.0'},function(){
jQuery.post(tempURL, function(response){
$('#pages').html(response);
ga('send',{ // google
'hitType': 'pageview',
'title': 'mywebsite',
'location':'http://www.mywebsite.com/'+ tempURL,
'page': '/'+ tempURL
});
document.title = $(response).filter('title').text();
scrollOnTop();
$('#pages').animate({opacity: '1.0'});
tempURL = "";
})
});
}
}
$(window).on("hashchange", function () {
loadPage();
});
function menuPage(obj){
menu = "#" + obj.getAttribute("href");
window.location = menu;
return false;
}
function scrollOnTop(){
jQuery("html, body").scrollTop(0);
}
//The above works 100% expected:**
So lets say i click link or enter the url www.myexample.com/#item1 this will take me to that page all good but lets say i click or type in www.myexample.com/item1 with out hash this will take to the page but all broken as there is a folder named "item1" with an index file in it...
Essentially i would like to add hash into the url:
Once i add to the .htaccess file anything along the lines of : RewriteRule
^([A-Za-z0-9-]+)/?$ # [NC,NE,R=301]
or variations.
This just messes up.

I'm finding it a bit difficult to understand what your code is doing. A jsfiddle or equivalent might help.
It looks like loadPage is only executed when the url hash changes? And an anchor with href of www.myexample.com/item1 doesn't result in a hash change.
My guess is you want to bind a click event to your anchors, so you can intercept the click and run your own custom code (load page snippet without refresh), instead of the browser default behaviour of requesting the url (www.myexample.com/item1) from the server.
Something like:
$('a').click(function() {
/* Your code here. E.g... */
$('#pages').animate({opacity: '0.0'},function(){
$("a[data-role='Home']").parent().addClass('active');
$.get('Home/index.html', function(response){
$('#pages').html(response);
scrollOnTop();
$('#pages').animate({opacity: '1.0'});
})
});
// Returning false prevents browser default behaviour
// Some people don't like it - see http://fuelyourcoding.com/jquery-events-stop-misusing-return-false/
return false;
});

Related

Making a single page application with ajax and get a 404 error when the page is reloaded

Basically, I'm coding a personal website and have made a single page application with ajax so content is added to the page between the header and footer when a page in the navigation bar is clicked. I had to manually code the push state and pop state in order to get the back and forward arrows working, which they do. However, the only issue left is that when I reload the page, I get an entry not found error.
I'm very new to web dev and javascript so some of my code is a little messy. I know the reload issue has to do with the added page URL not actually existing on the server.
Here are the relevant pieces of my code:
HTML:
<nav>
<ul class='nav-bar'>
<li class='nav-item'><a id='writing'>Writing</a></li>
<li class='nav-item'><a id='editing'>Editing</a></li>
<li class='nav-item'><a id='about'>About</a></li>
<li class='nav-item'><a id='contact'>Contact</a></li>
</ul>
</nav>
Javascript
//change page on nav click
$('.nav-bar li a').on('click', function(e) {
e.preventDefault();
var page = $(this).attr('id');
var file = page + '.html';
var origin = window.location.origin;
//nav color change for current page
removeActiveLinks();
$(this).parent().addClass("active");
$.ajax({
type: 'GET',
url: origin,
dataType: 'html',
success: function(response) {
$('#content').load(file);
},
error: function(error) {
console.log('There was an error', error);
}
});
window.history.pushState(file, null, '/' + page);
});
//nav for home page
$('#home').on('click', function(e) {
e.preventDefault();
removeActiveLinks();
$('#content').load('home.html')
window.history.pushState('index.html', null, '/');
});
//ensure page back functionality
window.addEventListener('popstate', function(event) {
var prevState = event.state;
$('#content').load(prevState);
removeActiveLinks();
var page_id = '#' + prevState.split('.')[0];
$(page_id).parent().addClass('active');
});
Here's what the error looks like
I would suggest something simpler, using simple load() (shorthand for ajax) and a the state of the history directly.
Not tested, but should work fine.
// Initial page load
$(document).ready(function(){
$("#content").load("home.html");
})
// Change page on nav click
$(".nav-bar li a, #home").on("click", function (e) {
e.preventDefault();
var file = this.id + ".html";
//nav color change for current page
$(".active").removeClass("active");
if(this.id != "home"){
$("#"+this.id).parent().addClass("active");
}
$("#content").load(file);
window.history.pushState(file, null, "/");
});
// Ensure page back functionality
window.addEventListener("popstate", function (event) {
var prevState = event.state;
$("#content").load(prevState);
var page_id = "#" + prevState.split(".")[0];
$(".active").removeClass("active");
if(page_id != "#home"){
$(page_id).parent().addClass("active");
}
});
But there is no /writing in the adress bar with this solution. If you insist on it, you will have to dive in more complex route settings on the server.

changing the url without loading a new page

For my single page website, I have an index of projects. If a project is clicked it opens up a slideshow on the same page. So basically, I only have one URL, and if anyone wants to link to a specific project, they can't.
I'm trying to make it so that if I click on a project, it changes the URL. And so that URL can be used to get to my website with that project opened.
Here is a link to what I have so far.
For reference, I'm trying to achieve something that is found on this site.
I found some good suggestions here, but what happens when I use something like this (below), a new URL is created but it doesn't open up the project if I renter that URL into the browser.
<a href="#" id='click'>Click to change url to bar.html</a>
<script type="text/javascript">
var stateObj = { foo: "bar" };
function change_my_url()
{
history.pushState(stateObj, "page 2", "bar.html");
}
var link = document.getElementById('click');
link.addEventListener('click', change_my_url, false);
</script>
function processAjaxData(response, urlPath){
document.getElementById("content").innerHTML = response.html;
document.title = response.pageTitle;
window.history.pushState({"html":response.html,"pageTitle":response.pageTitle},"", urlPath);
}
You can use `window.onpopstate to sense the back/forward button navigation
window.onpopstate = function(e){
if(e.state){
document.getElementById("content").innerHTML = e.state.html;
document.title = e.state.pageTitle;
}
};
I would appreciate someone with more skill to check this over for me
You can use id at elements which has slideshow as unique URL; at .ready() start animation of element where id matches .location.hash
$().ready(function() {
// `location.hash`: `id`: `#slideshow1` of element linked to
// from, e.g., `http://example.com/#slideshow1`
var currentSlideshow = $(location.hash);
// do slideshow stuff at `currentSlideshow`: `#slideshow1` element
})
using a hash might work best in this case
$(document).ready(function({
//loading a page
var project = window.location.hash
yourProjectLoadFunction(project);
//setting a url
$('.number').click(function(e){
$this = $(this);
window.location.hash = $this.attr('id');
});
});

Load AJAX content in modal and change URL

My current setup is on click a modal popups with data from the ajax action which has been passed an id, I want the URL to change on click.
But I also want it so that if you directly accessed the URL it would load say index with the modal preloaded.
Very much like https://www.myunidays.com/perks/view/shoeaholics/online it loads the URL with the content in a model then if you click/close the modal the URL changes to the index page.
I have seen related questions about changing URL on click but couldn't find anything to do with accessing URL directly (is their a rule I can add to my .htaccess).
(Any code/direction is appreciated)
Create a partial view (so that layout isnt rendered twice) and add the action to controller
public function actionViewmodal($id)
{
return $this->renderPartial('_view', array('model' => $this->findModel($id)));
}
Then within my index I did the following
$(document).ready(function() {
$('a').click(function() {
pageurl = $(this).attr('href');
var Id = jQuery(this).attr('id');
$.ajax({
type: 'POST',
data: {
'modal_id' : Id,
},
url : 'http://localhost:8888/directory/viewmodal?id='+Id,
success: function(response) {
if(response) {
$('.modal_some_wrapper').html(response);
$('#modal_'+Id).modal('show');
$(document).on('hidden.bs.modal', modal_id, function (event) {
$(this).remove();
});
} else {
alert('Error');
}
}
});
//to change the browser URL to the given link location
if(pageurl!=window.location){
window.history.pushState({path:pageurl},'',pageurl);
}
//stop refreshing to the page given in
return false;
});
});
Could someone example how myunidays website works with modal and URL change?

How to retain Javascript state on page change

I have an accordion style navigation list set up so that when categories are clicked it opens up to show sub-categories that link to pages.
What I would like to do is have the accordion navigation list keep it's open or closed state when the new page opens.
I've gathered that cookies work to retain the state on refresh, but how do I retain the state when a different page is visited? All the pages have the same accordion navigation list.
Try Web Storage. Store the state of the tabs on page unload, restore the state on the page load event.
I found a solution, it uses the accordian plug-in found here, http://www.i-marco.nl/weblog/archive/2010/02/27/yup_yet_another_jquery_accordi and the jquery cookie.js plug-in
I added id's to the header anchor tages in the HTNL mark-up like so,
<li>
<a id="m1" class="label" href="#">Sound/Audio Systems</a>
<ul class="acitem">
<li>PA Systems</li>
<li>Loudspeakers</li>
<li>Microphones </li>
<li>DJ Equipment</li>
<li>Sound Processing Equipment</li>
</ul>
</li>
And modified the accordian.js code, I added the lines beginning with $.cookie, and the If statement in the document.ready funciton.
jQuery.fn.initMenu = function() {
return this.each(function(){
var theMenu = $(this).get(0);
$('.acitem', this).hide();
$('li.expand > .acitem', this).show();
$('li.expand > .acitem', this).prev().addClass('active'),
currentID = "";
$('li a', this).click(
function(e) {
e.stopImmediatePropagation();
var theElement = $(this).next();
var parent = this.parentNode.parentNode;
if($(parent).hasClass('noaccordion')) {
if(theElement[0] === undefined) {
window.location.href = this.href;
}
$(theElement).slideToggle('normal', function() {
if ($(this).is(':visible')) {
$(this).prev().addClass('active');
currentID = $(this).prev().attr('id');
$.cookie('menustate', currentID, {expires: 2, path: '/'});
}
else {
$(this).prev().removeClass('active');
$.cookie('menustate', null, {expires: 2, path: '/'});
}
});
return false;
}
else {
if(theElement.hasClass('acitem') && theElement.is(':visible')) {
if($(parent).hasClass('collapsible')) {
$('.acitem:visible', parent).first().slideUp('normal',
function() {
$(this).prev().removeClass('active');
$.cookie('menustate', null, {expires: 2, path: '/'});
}
);
return false;
}
return false;
}
if(theElement.hasClass('acitem') && !theElement.is(':visible')) {
$('.acitem:visible', parent).first().slideUp('normal', function() {
$(this).prev().removeClass('active');
$.cookie('menustate', null, {expires: 2, path: '/'});
});
theElement.slideDown('normal', function() {
$(this).prev().addClass('active');
currentID = $(this).prev().attr('id');
$.cookie('menustate', currentID, {expires: 2, path: '/'});
});
return false;
}
}
}
);
});
};
$(document).ready(function() {
$('.menu').initMenu();$('#side-navigation_frame').show();
if ($.cookie('menustate')) {
var anchor = "",
elementID = $.cookie('menustate');
anchor = document.getElementById(elementID);
$(anchor).addClass('active');
$(anchor).next().show();
}
});
It works nicely, not bad for a beginner, thanks for all the advise.
Rob Fenwick
Cookies "retain state" across the full path and domain for which they are specified. So if you can get them to work for just one page, you should have them work automatically on all pages of your site.
You can still use cookies, you just have to make sure they're not specific to the one page. For example:
document.cookie = 'openitem=5; expires=somedate; path=/';
will be accessible to all pages on the site. More about cookies.
Ok so I took a look at the library you are using, it's a decent library and all but you might find it easier to find solutions to your problems if you use a more standard library like jQuery UI, it has an accordion control http://jqueryui.com/demos/accordion/ and like I mentioned there are so many people using it that the answer to most problems can be found.
But like I mentioned I did take a look at your library. As others have mentioned you would use a cookie to store the value. This library supports 'pre expanding' a particular section of the accordian, to do that you would add the expand class to the element. You can either do that server side or you can do it using JavaScript before initMenu() is called.
The other less elegant option is to trigger the click event on the anchor tag after the call to initMenu. Finally you can use jQuery's show() to show expand the section without animation.
The first thing you have to do is find out which section was clicked on, then you would store that sections name in a cookie. On page load you would get that value and expand the appropriate according section. This is what the code should kinda look like - note this is psuedo code and you have fill in the appropriate parts.
$(function() {
$(".menu.collapsible .label").click(function() {
var accordianSection = $(this).text();
rememberSection(accordianSection);
});
var section = recallSection();
if(section !== undefined) {
expandSection(section);
}
});
The expandSection function can look something like this:
var sectionLink = $(".menu.collapsible .label").filter(function() {
return $(this).text() == section;
});
sectionLink.trigger('click');

Get specific page from URL and get the data with AJAX

window.onload= function(){
var page = window.location.hash;
if(window.location.hash != ""){
page = page.replace('#page:', '');
getdata('src/'.page);
}
}
After the window loads, i want the page to look in the URL, see if there is a # is set, and if so, i want to grab the page and display it inside a DIV. So for example, a link would be link. So when somenone clicks on the link, the page thinks and grabs the data from contact.php, and puts it inside the div. But now, this isn't working. No errors, no warnings, no nothing. Help please? Thanks!
Edit: Getdata:
function getdata(file){
openloading(); // loading message
$('#content').fadeOut('slow', function () { // Content is the div where all the content must be in
$.get(file, function(data) {
$('#content').html(data);
$('#content').fadeIn('slow');
})
})
updateusersonline();
}
And updateusersonline() directly too:
function updateusersonline(){
$.get('src/usersonline.php', function(data3) {
$('#usersonline').html(data3);
})
getdata('src/'.page); should be getdata('src/' + page);

Categories