Showing posts with label ajax. Show all posts
Showing posts with label ajax. Show all posts

Wednesday, 17 October 2007

Progress Update

Have been working on budgeting functionalities this past couple of weeks. Seems like I've managed to get these things working though it may require further testing.

  1. Transactions - Add/Edit/Delete (admin, member, guest)
  2. Jobs - Add/Edit/Delete (admin) [job description might still need some work]
  3. Projects - Add (all) [need to do edit and delete]
  4. Members - Add/Delete (admin) [need to do permission editing]
All this is done using javascript and ajax. A lot of fiddling around but its getting there.

Monday, 17 September 2007

Dealing with JavaScript Object Notation (JSON)

Ruby on Rails provides an easy way to render JavaScript Object Notation (JSON) without actually having to deal with itty gritty details of forming the object literal.

# Controller
render :json => { :name => "Danny", :title => "Mr" }.to_json

produces

{ name: 'Danny', title: 'Mr' }

Once you have done so, you can create an object in javascript by running

var person = eval("(" + request.responseText) + ")");

You can then access the attributes by going person.name and person.title which returns "Danny" and "Mr", as expected.

Saturday, 15 September 2007

Thesis Update!

It's been a busy past few weeks, getting familiar with the prototype and scriptaculous javascript framework but it has paid off. Been looking into user interface design where there can be more interaction with the user.

What I've been trying to do is to try and simulate a 'desk' environment, where you would normally use your hands to move things around depending on what you want to do. What that means is to make things draggable, collapsible, expandable etc.

As you can see below, I've added drop down menus for menu selection. I've also made the right hand navigation bar draggable, as well as the main content in the middle. Can't really see it from a picture I guess. The main content and navigation bars are also expandable and collapsible.
I've also rethought the design of performing actions that does not require a lot of data loading. In other words, utilizing AJAX to perform actions without really leaving the page which means no refresh.

Created a hovering div that disables the content below, and displays the content above it depending on what type of action it is. I used scriptaculous' effects (Fade and Switchoff) to display and close the hover div.

I've only tested this on a Firefox environment as the browser has great plugin tools (Firebug) which makes debugging JavaScript, HTML and CSS a walk in the park.





Over the next couple of weeks I plan to add drag & drop features which will allow more user interaction by using the mouse which in return, simulates using a hand to do stuff. Hopefully there will be minimal user input where it isn't necessary.

Hopefully I'll have the chance to post up how I did all these things soon.

Wednesday, 5 September 2007

JavaScript Validation

I've spent some time writing a validation framework for checking user text field inputs on the client-side.

The parameters it takes are:
function(valField, type, options) where valField and type are required. valField is the element to validate, and type is a choice of ["required", "exists", "update", "password"].
Options is optional and is an object. In the options object, it takes these attributes:

infoField: element - the element to display messages to the user,
repeatField: element - the element which is used to repeat (like repeat password or email),
required: boolean - specifies whether input is required (defaults to true),
ajax: boolean - specifies whether Ajax is used to communicate to the server (defaults to false),
url: string - url for Ajax call (only works if ajax: true),
column: string - the column in the table (only works if ajax: true),
idkey: string - the id parameter (only works if ajax: true)

Examples of different types of usage:

  • new Validator(this, 'exists', { infoField: $('project_name_span'), ajax: true, idkey: $('user_id').value , column: 'name', url: '/project/check_exists' });
  • new Validator(this, 'required', { infoField: $('project_name_span') });
  • new Validator(this, 'update', { infoField: $('user_lname_span'), ajax: true, column: 'lname', idkey: $('user_id').value, url: '/user/ajax_update' });
  • new Validator(this, 'password', { infoField: $('user_pwd_span') });

Thursday, 23 August 2007

Bug #1: AJAX checking in certain actions

So I came across a bug as I was testing my newly written code to check whether handles and usernames have already been registered in the database. This worked fine when I want to sign up. However, when I want to update a user's profile, it would not let me update my profile with my existing email because the email already exists in the database. Pretty obvious that there's a bug there.

So when I did my AJAX checking, I had to determine what type of action I was doing (i.e. signing up, updating...). I had a parameter called action which would be sent in the query string, telling the controller what kind of action I am doing. The problem is, whenever I did that, my code for some reason could not recognise what kind of action I'm performing. When I printed out params[:action], it gave me the controller's method name.

Out of frustration, I hopped onto irc to get some real-time help. Turns out that action was a reserved name used for routing purposes, which determines which method of the controller you're calling to. D'oh! Obviously I should've known this as my code is scattered with :action => "something".

So I changed the parameter name to actiontype and it worked perfectly!

Tuesday, 21 August 2007

Form validation with AJAX

Finally managed to utilise javascript and ajax to do client-side form checking. I am using javascript instead of rjs because I feel like I have more control over what I'm doing and also I'm more familiar with the javascript syntax. Since prototype framework is included as part of the javascript defaults in RoR, I will be using that framework too.

Its got some pretty handy things like accessing DOM elements using $('element id'), so you don't have to deal with document.getElementId etc. The framework also provides a cool Ajax object which handles all the nasty readystates that you will come across if you use the conventional way of doing Ajax.

Here is a snippet of the client-side code:

new Ajax.Request("/user/check_exists",
{
parameters: params + "=" + textField.value,
onLoading: showMsg(infoField, "<img src="../../images/ajax/ajax-loader.gif" border="0" /> Checking if available..."),
onSuccess: function(request) {
if (request.responseText)
{
showMsg(infoField, request.responseText);
textField.className = "fail";
textField.focus();
}
else
{
showMsg(infoField, "");
textField.className = "success";
}
}
});
Here is a snippet of the server-side code:

def check_exists
if params[:handle]
@handle_exists = User.find(:first, :conditions => [ "handle = ?", params[:handle] ])
if @handle_exists == nil
render :text => ""
else
render :text => "Username is taken. Please choose another."
end
elsif params[:email]
@email_exists = User.find(:first, :conditions => [ "email = ?", params[:email] ])
if @email_exists == nil
render :text => ""
else
render :text => "This email is registered. Please choose another."
end
end
end
Sorry about the indentations if they don't come out correctly. For some reason this current blogger layout strips any unnecessary whitespaces.

Here are some screen shots of what I've done today. You will notice I used a little CSS to make things look nicer.



[edit date="23-08-07"]

I decided to move the business logic into the model and leave the transaction logic in the controller. More elegant and scalable I reckon.

In the model:
def self.attribute_exists?(attribute, value)
@attribute_exists = User.find(:first, :conditions => [ attribute + " = ?", value ])
if @attribute_exists != nil
return @attribute_exists
else
return nil
end
In the controller:
def check_exists
if params[:actiontype] == "new"
if params[:handle]
@user = User.attribute_exists?("handle", params[:handle])
if @user == nil
render :text => ""
else
render :text => "Username is taken. Please choose another."
end
elsif params[:email]
@user = User.attribute_exists?("email", params[:email])
if @user == nil
render :text => ""
else
render :text => "This email is registered. Please choose another."
end
end
elsif params[:actiontype] = "edit"
@cur_user = User.find(params[:id])

if params[:handle]
@user = User.attribute_exists?("handle", params[:handle])
if @user == nil || @user == @cur_user
render :text => ""
else
render :text => "Username is taken. Please choose another."
end
elsif params[:email]
@user = User.attribute_exists?("email", params[:email])
if @user == nil || @user == @cur_user
render :text => ""
else
render :text => "This email is registered. Please choose another."
end
end
end
end
A general rule of thumb is that code that requires communication with the database should be placed in the model side instead of the controller. The controller's job is to handle the user's request, retrieve data from the model and provide a response if necessary. The view's job is to handle presentation layer (i.e. HTML & CSS) for viewing purposes (thus called the View).

[/edit]

Friday, 17 August 2007

auto-complete textfield

We have all seen the famous Google Suggestions which was one of the driving factors to the rapid growth of AJAX applications, using real-time auto-completion without refreshing your browser.

Ruby on Rails makes this easy by using script.aculo.us javascript framework. A simple ajax auto-complete field only consists of two lines (with reference to the MVC framework):


#View
<%= text_field_with_auto_complete :model, :attribute %>

#Controller
auto_complete_for :model, :attribute

Viola! You've got yourself a working auto-complete textfield.