After Thought

Archive for November 2011

Include vendor java scripts and style sheets in Rails 3.1

with 2 comments

In rails 3.1 any external javascript/stylesheet plugins (like tablesorter.js etc) that you use in your project are placed in vendor/assets directory. To include it in your rails application, add a vendor.js and vendor.css.scss file as shown below in your assets/javascripts and assets/stylesheets directory.

vendor.js:

// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require_tree .

vendor.css.scss:

/*
 * This is a manifest file that'll automatically include all the stylesheets available in this directory
 * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
 * the top of the compiled file, but it's generally better to create a new file per style scope.
 *= require_self
 *= require_tree .
*/

Now update your application.js and application.css.scss files to include vendor.js and vendor.css.scss respectively.

application.js:

// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require jquery-ui
//= require vendor
//= require_tree .

application.css.scss:

/*
 * This is a manifest file that'll automatically include all the stylesheets available in this directory
 * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
 * the top of the compiled file, but it's generally better to create a new file per style scope.
 *= require_self
 *= require lib
 *= require vendor
 *= require_tree .
*/

Now you can add files to your vendor assets directory and it will be picked up your rails app. Being a beginner in rails, I found this way very effective as I don’t have to update my application.js file once set. I would be interested to know if there is a better way of handling this.

Written by shashankshetty

November 6, 2011 at 8:20 pm

Track changes if form fields are changed on a web page

leave a comment »

A very useful feature to have on a web page is to remind the user of unsaved changes when he/she navigates away from the page without saving. A easy way to implement this is to set a global flag when a form is changed. Based on the flag value, pop a dialog when the user tries to navigate away from the web page without saving. This approach has several flaws, the obvious one being the usage of a global variable. It also fails if the user reverts his changes.

A better solution is to keep track of all the fields on the page and display the dialog only when there is a change. If we were to implement such a tracker, it  has to do the following.

Step 1: Scan all the form fields like textbox, textarea, checkbox etc to and store the existing values when the page loads.

Step 2: When the user makes a change, attach an event on all the links to pop a dialog when the user clicks on it without saving.

Step 3: Remove the attached events, if the user reverts those changes.

Here is an example web page.

If the user edits Name field and clicks on My Blog link without saving, it should pop a dialog as shown below:

Dialog in the example is dialog from jqueryui .

track.js keeps track of changes on the form and makes it possible to hook before change and after change events.  Assuming the form id is editForm, call trackchanges (with events you want to associate with) in your document ready function. Hook a dialog open event in the afterChangeAction and remove it in beforeChangeAction.

Below is the code listing.

jQuery(document).ready(function($) {
	var beforeChangeAction = function () {
        $("a[id^='lnk']").each(function() {
            $("#" + this.id).die('click');
        });

    };

    var afterChangeAction = function () {
        $("a[id^='lnk']").each(function() {
            var id = this.id;
            $("#" + id).live('click', function (e) {
                bindModalConfirmationDialogFor(id, redirectAction);
                openConfirmationDialog(e, "Any changes made will be lost. Are you sure you want to continue?");
            });
        });
    };

	$("#editForm").trackchanges({events: "change blur keyup mousedown", exclude: "exclude", beforeChangeAction: beforeChangeAction, afterChangeAction: afterChangeAction});
});

function bindModalConfirmationDialogFor(fld, action) {
    var dialogOpts = {
        modal: true,
        autoOpen: false,
        buttons: {
            'No': function() {
                $(this).dialog('close');
            },
            'Yes': function() {
                action(fld);
                $(this).dialog('close');
            }
        }
    };
    $("#dialog-confirm").dialog(dialogOpts);
}

function openConfirmationDialog(e, message) {
    e.preventDefault();
    $("#dialog-confirm").html("<p><span class='ui-icon ui-icon-alert' style='float:left; margin: 0 7px 20px 0;'></span>" + message + "</p>");
    $("#dialog-confirm").dialog("open");
}

function redirectAction(fld) {
    window.location.href = $("#"+fld).attr("href");
}

The problem with this approach is, it is obtrusive. The user is forced to click twice to navigate without saving. What would be really cool is if we can change the color of the banner on the page as the user edits any form field. Further, we can change the color back to the original state when the user reverts those changes without ever refreshing the page. It would be a seamless unobtrusive experience to users reminding them to save the page before navigating to a different page (Some of the websites out there already have this nifty feature). As an example let us change the color of the Banner shown below from blue to yellow when a user edits any form field.

If we were to implement such a tracker, it  has to do the following.

Step 1: Scan all the form fields like textbox, textarea, checkbox etc to and store the existing values when the page loads.

Step 2: When the user edits any field check if the new value of that field is different from the old value; change the color of the Banner from blue to yellow.

Step 3: Revert the color back to blue, if the user reverts those changes.

Below is the code listing:

jQuery(document).ready(function($) {
	var beforeChangeAction = function () {
        $("#buttons").css("background-color", "#bcd3e9");
        if ($("#changed-text").length > 0) {
            $("#changed-text").remove();
        }
    };

    var afterChangeAction = function () {
        $("#buttons").css("background-color", "#fbec88");
        if ($("#changed-text").length === 0) {
            $("#buttons").prepend("<span id='changed-text'>Changes not saved</span>");
        }
    };

	$("#editForm").trackchanges({events: "change blur keyup mousedown", exclude: "exclude", beforeChangeAction: beforeChangeAction, afterChangeAction: afterChangeAction});
});

You can choose to exclude a field or a form with a class. In the example above we excluded Exclude Changes field by adding class “exclude”.

<input type='text' id='exclude_changes' name='exclude_changes' class='exclude' value=''/>

FormChangeTracker project is available on github. You can find code for both the above examples along with track.js.

Written by shashankshetty

November 4, 2011 at 5:16 pm

Posted in javascript, Uncategorized

Tagged with ,