Snippets

Create an account or login to be able to add, comment and rate snippets.

Navigation

Refine Tags

Snippets tagged "javascript ajax" Snippets tagged "javascript ajax"

Ajax InplaceSelect

creates an InplaceSelect field. A text is as normal text shown, when you click on it, it transforms to a select field. After selecting a value the select field transforms back to normal text. The data shown in the select field is requested from the server.

Save this helper in your_project/lib/helper/AjaxInplaceSelectHelper.php:

<?php
 
    /**
     * AjaxInplaceSelectHelper.
     *
     * @package    symfony
     * @subpackage helper
     * @author     Thomas Eigner <webmaster@flyingfinger.de>
     */
 
    /**
     * wrapper for InplaceSelect.
     * @param string $name The id of surrounding span
     * @param string $value The default text for the span
     * @param string $url The url to receive the update
     * @param string $json The url to fetch the list to show in the select field
     * @param int $selectedId The id of the element to select when select is shown first time
     * @param array $spanOptions The span tag options. (size, class, etc...)
     * @param array $inplaceOptions The options for the inplaceSelect (callback, etc...)
     *
     * @return string A span with the text, and InplaceSelect javascript tags
     */
 
    use_helper('JavaScript');
 
    function input_in_place_select_tag($name, $value, $url, $json, $selectedId, $spanOptions = array(), $inplaceOptions = array())
    {
      $context = sfContext::getInstance();
 
      $response = $context->getResponse();
      $response->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/builder');
      $response->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/prototype');
      $response->addJavascript(sfConfig::get('sf_prototype_web_dir').'/js/effects');
      $response->addJavascript('/js/inplaceselect');
 
      $content = content_tag('span', $value, array('id' => $name));
 
      $js_options = array();
 
      if (isset($inplaceOptions ['callback']))
      {
        $js_options['callback'] = $inplaceOptions['callback'];
      } else
      {
        $js_options['callback'] = "function(value, text) { return '".$name."_id='+value+'&".$name."_value='+text; }";
      }
      if (isset($inplaceOptions ['onFailure']))
      {
        $js_options['onFailure'] = $inplaceOptions['onFailure'];
      }
      if (isset($inplaceOptions ['onSuccess']))
      {
        $js_options['onSuccess'] = $inplaceOptions['onSuccess'];
      }
      if (isset($inplaceOptions ['highlightcolor']))
      {
        $js_options['highlightcolor'] = "'".addslashes($inplaceOptions['highlightcolor'])."'";
      }
      if (isset($inplaceOptions ['highlightendcolor']))
      {
        $js_options['highlightendcolor'] = "'".addslashes($inplaceOptions['highlightendcolor'])."'";
      }
      if (isset($inplaceOptions ['savingText']))
      {
        $js_options['savingText'] = "'".addslashes($inplaceOptions['savingText'])."'";
      }
      if (isset($inplaceOptions ['cancelText']))
      {
        $js_options['cancelText'] = "'".addslashes($inplaceOptions['cancelText'])."'";
      }
      if (isset($inplaceOptions ['savingClassName']))
      {
        $js_options['savingClassName'] = "'".addslashes($inplaceOptions['savingClassName'])."'";
      }
      if (isset($inplaceOptions ['clickToEditText']))
      {
        $js_options['clickToEditText'] = "'".addslashes($inplaceOptions['clickToEditText'])."'";
      }
      if (isset($inplaceOptions ['cancelLink']))
      {
        $js_options['cancelLink'] = ($inplaceOptions['cancelLink']) ? "true" : "false";
      }
 
 
      $javascript  = "new Ajax.InPlaceSelect('" . $name . "', '" . url_for($url)
        . "', '" . url_for($json) . "', " . $selectedId . ", "
        . _options_for_javascript($js_options) . " );";
 
      return $content . javascript_tag($javascript);
    }
 

You also need an additional JS-File in your_project/lib/helper/AjaxInplaceSelectHelper.php:

/*
    - inplaceselect.js -
      Creates a <select> control in place of the html element with the id
      specified.  It functions similar to "Ajax.InPlaceEditor" but instead
      of an <input> control, it creates a <select> control with a list of
      <options> from which to choose.  The parameters 'values' and 'labels'
      are arrays (of the same length) from which the <options> are defined.
 
    - Syntax -
      new Ajax.InPlaceSelect('id', 'url', 'json', 'selected', { options });
 
    - Example -
      new Ajax.InPlaceSelect('someId', 'someURL', 'otherURL', 1,
        { callback: function(value, text) { return 'newval='+value+'&newtxt='+text; } } );
 
    - Options('default value') -
      - hightlightcolor("#FFFF99"): initial color (mouseover)
      - hightlightendcolor("#FFFFFF"): final color (mouseover)
      - onFailure(function(transport) {}): Called if failure occurs sending changes
      - onSuccess(function(transport) {}): Called on sending changes successfully
      - callback(function(value, text) { return 'newval='+value+'&newtxt='+text; }): function to
        send additional parameters with the requests
      - cancelText("cancel"): Text for the cancel link
      - clickToEditText("Click to edit"): Tooltip for the text
      - cancelLink(true): Should the cancel link be shown
 
    Original JS-Script is from http://dev.rubyonrails.org/ticket/2667
 
    */
 
    Ajax.InPlaceSelect = Class.create();
    Ajax.InPlaceSelect.prototype = 
    {
      initialize:function(element,url,json,selected,options) 
      {
        this.element = $(element);
        this.url = url;
        this.json = json;
        this.selected = selected;
        this.values = new Array();
        this.labels = new Array();
        this.options = Object.extend(
          {
            highlightcolor: "#FFFF99",
            highlightendcolor: "#FFFFFF",
            onFailure: function(transport) {},
            onSuccess: function(transport) {},
            callback: function(value, text) 
            {
              return 'newval='+value+'&newtxt='+text;
            },
            cancelText: "cancel",
            clickToEditText: "Click to edit",
            cancelLink: true,
          }, 
          options || {}
        );
 
        this.originalBackground = Element.getStyle(this.element, 'background-color');
        if (!this.originalBackground) 
        {
          this.originalBackground = "transparent";
        }
 
        this.element.title = this.options.clickToEditText;
 
        this.ondblclickListener = this.enterEditMode.bindAsEventListener(this);
        this.mouseoverListener = this.enterHover.bindAsEventListener(this);
        this.mouseoutListener = this.leaveHoverNormal.bindAsEventListener(this);
 
        Event.observe(this.element, 'click', this.ondblclickListener);
        Event.observe(this.element, 'mouseover', this.mouseoverListener);
        Event.observe(this.element, 'mouseout', this.mouseoutListener);
      },
      enterEditMode: function(evt) 
      {
        if (this.saving) return;
        if (this.editing) return;
        this.editing = true;
        new Ajax.Request(
          this.json, 
          {
            parameters: this.options.callback('', ''),
            onSuccess:this.finishEnterEditMode.bind(this)
          }
        );
        return false;
      },
 
      finishEnterEditMode: function(response) 
      {
        var newData = eval(response.responseText);
        this.values = new Array();
        this.labels = new Array();
        var i = 0;
        var toSelect = 0;
        for (var value in newData) 
        {
          this.values.push(value);
          if (value == this.selected) toSelect = i;
          this.labels.push(newData[value]);
          i++;
        }
        Element.hide(this.element);
        this.createControls();
        this.element.parentNode.insertBefore(this.menu, this.element);
        this.menu.focus();
        if (this.options.cancelLink) 
        {
         this.element.parentNode.insertBefore(this.cancelButton, this.element);
        }
        this.menu.selectedIndex = toSelect;
        return false;
      },
      createControls: function() 
      {
        var options = new Array();
        for (var i=0;i<this.values.length;i++)
          options[i] = Builder.node('option', {value:this.values[i]}, this.labels[i]);
        this.menu = Builder.node('select', options);
        this.menu.onchange = this.onChange.bind(this);
 
        this.menu.onblur = this.onCancel.bind(this);
 
        for (var i=0;i<this.values.length;i++)
          if (this.labels[i]==this.element.innerHTML) 
          {
            this.menu.selectedIndex=i;
            continue;
          }
        if (this.options.cancelLink) 
        {
         this.cancelButton = Builder.node('a', this.options.cancelText);
         this.cancelButton.onclick = this.onCancel.bind(this);
        }
      },
      onCancel: function() 
      {
        this.cleanUp();
        this.leaveEditMode();
        return false;
      },
      onChange: function() 
      {
        var value = this.values[this.menu.selectedIndex];
        var text = this.labels[this.menu.selectedIndex];
        this.selected = value;
        this.onLoading(text);
        new Ajax.Request(
          this.url, Object.extend(
            {
              parameters: this.options.callback(value, text),
              onComplete: this.onComplete.bind(this),
              onFailure: this.onFailure.bind(this)
            },
            this.options.ajaxOptions
          )
        );
      },
 
      onLoading: function(text) 
      {
        this.saving = true;
        this.removeControls();
        this.leaveHover();
        this.showSaving(text);
      },
      removeControls:function() 
      {
        if(this.menu) 
        {
          if (this.menu.parentNode) Element.remove(this.menu);
          this.menu = null;
        }
        if (this.cancelButton) 
        {
          if (this.cancelButton.parentNode) Element.remove(this.cancelButton);
          this.cancelButton = null;
        }
      },
      showSaving:function(text) 
      {
       this.oldInnerHTML = this.element.innerHTML;
        this.element.innerHTML = text;
        this.element.style.backgroundColor = this.options.highlightcolor;
        Element.show(this.element);
      },
      onComplete: function(transport) 
      {
        this.options.onSuccess(transport);
        this.cleanUp();
      },
      cleanUp: function() 
      {
        this.leaveEditMode();
        new Effect.Highlight(
          this.element, 
          {
            startcolor: this.options.highlightcolor,
            endcolor: this.options.highlightendcolor,
            restorecolor: this.originalBackground
          }
        );
      },
      onFailure: function(transport) 
      {
        this.options.onFailure(transport);
        if (this.oldInnerHTML) 
        {
          this.element.innerHTML = this.oldInnerHTML;
          this.oldInnerHTML = null;
        }
        return false;
      },
      enterHover: function() 
      {
        if (this.saving) return;
        this.element.style.backgroundColor = this.options.highlightcolor;
        if (this.effect) { this.effect.cancel(); }
        Element.addClassName(this.element, this.options.hoverClassName)
      },
      leaveHoverNormal: function() 
      {
        if (this.saving) return;
        this.element.style.backgroundColor = this.originalBackground;
      },
      leaveHover: function() 
      {
        if (this.options.backgroundColor) 
        {
          this.element.style.backgroundColor = this.oldBackground;
        }
        Element.removeClassName(this.element, this.options.hoverClassName)
        if (this.saving) return;
        this.effect = new Effect.Highlight(
          this.element, 
          {
            startcolor: this.options.highlightcolor,
            endcolor: this.options.highlightendcolor,
            restorecolor: this.originalBackground
          }
        );
      },
      leaveEditMode:function(transport) 
      {
        this.removeControls();
        this.leaveHover();
        Element.show(this.element);
        this.editing = false;
        this.saving = false;
        this.oldInnerHTML = null;
      }
    }
 

Now you need 3 actions

First one to build your complete HTML page:

...
    executeShow()
    {
      $this->article = Article::retrieveByPk(1);
    }
    ...
 

and the according template showSuccess.php:

<?php use_helper('AjaxInplaceSelect') ?>
<h1><?php echo $article->getName() ?></h1>
<strong>author:</strong> <?php echo input_in_place_select_tag(
  'author_dom_id', 
  $article->getAuthor()->getName(), 
  'module/updateChanges', 
  'module/jsonUpdate', 
  $article->getAuthor()->getId(), 
  array(), 
  array('callback' => 'function(value, text) { return \'author_id=\'+value+\'&article='.$article; }')); 
?>

Then the second action will generate the data to show in select field when clicking on the author. The data is passed to the InplaceSelect as JSON code:

...
    executeJsonUpdate()
    {
      $authors = Author::doSelect(new Criteria());
      $data = array():
      foreach($authors as $author)
      {
        $data[$author->getId()]=$author->getName();
      }
      $this->renderText('('.json_encode($data).')');
    }
    ...
 

And finally still the action that is receiving the change and saving it

...
    executeUpdateChanges()
    {
      $newAuthorId = $this->getRequestParameter('author_id');
      $articleId = $this->getRequestParameter('article');
 
      $article = Article::retrieveByPk($articleId);
      $article->setAuthorId($newAuthorId );
      $article->save();
      $this->renderText('');
    }
    ...
 

That's it! Now the InplaceSelect should work fine. After clicking an option of the select field, it transforms back to normal text which show now the selected option. Instead of only pass over the text of the option, of course you can specify something else. For example if you normally show beside the author name also the number of books written by him, you do not need to show all this information also in the select field in order to still have this information for a new selected author. Therefore you can define a onSuccess function when calling the helper in the showSuccess template:

<?php use_helper('AjaxInplaceSelect') ?>
<h1><?php echo $article->getName() ?></h1>
<strong>author:</strong> <?php echo input_in_place_select_tag(
  'author_dom_id', 
  $article->getAuthor()->getName() . ' [' . $article->getAuthor()->getNumberOfBooks() . ' Book(s)]', 
  'module/updateChanges', 
  'module/jsonUpdate', 
  $article->getAuthor()->getId(), 
  array(), 
  array(
    'onSuccess' => 'onSuccess' => 'function(transporation) { $(\'author_dom_id\').innerHTML = transporation.responseText; }',
    'callback' => 'function(value, text) { return \'author_id=\'+value+\'&article='.$article; }')
  ); 
?>

and when saving the changes render the more detailed Author info:

...
    executeUpdateChanges()
    {
      $newAuthorId = $this->getRequestParameter('author_id');
      $articleId = $this->getRequestParameter('article');
 
      $article = Article::retrieveByPk($articleId);
      $article->setAuthorId($newAuthorId );
      $article->save();
      $this->renderText($article->getAuthor()->getName() . ' [' . $article->getAuthor()->getNumberOfBooks() . ' Book(s)]');
    }
    ...
 

There are still some more option which you can use, check helper the source code.

Enjoy the InplaceSelect!

by Thomas Eigner on 2007-09-17, tagged ajax  inplaceselect  javascript 
(3 comments)

Define indicator for all ajax requests

I've found it annoying to set the show and hide commands on each remote request. So I've used this to define it globally:

/*
 * Defines the indicator globally
 */ 
Ajax.Responders.register({
  onCreate: function() { Element.show('indicator'); },
  onComplete: function() { Element.hide('indicator'); }
});
 
by Halil Köklü on 2007-09-16, tagged ajax  javascript 
(2 comments)

AJAX Degredation Helper that creates
tags with fragments inside

This helper creates a div tag tag into which links can call other actions and dynamically display its output via AJAX. When JS is not enabled, the links reload the page with GET parameters and allow this helper to load the output.

What do you think of this code? First of all, has it already been done before? And do you think it will actually be useful? How well does it conform to the MVC structure?

Actual code:

<?php
/**
 * This file includes functions that assist in making AJAX degradable
 *
 * These small helper functions add in some of the basic features that allow for degradable
 * JS. The idea is to dynamically load contents when JS is available and let the page reload with
 * appropriate html when JS is not.
 * @author Yining Zhao
 * @package YZ_Helpers
 * @subpackage AJAX_Degredation
 * @since 1/16/2007
 */
 
/**
 * This class creates a pair of <div> tags in which AJAX functions can input dynamic HTML.
 *
 * Usually what happends is that a link is pressed to activate the AJAX command via its onClick method.
 * The HREF attribute is suppressed by a 'return false;' at the end of the onClick method. However
 * when JS is not available, the onClick method is not activated and thus the HREF is called. The 
 * link in the HREF reloads the page and uses GET to pass along the variables to load the designated
 * fragment.
 *
 * If the $trigger_var is 'login_box', here is what the following GET parameters will do:
 *      login_box_display will load the fragment if it is set to 'on', otherwise div style = visibility:none and nothing is loaded
 *          e.g. URL: www.website.com/file.php?login_box_display=on //will load fragment
 *
 *      login_box_make_persistant will let set login_box_display to 'on' in the user session, so as long as
 *          login_box_make_persistant is not set to 'no', the fragment will automatically be loaded on every page 
 *          load regardless of the GET statement
 *          e.g. URL: www.website.com/file.php?login_box_make_persistant=on //will load fragment on every page load
 * 
 * Sample usage of function:
 *      //This function is being called from listSuccess.php template file in my Post module    
 *      div_fragment_creater('login_box','partial','loginPartial',array('referer'=>$referer),array('id'=>'login_div_id'))
 *
 * The source: {@source} 
 *
 * @param string $trigger_var The variable passed via GET that determines if the partial is loaded
 * @param string $fragment_type This tells the function if you are using a partial or a component
 * @param string $fragment_filename The name of the fragment to be called
 * @param array $fragment_values_ary This passes in the values for the fragment
 * @param array $div_attr_ary This contains all the html attributes for the <div> tag
 * @return void Since this function is designed to echo the necessary html, return is void
 */
function div_fragment_creater($trigger_var,$fragment_type, 
                                    $fragment_filename,$fragment_values_ary,$div_attr_ary)
{
    $sf_user=sfContext::getInstance()->getUser()->getAttributeHolder();
    $sf_params=sfContext::getInstance()->getRequest()->getParameterHolder();
    //If in the GET there is a make_persistant command for the given trigger variable, then the display command for the
    //tigger is set for sessions
    if($sf_params->get($trigger_var.'_make_persistant')=='on')
    {
        $sf_user->set($trigger_var.'_display','on');
    } else if($sf_params->get($trigger_var.'_make_persistant')=='off')
    {
        $sf_user->remove($trigger_var.'_display');
        $sf_params->remove($trigger_var.'_display');
    }
    //If the display is set for the trigger in either sf_params or sf_user, display the fragment.
    //Otherwise, don't display the fragment and make the div attribute style = display:none
    $output_fragment=false;
    if(($sf_params->get($trigger_var.'_display')=='on')||($sf_user->get($trigger_var.'_display')=='on'))
    {
        $output_fragment=true;
 
    } else
    {
        $div_attr_arry['style'] = 'display:none';
    }
 
    $div_attr_keys = array_keys($div_attr_ary);
    $div_attr_ary_size = count($div_attr_keys);
    $div_attr='';
    $div_attr_collection='';
    //Cteates the attributes for the <div>
    for($i=0;$i<$div_attr_ary_size;$i++)
    {
        //This creates a string where the div attribute is set to its corresponding value; e.g. id=5
        $div_attr_name = $div_attr_keys[$i];
        $div_attr_collection.=$div_attr_name . ' = "' . $div_attr_ary[$div_attr_name] . '" ';
    }
    echo '<div '.$div_attr_collection.' >';
    if($output_fragment==true)
    {
        switch($fragment_type)
        {
            case 'partial':
                echo include_partial($fragment_filename, $fragment_values_ary);
                break;
            case 'component':
                use_component($fragment_filename, $fragment_values_ary);
                break;
        }
    }
    echo '</div>';
}
?>

Usage Example: In myApp/myModule/list.php:

<body>
Anything is possible...
<?php 
//Creates div with id = myDiv. Usually this div is invisible and empty. But when the get or session variable of triggerVar_display is set to 'on', this div becomes visible and displays the whatsPossiblePartial partial file.
div_fragment_creater('triggerVar','partial','whatsPossiblePartial',array('id'=>$id),array('id'=>'myDiv'))
 
//Provides link to load action into myDiv. If JS is not enabled, link will reload page with triggerVar_display set to 'on'
 
echo link_to_remote('Click To See Whats Possible', array(
            'url'=>'MyModule/WhatPossible?id='.$value,
            'update'=>array('success' => 'myDiv'),
            'loading'=>"Element.show('indicator')",
            'complete'=>visual_effect('blind_down','myDiv',array('duration'=>0.5))';',
            ),          array('href'=>'list?triggerVar_display=on'));
?>
</body>

Inside the whatPossibleSuccess.php:

<html> ...
<?php 
//This file is basically just a wrapper for the whatsPossiblePartial. the reason I have this wrapper is so that I can access it from via link_to_remote() on other pages.
echo include_partial(whatsPossiblePartial,array('id'=>$this->id));
?>
...
</html>
by whoknows on 2007-01-18, tagged ajax  degradation  helper  javascript 

cascading combo 2-level mulit-select list

There are two multi-select box, the first one is parent list menu, the second one is child menu; when clicking item in first list, its submenu will appear in second list, then you can multi-select from 2nd list; and you can multi-select items in 1st list by clicking, double-click, ctrl+click, shift+click, all selected items in 1st list will display their children in 2nd list, all deselected items from 1st list will remove their children from 2nd list. This combo list can be used for select HOBBIES, TYPES, CATEGORIES etc.

*** in multiselSuccess.php:

<script type="text/javascript" src="/sf/js/prototype/prototype.js"></script>
<body onload="new Ajax.Request('/news/select/level/province', {asynchronous:true, evalScripts:false, onComplete:function(request, json){updateJSON(request,json,1)}}); return false;" >

*** in multiselSuccess.php:

<?php
            echo select_tag("province",options_for_select(Array(''=>'-Select-')),'multiple=multiple size=10  onmousedown=GetCurrentListValues(this); onchange=javascript:loadCity(\''.sfConfig::get('app_site_url').'news/select/level/city\',this)');
            echo select_tag('city[]',options_for_select(Array(''=>'-Select-')),'multiple=multiple size=10');
            ?>
            <div id=statusTxt></div>

*** in view.yml:

selectSuccess:
  has_layout: off

*** javascript can be written in multiselSuccess.php, or in another javascript file multiselSuccess.js: if written in a seperate file multiselSuccess.js, put it under PROJECT_NAME\web\js\, and in ...\apps\APPLICATION_NAME\config:

    javascripts:    [multiselSuccess.js ]

<script language="javascript">
<!--//
/**
 * ajax no refresh cascading 2-level menu
 *
 */
function loadCity(url,CONTROL) {                            //load city
 
    var strTmp=provinceChanged(CONTROL);                    //result format: +provinceId or -provinceId
    var provChg=strTmp.split(",");
    url=url+"/id/"+provChg[0];                              //provChg[0]: item value of first menu; url: /news/select/level/city/id/ItemValueOfFirstMenu
    new Ajax.Request(url, {asynchronous:true, evalScripts:false, onComplete:function(request, json){updateJSON(request,json,2,provChg[1])}});
    return false;
}
 
var arrOldValues;
function GetCurrentListValues(CONTROL){
    var strValues = "";
    strValues = GetSelectValues(CONTROL);
    arrOldValues = strValues.split(",")
}
 
function GetSelectValues(CONTROL){
    var strTemp = "";
    for(var i = 0;i < CONTROL.length;i++){
        if(CONTROL.options[i].selected == true){
            strTemp += "1,";
        }
        else{
            strTemp += "0,";
        }
    }
    return strTemp;
}
 
function provinceChanged(CONTROL){
    var strTemp = GetSelectValues(CONTROL);
    arrNewValues = strTemp.split(",");
    var sum=0;
    for(var i=0;i<arrNewValues.length-1;i++){
        sum+=eval(arrNewValues[i]);
        if (sum >= 2){                                      //more than 1 are selected
            break;
        }
        if (arrNewValues[i] == 1){                          //when this condition is met, sum must be 1
            var selectedPos=i;
        }
    }
 
    if (sum==0){                                            //deselect all by ^Click; remove all from 2nd menu
        provChg=""+",--";
    }
    else if (sum==1){                                       //only one selected, click or ctrl+click
        if (arrOldValues[selectedPos] == 0){                //if this selcted one wasn't selected before, just add;
                                                            //at this point,arrNewValues[selectedPos] must be 1
            removeOptionAll("city");
            provChg=CONTROL.options[selectedPos].value+",+";
        }
        else{               //if this selcted one was selected before, remove all others but keep selected of this one
            removeOptionAll("city");
            provChg=CONTROL.options[selectedPos].value+",+";        //???to simplify, just add, previously selected may be lost
        }
    }
    else{       //
        for(var i=0;i<arrNewValues.length-1;i++){
            if (arrNewValues[i] != arrOldValues[i]){
                if (arrNewValues[i]==1){                    //add a new province
 
                    provChg=CONTROL.options[i].value+",+";
                }
                else{                                       //remove a new province
                    provChg=CONTROL.options[i].value+",-";
                }
            }
        }
    }
    return provChg;
}
 
/**
 * ajax no refresh 2-level cascading menu
 *
 */
function addOption(objSelectNow,txt,val)
{
    //using W3C syntax add Options for SELECT
    var objOption = document.createElement("OPTION");
    objOption.text= txt;
    objOption.value=val;
    objSelectNow.options.add(objOption);
}
 
function addOptionGroup(selectId,optGroup)
{
    var objSelect = document.getElementsByTagName("SELECT");
    var objSelectNow = objSelect[selectId];
 
    if (selectId=="province"){
        objSelectNow.length = 1;
    }
        /// add Options group
        for (i=0; i<optGroup.length; i++)
        {
            addOption(objSelectNow, optGroup[i][1], optGroup[i][0]);
        }
 
}
 
 
function removeOptionGroup(selectId,optGroup)                   //optGroup: array of 2nd menu corresponding to deselected item of 1st menu; categoryId=>categoryName
{
    var objSelect = document.getElementsByTagName("SELECT");
    var objSelectNow = objSelect[selectId];
 
    for (i=0;i<objSelectNow.length;i++){
        if (objSelectNow.options[i].value==optGroup[0][0]){     //the first position to be removed
            var bgn=i;
            break;
        }
    }
 
    /// remove Options
    for (i=0;i<optGroup.length;i++){
        objSelectNow.options.remove(bgn);
    }
}
 
function removeOptionAll(selectId)
{
    var objSelect = document.getElementsByTagName("SELECT");
    var objSelectNow = objSelect[selectId];
    for (i=1;i<objSelectNow.options.length;){
        objSelectNow.options.remove(1);
    }
}
 
function updateJSON(request, json,level,operation){
    var responses = json;
    if (!json){
      //if you don't use the json tips then evaluate the renderedText instead
      var responses = eval('(' + request.responseText + ')');
    }
    if (level==1)                                       //for 1st menu
        addOptionGroup("province",responses);
    else if (level==2){                                 //for 2nd menu
        if (operation=="+"){
            addOptionGroup("city",responses);
        }
        else if (operation=="-"){
            removeOptionGroup("city",responses);
        }
        else if (operation=="--"){
            removeOptionAll("city");
        }
    }
}
 
-->
</script>

*** in actions.classs.php:

public function executeSelect(){
    /**
     * ajax no refresh 2-level cascading menu back-end
     *
     */
    //load data:
 
    $c=new Criteria();
    $c->add(CategoryPeer::PARENT_ID,NULL);                  //get contents for 1st menu
    $categories=CategoryPeer::doSelect($c);
    $parent="";
    if ($categories){
        $i=0;
        $parent='[';
        foreach ($categories as $category){
            $name=$category->getName();
            $id=$category->getId();
            $parent=$parent.'["'.$id.'","'.$name.'"],';     //format for 1st menu: [["1","German"],["2","France"],["3","Argentina"]]
 
            //retrive records whose parent_id is..
            $c=new Criteria();
            $c->add(CategoryPeer::PARENT_ID,$category->getId());
            $categories_sub=CategoryPeer::doSelect($c);
            $city[$id]='[';                                  //index of $city[] is category id; format of $city[]:[["48","Team1.Fr"],["49","Team2.Fr"],["50","Team3.Fr"],["51","Team4.Fr"],["52","Team5.Fr"]]
            foreach ($categories_sub as $category_sub){
                $city[$id]=$city[$id].'["'.$category_sub->getId().'","'.$category_sub->getName().'"],';
            }
            $city[$id]=rtrim($city[$id],",");
            $city[$id].=']';
            $i++;
        }
    }
    $parent=rtrim($parent,",");
    $parent.=']';
 
    $level=$this->getRequestParameter('level');
    if($level=="province"||$level==""){     //level=province, output contents for first menu
         $this->output=$parent;
    }
    else if($level=="city"){                //level=city, output contents for second menu
        $id=$this->getRequestParameter('id');
        $this->output=$city[$id];
    }
    else{                                   //false
        $this->output="error when getting data";
    }
    return sfView::SUCCESS;
}

*** in selectSuccess.php:

<?php
echo $output;
?>
by William Duan on 2007-01-04, tagged ajax  javascript 
(1 comment)

process XMLHttpRequest

function process(feeder, wrapper, method, content) {
    xmlhttp = getxmlhttp();
    if(method == "GET") {
        xmlhttp.open("GET", feeder,true);
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                wrapper.innerHTML = xmlhttp.responseText;
            }
        }
 
        xmlhttp.send(null);
    } else {
        xmlhttp.open("POST", feeder, true);
        xmlhttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=iso-8859-1");
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                wrapper.innerHTML = xmlhttp.responseText;
                dumpingData();
                //toogleEditorMode('contenttext');
            }
        }
        xmlhttp.send(content);
    }
}
 
/***** USAGE
obj = document.getElementById('content');
process ("feeder.php?go="+obj.value, obj, "GET", "");
*****/
by Ken Vu on 2006-12-16, tagged ajax  javascript  process  xmlhttprequest 
(3 comments)

initiate new XMLHttpRequest object - browser crossing

function getxmlhttp() {
    //Create a boolean variable to check for a valid IE instance.
    var xmlhttp = false;
 
    //Check if we are using IE.
    try {
        //If the javascript version is greater than 5.
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        //If not, then use the older active x object.
        try {
            //If we are using IE.
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (E) {
            //Else we must be using a non-IE browser.
            xmlhttp = false;
        }
    }
 
    //If we are using a non-IE browser, create a JavaScript instance of the object.
    if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
        xmlhttp = new XMLHttpRequest();
    }
 
    return xmlhttp;
}
by Ken Vu on 2006-12-16, tagged ajax  javascript  new  object  xmlhttprequest 

initiate new XMLHttpRequest object - browser crossing

function getxmlhttp() {
    //Create a boolean variable to check for a valid IE instance.
    var xmlhttp = false;
 
    //Check if we are using IE.
    try {
        //If the javascript version is greater than 5.
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        //If not, then use the older active x object.
        try {
            //If we are using IE.
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (E) {
            //Else we must be using a non-IE browser.
            xmlhttp = false;
        }
    }
 
    //If we are using a non-IE browser, create a JavaScript instance of the object.
    if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
        xmlhttp = new XMLHttpRequest();
    }
 
    return xmlhttp;
}
[/code/
by Ken Vu on 2006-12-16, tagged ajax  javascript  new  object  xmlhttprequest 
(2 comments)

Add aditional parameters to Autocomplete

You can pass aditional parameters to input_auto_complete_tag helper. By default, autocompleter pass only object-referer value. For aditional parameter you need use 'with' in $completion_options array. in view layer:

<
<?php echo object_input_tag($model, 'getFilter', array ('size' => 20, 'control_name' => 'filter',));?>
?php echo input_auto_complete_tag('field_to_search','','module/autocomplete', array('autocomplete'=>'off'),array('use_style'=>true,'with'=> " value+'&filter='+$('filter').value"))?>

you must put '" value' (with whitespace) because javascript fail (a little symfony bug). Aditional parameters must go after value.

in control layer:

 public function executeAutocomplete(){
    $search=$this->getRequestParameter('field_to_search');
    $filter=$this->getRequestParameter('filter');
....
}

now you can use field_to_search and filter to construct any query in model layer ans show this in AutocompleteSuccess.php view or another view that you define. this was tested in synfony version > 0.9. Check your version, and review your javascripthelper helper to verify if your input_auto_complete_tag helper supports 'with' option

by Boris Duin on 2006-10-27, tagged ajax  autocomplete  javascript 

How to perform an action when input_date_tag changes.

What is worth noting in the snippet below is the usage of the 'onchange'=> remote_function( ... you can use the remote_function in many places to call other functions ... like in the "update", "complete" etc...

<div id="js_updating">Stand by..</div>
<?php echo form_tag('/module/action', 'method=get class=simpleForm') ?>
Please select the day:
<?php
echo input_date_tag('day', 'now', array('rich' => true, 'readonly'=>true, 'onchange'=> remote_function( array(
      'update'   => 'Area To Update (DIV TAG)',
      'url'      => 'MODULE/ACTION',
      'loading'  => "Element.show('js_updating')",
      'complete' => "Element.hide('js_updating')"
  ))));
 
?>
 
</form>
by Fuad Arafa on 2006-08-23, tagged ajax  forms  javascript 
(2 comments)