You all know how to build AJAX sites with those 300ms trigger for checking anchors (hash links) in URL and then loading proper page with AJAX. But, these anchor links are nothing to search engines =(
I've thought of making some kind of workaround. All JS code remains the same, but, this little thing (I'm with JQuery, sorry):
$('a').live("click",function(){
var lnk = $(this).attr("href");
document.location.hash = lnk;
return false;
})
And then, you replace your anchor links in the body with plain links, build corresponding plain pages (still containing all JS codes) for non-javascript users and search engines. For normal visitors you would have plain links converted into hashes on fly and AJAX content loaded immediately. For those who are trying to load certain pages found through search engine - they will, and after that visitor will continue to move around with ajax navigation... somehow (remember, those plain direct pages still contain JS code).
I just want to make sure my assumptions are right. Are they?
Update: Bad thing is that when user directly enters some internal page with for ex. /portfolio address, he would then continue to /portfolio#contacts or similar URLs that are not so pretty, but still working (I mean /portfolio#contacts would show contacts).
That doesn't seem to be a good approach mainly because you'll end up having that function being triggered for the click event of each and every link, even those where you do not want to use your AJAX approach for loading content, for instance links to other sites or to javascript:....
If you place all your AJAX-y links under the same class or use another attribute to distinguish them and then adapt the jQuery selector that you're using there, then it will work and it will be a good approach because not only will it be SEO-friendly, but it also provides graceful degradation, that is, your users will still be able to access the content even if they're running in an environment where no JavaScript is allowed.
Other than that, and if SEO is your only concern, you may search the web for what a sitemap.xml file is and how to use it. Wikipedia has an article on it that may be worth a reading.
Sounds very sound... only I would suggest the callback on your 300ms timer also be called inside the event you have above, that way you have an instant result when clicking a link(and also a user can goto the link in the address bar and get the same effect)
Hey mate, you probably want to check out jQuery Ajaxy. It gracefully upgrades websites into rich ajax applications, so your website still works for SEO and Javascript disabled users.
You can see this functionality in action in this upcoming website. Notice how all the links are the same as they would be if the website isn't a Ajax application - and they still work if you right click and go open in new window!
This functionality is explained in detail at it's demo page. You can also find other examples and usage instructions there to:
http://www.balupton.com/sandbox/jquery-ajaxy/demo/
Overall to use it is surprisingly simple and straightforward (especially considering what it allows you to do!), and the support is fantastic.
Related
I have few items in my navigation bar side and horizontal. Each item holds the link for different page. I have read few articles about href attributes. There is a lot of different opinions on what should be used especially in HTML5 since href is not required. I would like to hide the link if possible. One of the options is to use onClick function. Also there is big debate on if there should be javascript or # sign. For example:
Option 1
or Option 2
<a href="javascript:void(0);" onclick="someFunction(e)">
I was wondering if this is the best way to approach this. Also I saw few options where JQuery is involved but I'm not sure if that would be the best option. if anyone can help with this please let me know. I just want to use something that is well tested and will be a long term solution. Thanks in advance.
If you are actually linking to another HTML page with a URL... then use a link element and an href.
If you are in some framework and changing a route or view - or triggering some event - it's up to you. You can use buttons or any element or an <a> if you want, but you have a ensure to prevent the default behaviour of the link.
It sounds like your question is not between href or none - but between link or something else.
regular link
<a href='http://sheriffderek.consulting' target='sheriff'>link</a>
A fallback link for non-javascript sites? (not likely in 2017 unless you are a public library or something)...
<a href='http://sheriffderek.consulting' onclick='someFunction(e)'>js view trigger with fallback link</a>
another element
<button onclick="someFunction(e)">button</button>
Also - it depends on the framework. I believe Angular just says to use a link but leave off the href.
Nowadays, I see most of the developers prefer "#" to "javascript:".
If I had to use onclick, I'd personally do it like this:
Link
Another example:
Link
<script>
someFunction = function(event) {
event.preventDefault();
// do the work
}
</script>
To answer one of your concerns, showing links in the page shouldn't be a security concern. Each server request must be protected against unauthorized calls, URL obfuscation will not help almost at all.
The method you use to redirect the page (or invoke an event) really depends on what you are trying to achieve from the action and the overall user experience. There are cases where an href is more appropriate:
An image that is also a link
A word or phrase that is used as a link
An actual link you want displayed to the user
An onClick event of a button can be coded to achieve the same effect but with a different route. Perhaps the code will be more efficient or the User Experience is improved with a button click event than just an href.
The two main things to keep in mind are the user experience and design and then the security of the page. Always ensure that any link/redirection will never compromise the security of the page. This could potentially determine the method you need to use.
For additional info, you can start by reading the following link and then continuing through the rest of the stack exchange UX section of the site:
I hope it helps a little.
Action in href or onClick event?
Imagine you have a simple, single-page application - regardless of whether it was written using Backbone, Angular, Ember or anything else.
How can you tell a screen reader that we've changed 'page' when a route is followed?
In a classic application, when I navigate from /index.html to /about.html the screen reader obviously detects the page change, and re-reads as you'd expect.
In my Backbone application though, when I follow a route I cannot work out how to trigger a 're-read'. I've tried triggering a focus event which I'd seen somewhere, but that doesn't seem to work.
Note: I'm currently testing with NVDA/Chrome.
Overall, you should not need to trigger a 're-read', and depending on your UI that might not be a good thing anyway.
My experience has been with angular.js (as an accessibility person rather than the developer), and our overall approach was to manage the focus rather than trigger a re-read. (We do extensive accessibility testing.)
The key thing from a UI point of view (primarily for screen reader users) is that selecting a link (e.g. about.html) should take you somewhere.
In this case the appropriate place to put the focus would be the top of the content area of the about 'page', hopefully an <h1>.
In order for that to work the target element should be focusable via a script, so probably needs tabindex unless it is a link or form control:
<h1 id="test" tabindex="-1">
The -1 means it is not in the default tab order, but is focusable via a script. See more at WAI-ARIA authoring practices.
Then at the end of the function that loads the new content, including the tabindex attribute, add something like:
$('#test').attr('tabindex', '-1').css('outline', 'none');
$('#test').focus();
When adding tabindex dynamically it is best to do so in a line before the focus() function otherwise it may not work (I remember that from testing with JAWS).
To test this I would use either:
NVDA & Firefox, Windows
Jaws & IE, Windows
It is also good to test with VoiceOver on Safari/OSX, but that works differently and may not hit the same issues as a windows based screen reader.
You will hit a lot of issues with Chrome/NVDA as that is not supported very well, and end-users are very unlikely to use that. IE is ok with NVDA, but Firefox is best.
Overall, it is worth getting to know the WAI-ARIA authoring practices, particularly Using ARIA in HTML. Even though you are using a JS app, the browser (and therefore screen reader) is interpreting the resulting HTML so that advice is still relevant.
Lastly, if you are updating page content without the user pressing space/enter to activate something, you might find that JAWS/NVDA do not know about the new content as their 'virtual buffer' has not updated. In that case, you might need to add a JS shim to make them update, but only do that if you run into problems in testing, it should not be a global patch.
Taking the answer from #AlastairC, and the comments below it. I've taken this a bit further now and am going with this as my solution going forward:
My go-forward solution
I found that just reading out the first heading wasn't really that useful. Especially if the last page you were on was a loading sequence. You can hear that there something new has been focused, but it's certainly not clear that this forms the part of a whole now page.
Add some useful, descriptive text to the page
As such I now have a single paragraph at the top of my page layout template. This includes a screen-reader friendly message, along with a very rough overview of what the page.
<p class="screenreader-summary" tabindex="-1">
The <strong>Dashboard</strong> page is now on-screen.
It contains several widgets for summarizing your data.
</p>
Note that the tabindex value allows us to focus this element with JavaScript. You might not want to use a p element for this, you can use anything you like really.
Hide it off-screen (optional, only required if it would break your design/readability)
This is then coupled with CSS to move this element off-screen:
.screenreader-summary {
position: absolute;
left:-10000px;
top:auto;
width:1px;
height:1px;
overflow:hidden;
outline: none; /* Important, don't show an outline on-focus */
}
Focus this element, when a new page is shown on-screen
Finally, in the JavaScript code that shows your page on screen (e.g. in MarionetteJS using onShow or the show event):
$yourViewEl.find('.screenreader-summary').focus();
The result
I'm a sighted person, so take what I say with a pinch of salt - however I found that reading out a short description is so much more useful.
For angular the url changes, If someone REALLY needs to reread everything, (like me because of requirements), what did the trick for us was this:
$(window).on('hashchange', function () {
location.reload();
});
and we just added extra code to handle pages like "success" were no reloads are supposed to happen.
this simulates the actual page loading, and screen readers will read it normally like a page change.
kind of defeats the purpose of angular in a way, but this will help people like me who already have the application, and want a quick fix.
I implemented infinite scroll like so:
new_page_value = 1;
$(window).scroll(function() {
if($(window).scrollTop() >= $(document).height() - $(window).height() - 200) {
new_page_value = parseInt(new_page_value) + 1;
get_page(new_page_value);
}
});
When the user almost reaches the bottom of the page (200px left) the function get_page() is called. This contains an ajax call that gets all the contents of the new page and appends it to the <body> of the document.
Now I just realized if my site gets big and instead of having 10 small pages I have a gazillion giant pages then the user's browser might crash if they are persistent enough to keep infinite scrolling for long time.
Would this be a possible solution to this problem:
I will keep appending the new pages to the document <body> until the 10th page, after that I will be replacing the <body> content entirely instead of appending. So using html() rather than append().
I just don't know if this will actually work to prevent crashes. Will .html() clear the "memory" of prior html that was brought in via ajax?
I really think this is a common issue for many sites with AJAX list content. So let's take an example at some of the most popular ( think of scale = experience ) websites and their solutions :
Google Images
If you check out images.google.com and you search for whatever, for e.g. "guiness", you will see a page full of results (actually the images are ajax loaded, not the html-code, so the page is with fixed height) and when you scroll at the bottom there is a button "Show more results". This might be solution one of your problem, but is it really necessary to place a button at the bottom after, for e.g. the 10-th page? I really think it is generally a good solution for page usability and memory leaks, but it is really not a necessary option as we can see in :
Facebook
Facebook Newsfeed is another story. There is a button "Show more posts", but I really don't know when exactly it is displayed rather than loading the next page of posts. It happened to me once to load 10-15 pages of posts, only by scrolling. And you know Facebook posts include videos, photos, AJAX comments and a lot of more Javascript fancy stuff, which take a lot of memory. I think they've managed to do this after a lot of research, how much of the users scroll to the bottom.
Youtube
Youtube has "Load more videos" at every page, so the solution is basically similar to Google, except that Google renders the whole html of the page and on scrolling just loads the images.
Twitter
Twitter supports infinite scrolling. Yep, they do it may be because tweet is 140 characters and they don't need to worry about memory so much. After all who is willing to read more than 1000 pages of tweets at one page load. So they don't have a button for "load more" and they don't need one.
So there are two solutions :
Use infinite scrolling ( you should consider how much content you load and how rich it is )
Use button : "Load More"
Most of all, you should not delete already loaded content of a list.
Nowadays everything is Javascript and Javascript has garbage collection, so it is very hard to unload the DOM ( if it has Javascript, not plain text ) and manage to remove the Garbage from Javascript. Which means that you won't free the whole allocated memory of the unloaded content from the browser.
Also think about of your requests, why would you need to load again something, that you have already loaded at first place. It costs another server request, meaning another database request and so on.
I have worked with this before and here are some of my thoughts:
a) If you are appending data to the memory page(s) at a time then it is not an issue, some browsers might not respond well but most of the lastest browsers will render without any problem so long as there is enough memory on the target machine, you could probably see how the ram usage increases as you append pages. Use chrome for this as each page is a separate process and it has an inbuilt task manager
b) regarding usage of html(), it indeed removes the markup but it does so at a heavy cost as it tries to take care of special conditions and has an overhead and accesses all the controls nested within the container that you are replacing (not sure about the last pat), but it has a cost. A simpler way to clear the DOM would be to use the innerHTML property and set it to empty, jquery does this but it is at a later point in the html() api. open up the api and look at the method.
using innerHTML
$("<selector>")[0].innerHTML=""
Also deletion of pages sounds weird to me as a user, what if I want to go back to the initial comments and please dont think about making it an infinite scroller too.. I have tried and given up after the number of bugs raised but we had a genuine use case for it and I had to stick a button up there, but this wasnt when the user scrolled away from the first page, this is when the user landed on a 3rd page but now needs to see the results above it.
Hope that answers your question and btw infinte scrolling is your friend use it, dont over engineer a case which will probably only be tested by your QA team. Its better to spend your effort somewhere else.
Yes it will, if i may suggest an idea after let's say 5 pages just delete the first page and append the new one instead of deleted all of the previous pages. good luck :)
I have a page with several reports that are produced via ajax calls. I am prototype.js framework on this page for some of the display functions.
The links for each report have anchors/tags like #Report1, #Report2 etc, which are hrefs with onClick functions that do lots of work to create the report via javascript.
I would like to make it so if a user bookmarks a page with a link or navigates directly with a anchor/link in the url for my page to load the report.
So if the user goes to : http://mysite/myPage.jsp#Report2 it should load the page and go to the 2nd report.
Is there anyway in my pageload I can look at the anchor/link and perform the onlcick for that anchor? I was thinking I could create a big case/if statement to figure out what to do, but maybe there was an easier way.
It all depends on how you're Ajax calls are structured really. I do something similar for opening the correct tab within a tab navigation. The code would start off like this, if you let me see how your Ajax events are hooked up then i should be able to show you the rest.
document.observe("dom:loaded", function() {
if(window.location.hash){
var report = window.location.hash.replace("#","");
}
});
EDIT
Looking at your code you would be much better off (imv) switching to an unobtrusive method where you attach events to your elements e.g.
$('ele').observe('click',doStuff.bindAsEventListener($('ele')));
This would enable you to more easily connect the same functionality to a click or a pageload but is also better practice anyway and would prevent code duplication etc. Obviously this is missing large chunks but hopefully you get what i mean
I run into a common problem when trying to do AJAX development. Where possible, I like to try and just update data in an existing layout, and not the layout itself. For example, take the div below:
<div id="content-5">Here is some content</div>
I would get the updated value for content-5 from the server and just replace the contents of content-5 with the value. This makes a lot of sense for simple data replacements where the value is always going to be displayed in its pure form.
Sometimes the content is more complicated, and I have to actually get more than just raw data... maybe there is some logic to determine how a value is displayed and perhaps the style needs to be different depending on the data inside. In that case, I generally produce the HTML on the server side and inject the HTML into the element instead of just raw data.
Example: A status field from the controller comes back as "complete", but from the design doc, "complete" is supposed to show the user the text "Available" and it needs to be styled in a way different from other statuses.
Doing this in Javascript would require some in-depth view knowledge that the template layer probably already handles. The end result would be the same (code snippet below), but the difference is that there could possibly be some code duplication and a far more complicated Javascript layer.
<div id="content-5"><span class="success">Available</span></div>
Without fail, the requirement comes up that the system will need to handle "new" contents as well. The easiest solution to implement is to just get all of the content's at the same time so that I do not need to handle the extra complexity of injecting a new element instead of just replacing existing content.
So, I create a new template, wrap the contents in another element with an ID, and bulk replace all of the content divs at the same time any time there is a change.
<div id="allContent">
<div id="content-1">Some content A</div>
<div id="content-2">Some content B</div>
<div id="content-3">Some content C</div>
<div id="content-4">Some content D</div>
<div id="content-5">Some content E</div>
</div>
At some point, I have to wonder: Where is the line? At some point it feels like I'll eventually just be replacing the whole page with an AJAX request. Would this really be a problem?
I realize this may be pretty subjective, but what are some good strategies for determining to which level you should be replacing content with AJAX? Replacing just the data seems to be my preferred method when possible as it makes the AJAX controllers very simple. Replacing larger chunks of HTML from a template seems to be the easiest for handling more complicating layout and design issues and also feels like it could be more easily maintained. Are there other options I have not considered?
I expect there will be some discussion about manipulating the DOM programatically, but I personally really dislike this. The code ends up looking pretty horrible and really starts to integrate too much layout and design into the JS layer for my liking. Since I generally work with template libraries of some sort (whether raw PHP, PHP templates like Smarty or JSP in Java) it seems to make more sense to leave as much visual design there as possible.
EDIT
Based on the first few answers, it seems like this is being read as trying to keep the user on the same page but navigating around around the site or otherwise changing the page in a radical way with each update. The question is more about how to determine where the layout work for AJAX calls should happen and whether or not it is an acceptable practice to change large chunks of code with an AJAX request, knowing that replacement code may look nearly identical to what had been there before.
I think the most important requirement is the refresh requirement. If after several AJAX updates I hit refresh, the page I was just looking at should be the page that arrives. If the page reverts to a previous state for any reason then the URL is wrong. If for any reason your AJAX data is going to make the URL in the browser invalid then you should not be using AJAX to fetch that data.
There are exceptions, of course for data the is even newer than the last AJAX request. But that's obviously not what I'm talking about. A live chat screen could receive an update between the last AJAX request and the refresh. No big deal. I'm talking about the logical content and the URL describing it should always be in sync.
Complete personal opinion ex nihil, my rule of thumb is to change no more than 1 "panel" unit or 33% of the page whichever is less.
The basis for this is that the user should be able to clearly recognise the previous page state is related to the new state - how would you feel if you were suddenly teleported into the building to your right? Be gentle with your poor user.
There are also serious technical questions about the benefits of moving and inserting basically a page worth of data, which I think is a bit of an AJAX anti-pattern. What benefit does AJAX provide if you're going to do that?
Your specific question seems dependant on the supposition that the response coming back from your AJAX request isn't "just" data. This feels wrong to me from a separation of concerns point of view: I would expect a page to have all the layout information it requires already, the AJAX response itself to provide nothing more than dumb data/markup, and the JS event handler which created the request to sew the two together, MVC style. In that respect I think, yes, you're doing too much.
(by panel, I mean one logical design element - a menu, a ribbon, an item metadata panel, etc..)
edit: now that I think about it, I think SO's user profile page breaks my rule of thumb with those tab clicks
Depending on whether you want people to be able to to link to / bookmark etc the current page, you might want to navigate the user's browser.
This isn't a concern for some apps like GMail etc, and they won't ever refresh the page.
For myself, I tend to think it's a good practice to navigate the browser when navigating to a logically different place. eg. a person's profile vs. a list of their messages.
Sorry if this is vague, it's rather subjective :-)
A good guideline for something like this is to ask yourself, "Is this dynamic application 'content', or is it content-content?" Your use case sounds like application content that will change with each user. This is probably the best place for Ajax, but with everything, it's always nice not to just have one hammer. You don't want to do too much on one page. For instance, if one part breaks, the entire thing might, thereby frustrating the user.
Anywhere you're looking at actual page content or anything where the information is static, I strongly suggest avoiding the use of JavaScript, as it runs the risk of being invisible to search engines. Make sure anything linking to information like this is crawlable. The first step towards this is dynamic generation on the server side rather than browser side.
If you're using Smarty templates to produce a page, just fragment a template into various meaningful sections - news.tpl, email.tpl, weather.tpl - and have a master.tpl producing the structure of the page and calling child templates.
Then, if you're for example using an AJAX call triggered by a timeout to refresh the news, you can just call the server, cram the necessary data into news.tpl, and return the results into the news div you set up with master.tpl. This way your news layout is always following the pattern of news.tpl. (If you used JavaScript to manipulate formatting bits or set up event handling on document load, you'll need to attach that post-processing to fire after the AJAX call.)
You haven't really gotten specific about the types of things you're trying to replace here, and my initial reaction is that, if a single event is triggering multiple sections of the page to update at once, that's a sign that maybe you should be coallating those sections into a single display.
How much formatting gets done on the server end versus how much gets done on the client end with JavaScript? I'd say server-side formatting if possible, that way you have code that reflects discussions you've made about display layout and logic. Client-side formatting can be used for more interface-based issues - sorting rows in a table and alternating row colors with :odd and :even selectors, showing and hiding divs to create a "tabbed display" without hitting the server since the data won't change just from selecting a new tab, that sort of thing.
Finally, AJAX is one-way. If your web page is a view on a database, this isn't as much of a problem, but using AJAX manipulation to take the place of normal navigation is a terrible idea.
If you were habitually replacing the entire contents of a page using AJAX calls, I would agree that you have a problem. However, it appears to me that you are attempting to carefully think through the implications of your design and attempting, where possible, to avoid what annakata has called this "AJAX anti-pattern."
My rule is a bit simpler: as long as a substantial amount of context (e.g. menu on the left, header, various controls, page title, etc.) remains on a page, I am Ok with replacing almost anything with an AJAX call. That being said, I've never struggled with a page that has as much AJAX-generated code as you are.
I do have one question though: isn't it possible to encode state so that you can just replace some of the Divs in your example rather than all of them? If not, have you thought about doing so?