Never been to TextSnippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world (or not, you can keep them private!)

« Newer Snippets
Older Snippets »
25 total  XML / RSS feed 

jQuery namespaced event binding/unbinding

// from a comment by Steven Bristol on errtheblog.com

I just wanted to share a really killer event handling tidbit:

Generally you do something like:

jQuery(’.class’).click(function(){//whatever});


Everyone knows this can be rewritten as:

jQuery(’.class’).bind(‘click’, function(){//whatever});


But sometimes you need to unbind something:

jQuery(’.class’).unbind(‘click’, function(){//});


The problem with this is that it will unbind all the click events, not just yours. So if multiple bits of javascript have a click event handler for ’.class’, unbinding removes them all. (This is because there is no way to identify an anonymous function.)

But jQuery is so good that there is a way to handle this: Namespacing your events:

jQuery(’.class’).bind(‘click.namespace’, function(){//}); 
jQuery(’.class’).unbind(‘click.namespace’);


or for reinitializing an element added via ajax:

jQuery(’.class’)unbind(‘click.namespace’).bind(‘click.namespace’, function(){//});

jQuery and Rails' respond_to

// Just throw this at the bottom of your application.js and you’re good to go: all jQuery ajax requests will trigger the wants.js block of your respond_to declaration, exactly like you’d expect. Enjoy.
// via: http://ozmm.org/posts/jquery_and_respond_to.html

jQuery.ajaxSetup({beforeSend’: function(xhr) {xhr.setRequestHeader(“Accept”,text/javascript”)} })

Ajax / Effects-only link

To create a link that is used purely for some Scriptaculous effects or for an Ajax call, use # as the href target and return false from the javascript onlick call.

<a href="#" onclick="Effect.toggle('widget_preview', 'blind');return false;">Blog this ...a>

Never render the full layout in a Rails view when called via AJAX

Essential for degradable javascript, when one never knows if a view or partial is being called via XmlHttpRequest or not. Throw the below code in your ApplicationController (application.rb)

More info in this blog post

def render(*args)
        args.first[:layout] = false if request.xhr? and args.first[:layout].nil?
        super
end

AJAX multiple updates to calling page without using RJS template

When a controller action is called via XHR (XmlHttpRequest), the action will look for a .rjs template first, then a .rhtml template if not available.

To skip using the .rjs template, include a render(:update) {|page| } call to perform updates.

  def toggle_showall
    render(:update) do |page|
      page[:fb_content].replace_html "just text? ripoff!"
      page[:flash_box].visual_effect :blind_down, :duration => 0.25
    end
  end


We use page as a hash to reference elements by id from the originating page.

page[:fb_content]


Then perform the updates to the element. Here we're replacing the contents of the element with id of "fb_content" with the string of text.
page[:fb_content].replace_html "just text? ripoff!"


You can render anything you could normally using a render call, example, some partial.
page[:fb_content].replace_html :partial => "shared/some_partial"


If the partial you're calling has instance vars you need to fill before, just include them before the render(:update) block and they'll be available to the partial during rendering.


Here we execute scriptaculous' Effect.BlindDown on element 'flash_box' with option of duration of .25 seconds.
page[:flash_box].visual_effect :blind_down, :duration => 0.25


There are plenty of other methods you can call on a page element. Refer to the Agile WebDev PDF for more details.

programmatically firing object event using javascript

Simply call the event of the object.

<select id='element_id' onChange="some_javascript_func">

<a href="#" onclick="$('element_id').onchange();">


Note that this uses Prototype's $ function to find the element.

More details here:
http://tinyurl.com/2b45me

Ajax link_to_remote replace with spinner on click

This combination of CSS and prototype allows you to swap out the text with a spinner element, then back when loading is complete.

CSS

div.loading {
        background: url(/images/dots-white.gif) no-repeat 8px 6px;
        text-indent: -999px;
}


RHTML
<div id="lc" class="">
<%= link_to_remote 'toggle action', {
        :url => toggle_showall_new_recipe_path, 
        :method => :get,
        :before => "Element.addClassName('lc', 'loading')",
        :complete => "Element.removeClassName('lc', 'loading')"}, 
        :class => 'loading xhr', 
        :id => 'xhr-link' %>
>


Upon link click, the loading class will be added, moving the text off the window, effectively hiding it, while showing the background (not background-image). When XHR call is complete, simply remove the class and you're back to normal display properties.

Multiple updates to calling page in AJAX call

Uses Rails' .rjs template to form multiple update calls, server side, that will update the calling page with the included javascript.

Example:

def original_control_handler
 [misc methods and other things]
 [done normally in this controller]
 render :update do |page|
  page.replace_html 'calling_element_id', :partial => 'updated_template'
  page.helper 'helper_id', :helper_options => 'go here'
 end
end


Without rjs templates, you would have to write complex javascript by hand to update multiple elements on the calling page after returning from an XMLHTTPREQUEST (XHR) request. This allows you to avoid that, and do it all server side.

You can also place the update calls into an actual view templates instead of in the controller. Just put the contents of the update block into app/views/[controller]/original_control_handler

To replace simple tag contents, just provide a string of what to replace it with
 ...
 page.replace_html 'element_to_update', "this string goes in element"


Or replace the entire tag itself.
 page.replace 'element2_to_update', 
  (link_to_remote "link_text", {:url => dest, :method => :get, :id => 'element2_to_update')



Building :with querystring values in AJAX remote_function call

To build the string with multiple values, you must end it with an '=' char.

example:
To get this
?chapter=9&sort_by=created_at&sort_dir=desc


You need this
:with => "'chapter='+ encodeURIComponent(value)+'&sort_by=#{@sort_by}&sort_dir=#{@sort_dir}&='", :update => 'list_items'


Explained at: http://codefluency.com/2006/6/2/rails-views-using-the-with-option

AJAX link submit of form

Submit a form using a link, which itself shows different text depending on whether a database item exists or not.

Place this in .rhtml file (or layout file for site-wide coverage)
<%= javascript_include_tag "prototype" %>


Creates a link that fires a javascript method.
Method is created by remote_function.
Form.Serialize processes the entire form contents into a string so that receiving page is none the wiser.
Giving link an id ('follow_anchor') and asking remote_function to update the same id, allows us to dynamically change the innerHTML of the link. On the target side, have the method (create in this case) render text that will be used as the new innerHTML of this link.
<%= link_to_function @toggle_text, remote_function(:url => watch_lists_path, :method => :post, :with => "Form.serialize('watch_form')", :update => 'follow_anchor'), :id => 'follow_anchor' %>


  def create
    @watch_list = WatchList.new(params[:watch_list])

    if @watch_list.toggle
      render(:text => @watch_list.toggle_text)
    else
      render(:text => 'We couldn''t add this book to your Watch List. Please contact us for help.')
    end
  end





Load javascript function from returned ajax HTML

Problem - calling a function in
ENDTXT end # RJS template 'css_preview.rjs' page.replace_html "css", ""

Displaying ActiveRecord validation errors from AJAX requests

I haven’t been able to find anything built into Rails to present errors from model validation when a request is sent via AJAX.

So I came up with this handly little hack, which I’ve put in my application.rb file.

def render_javascript_alert_for_errors_on(object)
  errors = object.errors.full_messages
  alert_text = errors.collect { |error| '-' + error }.join("\n")
  render :update do |page|
    page.alert alert_text
  end
end


This takes the object and displays a nicely-formatted version of all the errors on that object, taking advantage of inline RJS to render the javascript to create an alert().

It works perfectly, but it still feels a little “hacky” to me. Any better ideas?

Initialize XMLHttpRequest/ActiveXObject for use with AJAX

xmlHttp = false;
                
try {
        xmlHttp = new XMLHttpRequest();
} catch(Microsoft1) {
        try {
                xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch(failed) {
                xmlHttp = false;
        }
}
                
if(!xmlHttp) {
        alert("Error: Could Not Initialize XMLHttpRequest()!\r\n\r\nJavaScript must be enabled to view this page.");
}

Initialize XMLHttpRequest/ActiveXObject for use with AJAX

xmlHttp = false;
                
try {
        xmlHttp = new XMLHttpRequest();
} catch(Microsoft1) {
        try {
                xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch(failed) {
                xmlHttp = false;
        }
}
                
if(!xmlHttp) {
        alert("Error: Could Not Initialize XMLHttpRequest()!\r\n\r\nJavaScript must be enabled to view this page.");
}

A Caching XmlHttpRequest Wrapper



/* 
        XmlHttpRequest Wrapper
        Version 1.2.2
        29 Jul 2005 
        adamv.com/dev/
*/

var Http = {
        ReadyState: {
                Uninitialized: 0,
                Loading: 1,
                Loaded:2,
                Interactive:3,
                Complete: 4
        },
                
        Status: {
                OK: 200,
                
                Created: 201,
                Accepted: 202,
                NoContent: 204,
                
                BadRequest: 400,
                Forbidden: 403,
                NotFound: 404,
                Gone: 410,
                
                ServerError: 500
        },
                
        Cache: {
                Get: 1,
                GetCache: 2,
                GetNoCache: 3,
                FromCache: 4
        },
        
        Method: {Get: "GET", Post: "POST", Put: "PUT", Delete: "DELETE"},
        
        enabled: false,
        logging: false,
        _get: null,     // Reference to the XmlHttpRequest object
        _cache: new Object(),
        
        Init: function(){
                Http._get = Http._getXmlHttp()
                Http.enabled = (Http._get != null)
                Http.logging = (window.Logging != null);
        },
        
        _getXmlHttp: function(){
        /*@cc_on @*//*@if (@_jscript_version >= 5)
                try { return new ActiveXObject("Msxml2.XMLHTTP"); } 
                catch (e) {} 
                try { return new ActiveXObject("Microsoft.XMLHTTP"); } 
                catch (e) {} 
        @end @*/
                try { return new XMLHttpRequest();}
                catch (e) {}

                return null;
        },

/*
        Params:
                url: The URL to request. Required.
                cache: Cache control. Defaults to Cache.Get.
                callback: onreadystatechange function, called when request is completed. Optional.
                method: HTTP method. Defaults to Method.Get.
*/
        get: function(params, callback_args){   
                if (!Http.enabled) throw "Http: XmlHttpRequest not available.";
                
                var url = params.url;
                if (!url) throw "Http: A URL must be specified";
                                
                var cache = params.cache || Http.Cache.Get;
                var method = params.method || Http.Method.Get;
                var callback = params.callback;
                
                if ((cache == Http.Cache.FromCache) || (cache == Http.Cache.GetCache))
                {
                        var in_cache = Http.from_cache(url, callback, callback_args)

                        if (Http.logging){
                                Logging.log(["Http: URL in cache: " + in_cache]);
                        }

                        if (in_cache || (cache == Http.Cache.FromCache)) return in_cache;
                }
                
                if (cache == Http.Cache.GetNoCache)
                {
                        var sep = (-1 < url.indexOf("?")) ? "&" : "?"      
                        url = url + sep + "__=" + encodeURIComponent((new Date()).getTime());
                }
        
                // Only one request at a time, please
                if ((Http._get.readyState != Http.ReadyState.Uninitialized) && 
                        (Http._get.readyState != Http.ReadyState.Complete)){
                        this._get.abort();
                        
                        if (Http.logging){
                                Logging.log(["Http: Aborted request in progress."]);
                        }
                }
                
                Http._get.open(method, url, true);

                Http._get.onreadystatechange =  function() {
                        if (Http._get.readyState != Http.ReadyState.Complete) return;
                        
                        if (Http.logging){
                                Logging.log(["Http: Returned, status: " + Http._get.status]);
                        }

                        if ((cache == Http.Cache.GetCache) && (Http._get.status == Http.Status.OK)){
                                Http._cache[url] = Http._get.responseText;
                        }
                        
                        if (callback_args == null) callback_args = new Array();

                        var cb_params = new Array();
                        cb_params.push(Http._get);
                        for(var i=0;i<callback_args.length;i++)
                                cb_params.push(callback_args[i]);
                                
                        callback.apply(null, cb_params);
                }
                
                if(Http.logging){
                        Logging.log(["Http: Started\n\tURL: " + url + "\n\tMethod: " + method + "; Cache: " + Hash.keyName(Http.Cache,cache)])
                }
                
                Http._get.send(params.body || null);
        },
        
        from_cache: function(url, callback, callback_args){
                var result = Http._cache[url];
                
                if (result != null) {
                        var response = new Http.CachedResponse(result)
                        
                        var cb_params = new Array();
                        cb_params.push(response);
                        for(var i=0;i<callback_args.length;i++)
                                cb_params.push(callback_args[i]);
                                                        
                        callback.apply(null, cb_params);
                                
                        return true
                }
                else
                        return false
        },
        
        clear_cache: function(){
                Http._cache = new Object();
        },
        
        is_cached: function(url){
                return Http._cache[url]!=null;
        },
        
        CachedResponse: function(response) {
                this.readyState = Http.ReadyState.Complete
                this.status = Http.Status.OK
                this.responseText = response
        }    
}

Http.Init()

function json_response(response){
        var js = response.responseText;
        try{
                return eval(js); 
        } catch(e){
                if (Http.logging){
                        Logging.logError(["json_response: " + e]);
                }
                else{
                        alert("Error: " + e + "\n" + js);
                }
                return null;
        }
}

function getResponseProps(response, header){
        try {
                var s = response.getResponseHeader(header || 'X-Ajax-Props');
                if (s==null || s=="")
                        return new Object()
                else
                        return eval("o="+s)
        } catch (e) { return new Object() }
}



Caching Options
These options only make sense to use with the GET method. POST operations should not be cached.

Http.Cache.Get
Perform a normal request, and do not add the result to the local cache. Note: on IE, requesting the same URL via GET multiple times will cause IE to cache the result internally.
Http.Cache.GetCache
Perform a request and cache the result if sucessful. If the requested URL's response is already cached locally, do not perform the server request.
Http.Cache.GetNoCache
Perform a request and add a time-based variable to the querystring to force IE not to cache the result. The result is not placed in the local cache.
Http.Cache.FromCache
If the requested URL's response has already been cached, call the supplied callback on the locally cached version. Http.get will return true or false based on whether or not the response is in the cache.

AJAX Edit In Place With Prototype

// description of your code here

JS Source
/*
 * Edit In Place
 * http://josephscott.org/code/js/eip/
 *
 * Version: 0.2.0
 * License: http://josephscott.org/code/js/eip/license.txt
 */
EditInPlace = function() { };
EditInPlace.settings = function(set) {
        var settings = {
                id:                             false,
                save_url:               false,
                css_class:              'eip_editable',
                savebutton:             'eip_savebutton',
                cancelbutton:   'eip_cancelbutton',
                saving:                 'eip_saving',
                type:                   'text',
                orig_text:              false
        };

        for(var i in set) { settings[i] = set[i]; }

        return($H(settings));
};

EditInPlace.formField = function(set) {
        var field = '';
        set['orig_text'] = $(set['id']).innerHTML;

        if(set['type'] == 'text') {
                var size = set['orig_text'].length + 10;
                if(size >= 100) { size = 100; }
                if(set['size']) { size = set['size']; }

                field = '/>';
        }
        else if(set['type'] == 'textarea') {
                var cols = 50;
                if(set['cols']) { cols = set['cols']; }
                var rows = (set['orig_text'].length / cols) + 3;
                if(set['rows']) { rows = set['rows']; }

                field = '<span id="' + set['id'] + '_editor"><textarea id="'
                        + set['id'] + '_edit" class="' + set['css_class'] + '" name="'
                        + set['id'] + '_edit" rows="' + rows + '" cols="'
                        + cols + '">' + set['orig_text'] + 'textarea>';
        }

        return(field);
};

EditInPlace.formButtons = function(set) {
        return(
                '
/><span><input id="' + set['id'] + '_save" class="' + set['savebutton'] + '" type="button" value="SAVE" /> OR ' + '<input id="' + set['id'] + '_cancel" class="' + set['cancelbutton'] + '" type="button" value="CANCEL" />' + 'span></span>' ); }; EditInPlace.setEvents = function(set) { Event.observe( set['id'], 'mouseover', function() { Element.addClassName(set['id'], set['css_class']); }, false ); Event.observe( set['id'], 'mouseout', function() { Element.removeClassName(set['id'], set['css_class']); }, false ); Event.observe( set['id'], 'click', function() { Element.hide(set['id']); var field = EditInPlace.formField(set); var button = EditInPlace.formButtons(set); new Insertion.After(set['id'], field + button); Field.focus(set['id'] + '_edit'); Event.observe( set['id'] + '_save', 'click', function() { EditInPlace.saveChanges(set); }, false ); Event.observe( set['id'] + '_cancel', 'click', function() { EditInPlace.cancelChanges(set); }, false ); }, false ); }; EditInPlace.saveComplete = function(t, set) { $(set['id']).innerHTML = t.responseText; }; EditInPlace.saveFailed = function(t, set) { $(set['id']).innerHTML = set['orig_text']; Element.removeClassName(set['id'], set['css_class']); alert('Failed to save changes.'); }; EditInPlace.saveChanges = function(set) { var new_text = escape($F(set['id'] + '_edit')); $(set['id']).innerHTML = '<span class="' + set['saving'] + '">Saving ...span>'; Element.remove(set['id'] + '_editor'); Element.show(set['id']); var params = 'id=' + set['id'] + '&content=' + new_text; var ajax_req = new Ajax.Request( set['save_url'], { method: 'post', postBody: params, onSuccess: function(t) { EditInPlace.saveComplete(t, set); }, onFailure: function(t) { EditInPlace.saveFailed(t, set); } } ); }; EditInPlace.cancelChanges = function(set) { Element.remove(set['id'] + '_editor'); Element.removeClassName(set['id'], set['css_class']); Element.show(set['id']); } EditInPlace.makeEditable = function(args) { EditInPlace.setEvents(EditInPlace.settings(args)); }


HTML source
<html>
<head><title>Ajax Edit In Place (EIP) Exampletitle>







"example.html">Ajax Edit In Place (EIP) Example


"editme">AJAX edit in place like flickr.

"anotheredit">If you want room for more text you can use a textarea to edit instead.



PHP source
<?php
        $id = $_POST["id"];
        $content = $_POST["content"];
        print(htmlspecialchars($content));
?>

« Newer Snippets
Older Snippets »
25 total  XML / RSS feed