Monday, January 30, 2012

How to Make Javascript and Jquery Selectors function after Content is Refreshed with AJAX

So today I had another really specific problem while working on followtheproject.com. For my setup I have a group of <a> elements that are targeted by a jQuery selector, like $("a#id"), that was capturing their click() events and performing some ajax requests instead of going to a link. The return data for the ajax request reloads all of the <a> elements. The problem is that these newly loaded <a> elements are no longer targeted by the Jquery selector!

After some searching I found an extremely easy answer to solve this. The secret lies in jQuery's .live() function: http://api.jquery.com/live/

syntax:
selector.live( event, handler(eventObject) )

By wrapping event calls in the .live() function you are ensuring that all elements that match the selector, both now and in the future, will be targeted. This is different from regular selector and event functions because those are only applied to current elements that match the selector.

Old code 
$("a#id").click( function(e){ STUFF } );

New code
$("a#id").live('click', function(e){ STUFF });

For the lazy, here is the link to all of Jquery's event handlers: http://api.jquery.com/category/events/

Easy Peasy. The link will not always be redirected to the jQuery click event through the live() function, even after AJAX reloads the <a> elements! I wonder why the developer's of Jquery don't just build this into the normal click() and other event functions. Any performance hits would likely be worth the extra functionality.

Monday, January 23, 2012

Simple Site Search across Multiple Google App Engine Models

Search is a pretty important thing to have on a website. It is expected on every website and has become so prominent that it is many users main method of navigation on a site.
 

I have been working on a project management-esque application on Google App Engine, www.followtheproject.com , and have continually been putting off providing search functionality. I knew it was necessary from the beginning of development and have had a placeholder search input in the title bar and a search page for results, but no functionality at all, and very little guidance or ideas on how to provide that functionality across my application of many models such as Project, Account, Activity, File, Discussion, Comment etc.

This weekend I finally stumbled on a basic method to provide that functionality quickly and fairly easily. This method basically just “Gets it to work”, it is barebones with nothing fancy like auto completion or sorting. It is a good starting ground.


The starting point I used is found at http://www.billkatz.com/2008/8/A-SearchableModel-for-App-Engine on a blog post titled “A SearchableModel for App Engine” from 2008. I have no idea why it took me so long to find as I was searching for termes like “site search appengine” and “model search appengine” and it took a while to find a proper easy solution that is free.


Searching a Model, Easy


App Engine comes with a search module at google.appengine.ext.search. In the .py file that contains your models include this import:


 from google.appengine.ext import search 


The search module includes a class called search.SearchableModel which is a subclass of db.Model. Change desired searchable models to search.SearchableModel. 

class Activity(search.searchableModel):


This class provides functions that index an instance of the model whenever it is saved (with .put() or .save() ). Instances that are indexed can be searched using simple query syntax.


query = Activity.all().filter(“project =”, project).search(“some query string”)


I filter by project first because all of my searches will be project specific to whichever project is currently active. Optionally these results can be sorted by anything you would like using a .sort() call at the end of the query.


So how to search across multiple models?


Queries (as far as I know) can only be applied to one model at a time. To accomplish site-search over multiple models I simply did a separate a query for each model type I wanted and placed all the results in my values list to be sent to the template. In the template I list on results by model type, for my project management application this works nicely and the results can be somewhat sorted by category this way. I went with an order of importance based on my own judgment, which may change later. The order I used is Activities, Files, Discussions, People, Comments.
 

Next Steps

There is a lot to be desired with the built-in module. No autocomplete, no sorting by importance, and Bill Katz outlines a few more:

  • If you try to index too much text, you might run into CPU quota issues on put() as it builds the index.  Background processing, if it gets offered in the future, would address this issue.
  • There is a cap of 5000 indexed property values a single entity (one model instance) may have.  This could severely limit your keywords if you have a large number of indexed properties.  ListProperties take a toll.  Text and Blob properties aren't indexed, but your text property will generate keywords in SearchableModel.
  • SearchableModel entities currently don't display well in the App Engine data viewers because of the size of __searchable_text_index.
  • Multi-word searches seem broken for now because indexing the same property multiple times is not available until the next SDK release.
I believe that last one has been resolved now as the original post is from 2008 and I seem to be able to search multiple words. Try and design your app to sidestep these issues for now, and plan solutions for the future. I am doing that on mine.

Thanks and I hope this is useful to someone. It sure was to me this weekend!
Please let me know if you stumble on this and have any input as I will take it into consideration.

Friday, January 20, 2012

Detect where the scroll bar is with JQuery and provide visual cue to the user

I have a web page with a "display: fixed; z-index: 1; background: white" header at the top of the page. When I scroll down the body of my page slides behind the header. It works well but there is a problem:

  • There is no indicator aside from the scroll bar that the page is not at the TOP and it is deceiving.
To fix this I decided to use some simple JQuery watch for when the page is not scrolled at the top and to shade the background of the header slightly.


$(document).ready( function(){
  $(documnet).scroll( function(){
    var scrollPosition = $(document).scrollTop();
    if (scrollPosition == "0"){
      //The page is scrolled to the top
      $('#header').css('background', 'white');
    }
    else {
      //The page is not at the top
      $('#header').css('background', 'gray');
    }
  });
});



The code fires whenever the page is scrolled and checks if it is at the top. If it is at the top, it sets the header background to white. If it isn't at the top it sets it to gray and is a good visual cue to visitors that they are not at the top of the page.

A popular on is to display a hidden div in a fixed position near the edge of the screen with the text "Scroll back to top". When that div is visible the page is obviously not at the top, and when it is clicked, it is expected to take you back up to the top.

Here is some sample code for the click event to that takes the screen back to the top:

$(document).ready( function(){
  $("#scrollmessagediv").click( function(){
    //scroll to the top of the page
    $(document).scrollTop(0);
    //hide the element since we are at the top now
    $(this).hide();
  });
});


There are lot of ways to get creative with scrolling and JQuery, hopefully this got you started!

Thursday, January 12, 2012

How to Attach a Vertical Line to a Milestone in Microsoft Project 2010

Looks like we the deadline is met!

A big bold vertical line is a great indicator for a deadline/do-not-pass-or-else date in a schedule. The problem with drawing them in is that they second the timescale is changed or the project is zoomed the line is far off of where it needs to be. With the method below a line can be attached to a milestone and will move and scale with that milestone no matter the scale or zoom level.

Start a new line object by going to the Format section on the Ribbon and selecting line from the Drawing dropdown.

Left click and drag in the general area that you want your final line to be in, exactness is not key here only general limits.

  • Double Left Click the line to bring up the Format Drawing box and Left Click the Size & Position tab. 
  • Left click the Attach to task radio and enter the task ID into the box. The Task ID is the number to the far left of the desired task. In this example mine is 18. 
  • Click Ok.
Your line suddenly jumps, stay calm.

Straighten things up. 
  • Drag the line back to the general area you desire, it will stay from now on now that it is attached to a task. 
  • Double left click the line again and enter -0.10 in the Horizontal box. This will center the line on the milestone. 
  • Enter 0.00 in the Width box. This will ensure the line is straight. 
  • Click Ok.

The line should snap into the correct place. The height of the line was more or less defined when you originally drew it loosely. Feel free to adjust, and if you make the line crooked simply double left click the line and re-enter 0 in the Width box.

Make the line big, bold, and red (or whatever you choose it to be) by clicking the Line & Fill section of the Format Drawing box. Select your desired color and Line thickness. Click Ok.

That’s it! It is graphically pleasing and easy to understand for those VPs or clients that may not understand the importance of an upcoming deadline. Persuade them even more by adding a secondary scenario where if a desired action is not taken place it pushes the project past that imposing bold red line. Go get em.
UH OH we have crossed the RED LINE

Wednesday, January 11, 2012

First Google Server Error

Today, after 15 years or whatever, I experienced my first Google Search Server error while searching for something. It startled me and I didn't know what to do at first. I eventually just used Bing and it found what I needed. I am so excited about this that it is getting a blog post:

Also check out the xkcd I was after, http://xkcd.com/936/, it is a great read about password strength. It is much easier to remember a string of unrelated words or an abbreviated phrase than an obscure jumble of numbers letters and symbols, and as long as your password length is long it is just as secure! Just don't use horsebatterystaple as your password for everything now since it might be getting popular.

Sunday, January 8, 2012

Allow Users to Access their Email Address Books - A Dedication to Plaxo

I rely pretty heavily on my Gmail address book that has been accumulating since 2004 and love how it auto completes addresses as I type them. As I was coding an email-centric side project, http://www.sendrecurring.com, I realized that not having this feature and not being able to access your history of email contacts could potentially be a huge turn-off for people.

Luckily, I found Plaxo. Plaxo provides exactly what was needed for SendRecurring. It allows people to access their address books from all of the major email services, and use them on any webpage.

It is easy to implement, I just added their code to my <head> section, designated a link to show there popup, and designated a form field for the comma separated emails of their choosing to be deposited into. I set this up for my to, cc, and bcc fields on sendrecurring.

Thank you Plaxo, for allowing my recurring email service to be more convenient, and better overall!

Saturday, January 7, 2012

Web-Based Project Management


I am continuing to work on my goal of running a web based project management service that our office will benefit from. It needs to have more verbose and flexible sorting and filtering for a task list than what Excel offers. And should have a discussion forum and filesharing capabilities so that firms do not have to pay for an extra email service.
This would be an all in one package to complement Outlook and Office really. It does NOT need to have gantt or calendar functionality as most teams already have that in outlook and Microsoft Project or Primavera and it would only be awkward to change their workflow in those areas. May as well make a whole online office suite if I were trying to include those functions well.
I have followtheproject.com registered and have been fiddling with some of these features using mainly Google App Engine and Twitter Bootstrap. I have been piecing it together for around two months now and access is limited to myself at the moment on the site. I may open that up for a beta soon and I will continue to see how it goes.

Monday, January 2, 2012

Toggling Checkboxes in a Table with JQuery

I had a small problem tonight that was fun to solve. I have a table and in the first column of each row there is a checkbox. I want the checkbox to toggle when the row is clicked. This is easy to accomplish with some JQuery.

Here is a snippet of my HTML table:

Name Size Modified
Folder 1.0 KB Dec. 28, 2011, 3:41 p.m.
This is a new folder for the new project 53 bytes Jan. 3, 2012, 5:05 a.m.
ETC

And here is the accompanying JQuery:

$("tr").click(function(){
    var checkbox = $(this).children().children("input");
    checkbox.attr("checked", !checkbox.attr("checked"));
  });

The code finds the correct checkbox using the $(this) property provided by the event and the children() selector. Two children calls are necessary, first for the children of the TR, then for the children of the TD, this last one is specified to be the "input" child. The toggle is achieved by setting the "checked" attribute of the checkbox to the opposite of whatever it is currently set at, !$(checkbox).attr("checked");. Simple, love it!