OxyScripts.com
Menu spacer Home Tutorials Articles Code Forums irc.freenode.net #oxyscripts
Main (PHP)
Home Forums PHP News PHP Tutorials Articles PHP Code Snippets Contact Us Sysadmin Resources Books Template Shop
3rd Party Streams
SlashDot PHPDeveloper.org PHP.Net
Resources
PHP Manual MySQL Manual Smarty Manual PEAR Manual PHP-GTK Manual Symfony Manual
Code Snippets
Authentication Database Graphics HTTP Miscellaneous Time/Date
Affiliates
Scripts TutorialMan TutorialGuide CodingForums.com PHP Scripts Cheap Web Hosting Affordable Web Hosting Dreamweaver Templates

Search This Site :     PHP Function Reference :
 

JavaScript helpers

Overview

Interactions on the client side, complex visual effects or asynchronous communication are common in web 2.0 applications. All that require JavaScript, but coding it by hand is often cumbersome and long to debug. Fortunately, symfony automates many of the common uses of JavaScript in the templates.

Introduction

JavaScript has long been considered as a candy for beginners, without any real use in professional web applications due to the lack of compatibility between browsers. In the late 90s, the word 'DHTML' meant 'unreadable HTML code with embedded JavaScript written three times for compatibility', and it sometimes referred to dynamic web pages that didn't work.

These days are now over, since the compatibility issues are (mostly) solved and some robust libraries allow to program complex interactions in JavaScript without the need for 200 lines of code and 20 hours of debugging. The most popular advance is called AJAX, and will be treated a little further.

For now, all you need to know is... JavaScript. Or maybe forget a little about it, because what will be shown below is how NOT to use JavaScript to do what you would expect JavaScript for. Just reconsider this scripting language as an opportunity to manipulate the DOM on the client side, with all the power that it gives.

All the helpers described here are available in templates provided you declare the use of the Javascript helper:

<?php echo use_helper('Javascript') ?>

Some of them output HTML code, some of the output JavaScript code. It will be specified for each of them.

Basic helpers

Clean XHTML JavaScript inclusion

If you want to write a piece of JavaScript code in your page, instead of writing manually something like:

<script type="text/javascript">
//<![CDATA[ 
  function foobar()
  {
  ...
  }      
//]]>
</script>

You could try the javascript_tag() function:

<?php echo javascript_tag("
  function foobar()
  {
  ...
  }          
") ?>

Link behavior

The most common use of JavaScript is in a hyperlink that triggers a particular script. In HTML, you would probably write it like that:

<a href="#" onClick="alert('foobar');return none;">Click me!</a>

Symfony proposes a helper to write it in a more concise way, the link_to_function():

<?php echo link_to_function("Click me!", "alert('foobar')") ?>

Like the link_to() URL helper, you can add options to the <a> tag generated by a link_to_function():

<?php echo link_to_function("Click me!", "alert('foobar')", "class=mylink style=color:#f00 alt=please click me" ) ?>

Note: Just like the link_to() helper has a button_to() brother, you can trigger a JavaScript from a button (<input type="button">) by calling the button_to_function() helper. And if you prefer a clickable image, just call link_to_function(image_tag('myimage'), "alert('foobar')").

Updating an element

One common task in applications that use JavaScript a lot is the update of an element in the page. This is something that you usually write:

<?php echo javascript_tag("
  document.getElementById("indicator").innerHTML = "<strong>Evacuation complete</strong>";
") ?>

Symfony provides a helper that produces JavaScript - not HTML - for this purpose, and it's called update_element_function():

<?php echo javascript_tag(
  update_element_function('indicator', array(   
    'content'  => "<strong>Evacuation complete</strong>",
  ))
) ?>

You may ask: What's the interest of a helper if it is longer to write than the normal code? Sometimes, you want to insert content before an element, or after it; you may also want to remove an element instead of just updating it, or to do nothing according to a condition. In these cases, the JavaScript code becomes somehow messier, but the update_element_function() keeps very readable:

// insert content just after the 'indicator' element
update_element_function('indicator', array(
  'position' => 'after',      
  'content'  => "<strong>Evacuation complete</strong>",
));
 
// remove the element before the 'indicator' element, and only if $condition is true
update_element_function('indicator', array(
  'action'   => $condition ? 'remove' : 'empty',
  'position' => 'before',      
))

The helper makes your templates easier to understand than any JavaScript code, and you have one single syntax for similar behaviors. That's also why the helper name is so long: It makes the code self-sufficient, without the need of extra commentaries.

Graceful degradation

You already know how to qualify some HTML code to make it executed only by browsers with no JavaScript support, using the <noscript> tags. What if you could do it the other way around, i.e. qualify some code so that it is executed only by browsers actually supporting JavaScript? Symfony provides two helpers just for that, and it facilitates the creation of applications that degrade gracefully.

<?php if_javascript(); ?>
  <p>You have JavaScript enabled.</p>
<?php end_if_javascript(); ?>
 
<noscript>
  <p>You don't have JavaScript enabled.</p>
</noscript>
 

Note: You don't need to include the echo when calling these two helpers.

AJAX helpers

What if the function updating an element of the page was not in a JavaScript, but a PHP script executed by the server? This would give you the opportunity to change part of the page according to a server response. The remote_function() does exactly that:

<?php echo javascript_tag(
  remote_function(array(   
    'update'  => 'myzone',
    'url'     => 'mymodule/myaction',
  ))
) ?>

When called, this script will update the element of id myzone with the response or the request of the mymodule/myaction action. This kind of interaction is called AJAX, and it's the heart of highly interactive web applications. Here is how Wikipedia describes them:

AJAX makes web pages feel more responsive by exchanging small amounts of data with the server behind the scenes, so that the entire web page does not have to be reloaded each time the user makes a change. This is meant to increase the Web page's interactivity, speed, and usability.

AJAX relies on XMLHttpRequest, a JavaScript object that behaves like a hidden frame, which you can update from a server request and reuse to manipulate the rest of your web page.

An AJAX interaction is made up of three parts: a caller (a link, a button or any control that the user manipulates to launch the action), a server action, and a zone in the page to display the result of the action to the user. Symfony provides multiple helpers to insert AJAX interaction in your templates by putting the caller in a link, a button, a form, or a clock. Beware that this time, these helpers output HTML code, not JavaScript.

For instance, imagine a link that would call a remote function. Symfony writes it like this:

<?php echo link_to_remote('Delete this post', array(
    'update' => 'indicator',
    'url'    => 'post/delete?id='.$post->getId(),
)) ?>
 
<?php echo link_to_remote(image_tag('refresh'), array(
    'update' => 'emails',
    'url'    => '@list_emails',
)) ?>

Notice that the url parameter can contain either an internal URI (module/action?parameters) or a routing rule, just like in a regular link_to(). The askeet tutorial has other examples of link_to_remote() uses.

Note: Actions called as remote functions know that they are in an AJAX transaction, and therefore automatically don't include the web debug toolbar in development and skip the decoration process (i.e. their template is not included in a layout by default). This means that if you want an AJAX view to be decorated, you need to specify explicitly layout: foobar for this view in the module view.yml.

The second popular way of interacting with web pages is forms. Forms normally call a remote function, but this causes the refreshing of the whole page. The correspondence of the link_to_function() for a form would be that the form submission only updates an element in the page with the response of the server. This is what the form_remote_tag() helper does.

<?php echo form_remote_tag(array(
    'update'   => 'item_list',
    'url'      => '@item_add',
)) ?>
  <label for="item">Item:</label>
  <?php echo input_tag('item') ?>
  <?php echo submit_tag('Add') ?>
</form>

A form_remote_tag() opens a <form>, just like the form_tag() helper does. You are invited to use the symfony form helpers in AJAX forms as well as in regular forms.

If you want to allow a form to work both in page mode and in AJAX mode, the best solution is to define it like a regular form, but to provide, in addition to the normal submit button, a second button (<input type="button" />) to submit the form in AJAX - symfony calls it a submit_to_remote(). This will help you build AJAX interactions that degrade gracefully.

<?php echo form_tag('@item_add_regular') ?>
  <label for="item">Item:</label>
  <?php echo input_tag('item') ?>
  <?php echo submit_tag('Add') ?>
  <?php echo submit_to_remote('ajax_submit', 'Add in AJAX', array(
      'update'   => 'item_list',
      'url'      => '@item_add',
  )) ?>
</form>

Modern forms can also react not only when submitted, but also when the value of a field is being updated by a user. In symfony, you use the observe_field() helper for that:

<?php echo form_tag('@item_add_regular') ?>
  <label for="item">Item:</label>
  <?php echo input_tag('item') ?>
  <?php echo submit_tag('Add') ?>
  <?php echo observe_field('item', array(
      'update'   => 'item_suggestion',
      'url'      => '@item_being_typed',
  )) ?>
</form>

The module/action written in the @item_being_typed rule will be called each time the item field changes, and the action will be able to get the current item value from the value request parameter. If you want to pass something else than the value of the observed field, you can specify it as a JavaScript expression in the with parameter. For instance, if you want the action to get a param parameter, write the observe_field() helper as follows:

<?php echo observe_field('item', array(
      'update'   => 'item_suggestion',
      'url'      => '@item_being_typed',
      'with'     => "'param=' + value",
  )) ?>

Note that this helper doesn't output an HTML element, but a behavior for the element passed as parameter. You will see below more examples of JavaScript helpers assigning behaviors.

If you want to observe all the fields of a form, you'd better use the observe_form() helper, which calls a remote function each time one of the form fields is modified.

Last but not least, the periodically_call_remote() helper is an AJAX interaction triggered every x seconds. It is not attached to a HTML control, but runs transparently in the background, as a behavior of the whole page. This can be of great use to track the position of the mouse, autosave the content of a large textarea, etc.

<?php echo periodically_call_remote(array(
    'frequency' => 60,
    'update'    => 'notification',
    'url'       => '@watch',
    'with'      => "'param=' + $('mycontent').value",
)) ?>

If you don't specify the number of seconds (frequency) to wait between two calls to the remote function, the default value of 10 is taken.

Note: The AJAX helpers won't work if the URL of the remote action doesn't belong to the same domain as the current page. This restriction exists for security reasons, and relies on browsers limitations that cannot be bypassed.

Prototype

Prototype is a great JavaScript library that extends the possibilities of the client scripting language, adds the missing functions you've always dreamt of, and offers new mechanisms to manipulate the DOM.

The Prototype files are present in the symfony framework data/web/sf/js/ directory. This means that you can use Prototype by adding in your action:

$this->getResponse()->addJavascript('/sf/js/prototype/prototype');

...or by adding it in the view.yml:

all:
  javascripts: [/sf/js/prototype/prototype]

Note: Since the symfony AJAX helpers themselves use Prototype, as soon as you add a remote call to a template through a symfony helper, you also include automatically the Prototype library.

Once the Prototype library is loaded, you can take advantage of all the new functions it adds to the JavaScript core. It is not the purpose of this documentation to describe them all, and you will easily find on the web good documentations of Prototype (for instance ParticleTree's doc, Sergio Pereira's doc or the one from script.aculo.us). But as our latest example used the dollar ($()) function, let's just have a look at it:

// In JavaScript,
node = $("elementID");
// means the same as 
node = document.getElementById("elementID");

Other than being short and sweet, the $() function makes it short to find something in the DOM, and it is also more powerful than document.getElementById() because of its ability to retrieve multiple elements.

allNodes = $("firstDiv", "secondDiv");

Because programming in JavaScript with Prototype is much more fun than doing it by hand, and because it is also part of symfony, you should really spend a few minutes to read the related documentation.

Remote calls parameters

All the AJAX helpers described above can take other parameters, in addition to the update and url parameters.

Position

Just like you did in the update_element_function() helper, you can specify the element to update as relative to a specific element by adding a position parameter:

<?php echo link_to_remote('Delete this post', array(
    'update'   => 'indicator',
    'url'      => 'post/delete?id='.$post->getId(),
    'position' => 'after',
)) ?>

This will insert the result of the AJAX call after the indicator element. With this method, you can do several AJAX calls and see the answers pile down the update element.

The position parameter can be defined as:

Value Position
before Before the element
after After the element
top at the top of the content of element
bottom at the bottom of the content of element

Conditions

A remote call can take an additional parameter to allow a confirmation of the user before actually submitting the XMLHttpRequest:

<?php echo link_to_remote('Delete this post', array(
    'update'   => 'indicator',
    'url'      => 'post/delete?id='.$post->getId(),
    'confirm'  => 'Are you sure?',
)) ?>

A JavaScript dialog box showing 'Are you sure?' will pop-up when the user clicks on the link, and the post/delete action will be called only if the user confirms his choice by clicking 'Ok'.

The remote call can also be conditioned by a test performed on the browser side (in JavaScript):

<?php echo link_to_remote('Delete this post', array(
    'update'    => 'indicator',
    'url'       => 'post/delete?id='.$post->getId(),
    'condition' => "$('elementID') == true",
)) ?>

Method

By default, AJAX requests are made in post mode. If you want to make an AJAX call that doesn't modify data, or if you want to display a form that has built-in validation as the result of an AJAX call, you might need to change the AJAX request method to get. This is simpy done through the method option:

<?php echo link_to_remote('Delete this post', array(
    'update'    => 'indicator',
    'url'       => 'post/delete?id='.$post->getId(),
    'method'    => 'get',
)) ?>

Script execution

If the response code of the AJAX call (the code sent by the server, inserted in the update element) contains JavaScripts, you might be surprised to see that these scripts are not executed by default. This is to prevent remote attack risks, except if the developer knows for sure what code is in the response.

That's why you have to declare the ability to execute scripts in remote responses explicitly with the script option:

// If the response of the post/delete action contains JavaScript, allow them to be executed by the browser 
<?php echo link_to_remote('Delete this post', array(
    'update' => 'indicator',
    'url'    => 'post/delete?id='.$post->getId(),
    'script' => true,
)) ?>

If the remote response contains AJAX helpers (like, for instance, remote_function()), be aware that these PHP functions generate JavaScript code, and won't execute unless you add the 'script' => true option.

Note: Even if you enable script execution for the remote response, you won't actually see the scripts in the remote code - that is, if you use a tool to check the generated code. The scripts will execute but will not appear in the code. Although peculiar, this behavior is perfectly normal.

Callbacks

One important drawback of AJAX interactions is that they are invisible for the user until the zone to update is actually updated. This means that in case of slow network, or server failure, the user may believe that his action was taken into account while it was not.

This is why it is important to notify the users of the events of an AJAX interaction.

By default, each remote request is an asynchronous process during which various JavaScript callbacks can be triggered (for progress indicators and the likes). All callbacks get access to the 'request' object, which holds the underlying XMLHttpRequest. The callbacks correspond to the events of any AJAX interaction:

Callback Event
before before request is initiated
after immediately after request was initiated and before loading
loading when the remote document is being loaded with data by the browser
loaded when the browser has finished loading the remote document
interactive when the user can interact with the remote document, even though it has not finished loading
success when the XMLHttpRequest is completed, and the HTTP status code is in the 2XX range
failure when the XMLHttpRequest is completed, and the HTTP status code is not in the 2XX range
404 when the url returns a 404 status
complete when the XMLHttpRequest is complete (fires after success/failure if they are present)

For instance, it is very common to show a loading indicator when a remote call is initiated, and to hide it once the response is received. In a link_to_remote(), you can write it like that:

<?php echo link_to_remote('Delete this post', array(
    'update'   => 'indicator',
    'url'      => 'post/delete?id='.$post->getId(),
    'loading'  => "Element.show('indicator')",
    'complete' => "Element.hide('indicator')",
)) ?>

The show and hide methods, as well as the JavaScript Element object, are another useful addition of Prototype.

Visual effects

Symfony integrates the visual effects of the script.aculo.us library, to allow you to do more than show and hide divs in your web pages. You will find a good documentation on the effects syntax in the script.aculo.us wiki. Basically, they are JavaScript objects and functions that manipulate the DOM in order to achieve complex visual effects:

// highlights the element 'my_field'
Effect.Highlight('my_field', {startcolor:'#ff99ff', endcolor:'#999999'})

// Blinds down an element
Effect.BlindDown('id_of_element');

// Fades away an element
Effect.Fade('id_of_element', 
  { transition: Effect.Transitions.wobble })

Have a look at the combination effects demo to get a visual idea of what these functions do.

Symfony encapsulates these JavaScript objects in a helper called visual_effects(). It outputs JavaScript that can be used in a regular link:

<?php echo link_to_function("Show the secret div", visual_effect('appear', 'secret_div')) ?>
// will make a call to Effect.Appear('secret_div')

The visual_effects() helper can also be used in the AJAX callbacks:

<?php echo link_to_remote('Delete this post', array(
    'update'   => 'indicator',
    'url'      => 'post/delete?id='.$post->getId(),
    'loading'  => visual_effect('appear', 'indicator'),
    'complete' => visual_effect('fade', 'indicator').visual_effect('highlight', 'post_nb'),
)) ?>

Notice how you can combine visual effects by concatenating them in a callback.

JSON

AJAX helpers allow to update more than one element at a time, using the JSON syntax. For more information about it, check out the user submitted documentation in the symfony wiki.

Complex interactions

JavaScript also provides tools to build up complex interactions. But the complexity of the implementation makes it quite rare over the Internet, although examples like google suggest (for autocomplete input) or netvibes (for sortible lists) show that desktop-like interactions are now possible in web applications.

The script.aculo.us library provides high-level JavaScript functions that symfony integrates as helpers. They allow the following kind of interaction:

  • Autocomplete input: A text input that shows a list of words matching the user's entry while he/she types in. Examples of the use of the input_auto_complete_tag() helper in symfony can be found in the askeet tutorial.
  • Drag and Drop: The ability to grab an element, move it and release it somewhere else, for a real "put it there" feeling. Refer to the shopping cart tutorial for a step-by-step documentation on how to use draggable_element() and drop_receiving_element() - and a self explaining screencast.
  • Sortable lists: Another possibility offered by draggable elements is the ability to sort a list by moving its items. The sortable_element() helper adds the 'sortable' behavior to an item, and the symfony book has a dedicated sortable chapter dealing with this feature.
  • Edit in place: More and more web applications allow users to edit the content of pages directly in the page, without the need to redisplay the content in a form (see a demo here. the symfony helper that does it is the input_in_place_editor_tag().
 
   Print this page

Top Sponsor
Symantec\'s Norton SystemWorks 2006
Sponsors
CA
Sponsors
AdWords Dominator 125*125
Advertisting


Affiliates
VertexTemplates PHPFreaks CodeWalkers StarGeek DevScripts CGI & PHP Scripts PHP CMS Free Templates

Shopping Rebates   Sell It 4 You   Flash Page Counters   Get Insured
GPS Tracking Service   Charity Donate Info   Web Site Hosting   VOIP Service

Privacy Policy | Links | Site Map | Advertising

All content on OxyScripts.com is (©)2002-2007

 
Powered by Adrastea - Version 1.0.0. Copyright © Rune Solutions, 2004-2005