Skip to content
trezmann edited this page Aug 27, 2013 · 15 revisions

jQuery is one of the standard JavaScript Ajax Libraries. It ships with Ruby on Rails and will be used by us for various things including AJAX and cleaning up usability and user interfaces. There is a powerfull API Documentation of jQuery available: http://api.jquery.com/

AJAX

AutoCompletion

http://www.jqueryrain.com/2012/03/35-best-ajax-jquery-autocomplete-tutorial-plugin-with-examples/

I'll try to show some of the functionality of AJAX by the means of our autocompletion. First of all I show the code as a whole, then I'll pick out the AJAX part and describe / explain it in greater detail.

 
<html lang="en">

<head>
  <meta charset="utf-8" />
  <title>jQuery UI Autocomplete - Default functionality</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>
<!--  <link rel="stylesheet" href="/resources/demos/style.css" />-->
	<script>
  	$(function() {
	    	$( "#tags" ).autocomplete({
		//http://jqueryui.com/autocomplete/#remote-jsonp
      		source: function( request, response ) {
        		$.ajax({
				url: "/autocompleteServer-0.0.1-SNAPSHOT/suggest",
				dataType: "json", 
				data: 	{
			        	numItems: 7,
						indexName: "generalindex",
			        	term: request.term
					},
		        	success: function( data ){
				    $.each(data, function(key, val) {
					if (key === "suggestionList"){
					    response( val );
					}
					if (key === 
				    });

				}
        		});
      		},
		//http://codeblogging.net/blogs/1/15/
		minLength: 1})
		.data("ui-autocomplete")._renderItem = 
			function(ul, item) {
				var inner_html = '<a><div class = "list_item_container"><div><img src="'+item.image+'"></div>' + item.suggestion  + item.key + '</div></a>';
				return $("<li></li>").data("item.autocomplete", item).append(inner_html).appendTo(ul);				 
			}		
  	});
  

	</script>
</head>


<body> 
<div class="ui-widget">
  <label for="tags">Suche: </label>
  <input id="tags" />
</div>
</body>


</html>

So our Ajax-request is in our autocompletion, it is the part where we define the origin for our search results. When you override the "source" part of our autocompletion, and want to use an external source, e.g. a server as ours, you can use a function for that, with 2 parameters, (request, response) Here comes our AJAX into play, our asynchronous request, while the user is typing a search term.

###Newsfeed Widget

We tried to get a newsfeed widget tutorial to work with a JSON input instead of a xml: http://net.tutsplus.com/tutorials/javascript-ajax/how-to-build-a-widget-to-display-your-buzzing/

The widget was a bit hard to understand, thanks to some weird code that seemed to do nothing at all. Thanks to Rene we streamlined it down to its core and now I try to explain a bit more in detail how it works. First of all, here is our complete js code we need for the widget to work:

jQuery.fn.metalconReader = function(options){
	return this.each(function(){
		var opts = options || {};
		opts.renderTo = this;
		new MetalconReader(opts);
	}); //End each function
}; //End Plugin
 
var MetalconReader = function(options){
    jQuery.extend(this,options || {});
    this.url = "http://141.26.71.115:8080/Graphity-Server-0.1/read?user_id="+this.user+"&poster_id="+this.user+"&num_items=15&own_updates=1";
	//this.url = "https://api.flattr.com/rest/v2/users/"+this.user+"/things.as";
	if(this.user === "") throw "The 'user' property is required";
	if(this.renderTo === "") throw "The 'renderTo' property is required";
	this.read();
}; //End constructor

MetalconReader.prototype = {
	renderTo: "",
	user	: "",
	items	: 10,
	
	read	: function(){
		this.el = jQuery(this.renderTo);
		this.el.append("<div class=\"metal-loading\"></div>");
		jQuery.ajax({
			url		: this.url,
			context	: this, 
		    success	: this.parse,
		}); //End AJAX call
	}, //End read function

	parse	: function(json_data){
		this.el.empty();
		this.data = json_data.items;
		this.render(this.renderTo);
	}, //End parse function

	render	: function(element){
		var html = [];
		var that = this;
		html.push("<ul>");
		for(var i = 0; i < this.items && i < this.data.length;i++){
			var temp_date = that.createDate(this.data[i].published);
			html.push("<li><strong><a href=\""+this.data[i].id+"\">"+that.format(temp_date)+"</a></strong><br><span>"+this.data[i].actor.id+": "+this.data[i].object.message+"</span></li>");
		} //End for
		html.push("</ul>");
		this.el.append(html.join(""));
	}, //End render function
	createDate	: function(str){
		str = str.substring(0,19).replace(/[ZT]/," ").replace(/\-/g,"/");
		return new Date(str);
	}, //End createDate function
	format		: function(date){
		var diff   = (((new Date()).getTime() - date.getTime()) / 1000),
			days   = Math.floor(diff / 86400),
			months = Math.floor(days / 31);

		if (isNaN(days) || days < 0)return date.toString();
		
		if(days == 0){ 
			if(diff < 60)return "Just now";
			if(diff < 120)return "1 minute ago";
			if(diff < 3600)return Math.floor( diff / 60 ) + " minutes ago";
			if(diff < 7200)return "1 hour ago";
			if(diff < 86400)return  Math.floor( diff / 3600 ) + " hours ago";
		}else if(days < 31){
			if(days == 1)return "Yesterday";
			if(days < 7)return days + " days ago";
			if(days < 31)return Math.ceil( days / 7 ) + " weeks ago";
		}else{
			if(months == 1)return "A month ago";
			if(months < 12)return Math.ceil( days / 31 ) + " months ago";
			if(months >=12)return Math.floor( days / 365 ) + " years ago";
		}//End else
	} //End format function	
}; //End Prototype

The script has the following structure. It starts with jQuery.fn.buzzReader = function(options){...} In this part we define how we can use the final widget in our html source code. This code checks if the given options are empty and writes the renderTo part of the options to this, which in that part refers to JQuery. After that we instantiate a new Object of our BuzzReader Class. In our html part, we can call our widget now with:

$(function(){
	$("#metal .reader").metalconReader({
		user	: "sampleUser",
		items	: 5
	});
});

Next step is our constructor for our object. It gets called when we make a "new" instance of our object.

var MetalconReader = function(options){
    jQuery.extend(this,options || {});
    this.url = "http://localhost:8080/Graphity-Server-0.1/read?user_id="+this.user+"&poster_id="+this.user+"&num_items=15&own_updates=1";
	if(this.user === "") throw "The 'user' property is required";
	if(this.renderTo === "") throw "The 'renderTo' property is required";
	this.read();
}; //End constructor

In this example we use a server that is located on the same computer as the script,therefore the localhost address. Then we have some error handeling if renderTo or user weren't set before but its not used at the moment. The more important part is that the constructor calls this.read(); when he is created. This calls his own read method, in which our next step follows. In the read part it gets a bit more complicated. In read we call this.el = jQuery(this.renderTo); and this.el.append("<div class=\"metal-loading\"></div>"); This basiclly means that we take the element that called our function in the first place, our $("#metal .reader") object in our html and render our data into that object. And as a first action of this we append a small giv that appears at the start when our widget loads. This gets removed as soon as our server provides data. After that we start a request to our server using AJAX.

jQuery.ajax({
			url		: this.url,  //take the URL you got from the start
			context	: this,   //use the object you had before instead of an JQuery object
		    success	: this.parse,  //when you are done with the ajax, call the parse function of my object
		}); //End AJAX call

Activity Stream

Loading Components

Event Bus

User Interface

Transitions

Fading

Drag and drop

Clone this wiki locally