My Very First Steps with Zend_Dojo

Wednesday, August 20th, 2008

Even though I feel pretty tired this evening, I had to satisfy my curiosity and took a quick look at Zend_Dojo.

My first result: (Click on the picture to see the demo)

Looks quite nice. If you (like me) don’t know the Dojo Toolkit yet, you probably need some time to understand the documentation. It would have been easier to play around with Dojo independently from the Zend_Dojo stuff for some time, but as long as there is no time pressure on you, trial and error can be fun too. I simply tried to follow the Zend_Dojo documentation. First of all you need to tell the view object where it can find the Zend_Dojo ViewHelpers. I’m doing this in my bootstrap file (I’m using the default directory structure like it is described in the docs):

<?php
error_reporting(E_ALL|E_STRICT);
set_include_path('../library' . PATH_SEPARATOR . get_include_path());

require_once 'Zend/Loader.php';
Zend_Loader::registerAutoload();

$layout = Zend_Layout::startMvc();
// Tell the view where it finds Zend_Dojo ViewHelper
$layout->getView()->addHelperPath('Zend/Dojo/View/Helper/', 'Zend_Dojo_View_Helper');

$front = Zend_Controller_Front::getInstance();
$front->addControllerDirectory('../application/controllers');
$front->throwExceptions(true);
$front->dispatch();

Next step is to include the Dojo library. Because this belongs into the <head> part of your HTML document, I’m changing my layout file (layout.phtml):

<?php echo $this->doctype() ?>
<html>
<head>
    <title>roetgers.org Dojo Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <?php
    // My own stylesheet
    echo $this->headLink()->setStylesheet('/css/my.css');
    // Check if dojo library is needed
    if ($this->dojo()->isEnabled()):
        // Include dojo library
        $this->dojo()->setLocalPath('/js/dojo/dojo.js')
            // Use dojo theme tundra
            ->addStyleSheetModule('dijit.themes.tundra');
        // Echo out the dojo <script> tags
        echo $this->dojo();
    endif; ?>
</head>
<!-- Set body class to "tundra" -->
<body class="tundra">
<?php echo $this->layout()->content ?>
</body>
</html>

After those changes my application is prepared to use Dojo. In the beginning of a view script you need to tell the ZF, that Dojo is needed by calling

$this->dojo()->enable();

If you don’t do this, the Dojo library will not be included in your layout.phtml file and Dojo won’t work. My first target was to create a TabContainer. Of course there is a ViewHelper which you can use to create such a container:

echo $this->tabContainer($id, $content, $params, $attribs);

Looks like a normal ViewHelper. But there is a difference because all layout containers know the capture methods captureStart() and captureEnd():

<?php
$this->dojo()->enable();

// Container with tabs
$this->tabContainer()->captureStart('tab1', array(), array('style' => 'width:800px;height:500px;'));
    // My content goes here
echo $this->tabContainer()->captureEnd('tab1');

I really like this way of adding content into a container, because your view script stays readable even if you start nesting containers into containers. Let’s have a look at my complete view script which I used for my sample:

<?php
$this->dojo()->enable();






// Container with tabs
$this->tabContainer()->captureStart('tab1', array(), array('style' => 'width:800px;height:500px;'));

    // First tab "Dates"
    $this->contentPane()->captureStart('pane1', array(), array('title' => 'Dates'));
        echo $this->form1;
    echo $this->contentPane()->captureEnd('pane1');
   
    // Second tab "FAQ"
    $this->contentPane()->captureStart('pane2', array(), array('title' => 'FAQ'));
        echo '<h1>FAQ</h1>
        <dl><dt>Question 1?</dt><dd>This is my answer 1!</dd></dl>
        <dl><dt>Question 2?</dt><dd>Good question, next one.</dd></dl>
        <dl><dt>Question 3?</dt><dd>Ok, that\'s enough!</dd></dl>
        '
;
    echo $this->contentPane()->captureEnd('pane2');
   
    // Third tab "Closable"
    $this->contentPane()->captureStart('pane3', array(), array('title' => 'Closable', 'closable' => true));
        echo 'You can close me!';
    echo $this->contentPane()->captureEnd('pane3');
   
    // Fourth tab "Splitted"
    $this->contentPane()->captureStart('pane4', array(), array('title' => 'Splitted'));
        $this->splitContainer()->captureStart('split1', array(), array('style' => 'width:250px;height:250px;'));
            $this->contentPane()->captureStart('splitpane1', array(), array());
                echo 'Hey, I am on the left side!';
            echo $this->contentPane()->captureEnd('splitpane1');
            $this->contentPane()->captureStart('splitpane2', array(), array());
                echo 'Cool!';
            echo $this->contentPane()->captureEnd('splitpane2');
        echo $this->splitContainer()->captureEnd('split1');
    echo $this->contentPane()->captureEnd('pane4');

echo $this->tabContainer()->captureEnd('tab1');

As you can see every tab is a new ContentPane. ContentPanes can be used inside every layout container except the AccordionContainer. Have a look at the docs for more information on that.
I’m displaying a form in the first tab. This form is an object of the class Zend_Dojo_Form. There are some really cool Dojo widgets (Dijits) which you can use to spice your forms up. The form is created in my IndexController:

public function indexAction()
{
    $form1 = new Zend_Dojo_Form();
    $form1->setMethod('post')->setAction("/");
    $form1->addElement('DateTextBox', 'date1', array(
        'label' => 'Choose a date:',
        'datePattern' => 'yyyy-MM-dd',
        'validators' => array('Date'),
        'required' => true
    ))
    ->addElement('TimeTextBox', 'time1', array(
        'label' => 'Choose a time:',
        'timePattern' => 'HH:mm:ss',
    ))
    ->addElement('NumberSpinner', 'number1', array(
        'label' => 'Choose a number:',
        'value' => 0,
        'smallDelta' => 1,
        'min' => 0,
        'max' => 30,
        'defaultTimeout' => 100,
        'timeoutChangeRate' => 100,
    ))
    ->addElement('HorizontalSlider', 'slide1', array(
        'label' => 'Let\'s slide:',
        'minimum' => 0,
        'maximum' => 25,
        'discreteValues' => 10,
        'style' => 'width: 450px;',
        'topDecorationDijit' => 'HorizontalRuleLabels',
        'topDecorationLabels' => array('0%', '50%', '100%'),
        'topDecorationParams' => array('style' => 'padding-bottom: 20px;'),
    ))
    ->addElement('SubmitButton', 'submit', array(
        'label' => 'Submit!'
        ));

    $this->view->form1 = $form1;
}

As you can see it is ridiculous easy to put together such a form. Basically it is the same as with the normal Zend_Form. Of course the Dojo form elements have different names (e.g. “SubmitButton” instead of “submit”) and you need some additional array keys in the form element configuration but then the magic happens.

This is only the very first step on my way of understanding Dojo but so far it looks promising! I’ll write more about it as soon as I digged deeper into that topic.

Link to My Demo

These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • Reddit
  • Webnews
  • MisterWong
  • Y!GG
  • Technorati
  • Facebook
  • Furl
  • Google Bookmarks
  • Slashdot
  • Ask
  • Hype
  • Netscape
  • Readster
  • YahooMyWeb

Tags: , , , ,

27 Responses to “My Very First Steps with Zend_Dojo”

  1. Johan Says:

    If I understand correctly, the viewhelpers (like the tabContainer) are only usable in the view script and not in the layout script? Because if it is, this would be very useful. Else I’d have to put the same code in all of the view scripts, while the layout script should help avoid this.
    If not, would I be able to access the viewHelpers like so in my layout script:
    $this->getView()->tabContainer(…)?

    thx

  2. Mike Rötgers Says:

    A layout script behaves similar to a view script. So of course you can use the dojo view helpers in the layout script in the same way you use them in a view script, e.g. echo $this->tabContainer($what, $ever);
    The only problem is, that the dojo view helper, which builds all the javascript tags in the <head> part of your html document, only knows which parts of the Dojo Toolkit are needed, if you used them before. That means if you build up your layout script like I described it in my blog post and then add some dojo stuff in the <body> area of your layout script, the view helper which you used in the <head> part don’t know about that, because it happens after the helper is called. As far as I oversee that in the moment, you have two options: Build the dojo stuff _before_ the <head> part in your layout script but print it out _after_ the <head> part or tell the dojo view helper which dojo modules are required before you use them like this:
    $this->dojo()->enable()
    ->setDjConfigOption(’parseOnLoad’, true)
    ->registerModulePath(’../whatever/’)
    ->requireModule(’dijit.form.DateTextBox’)
    ->requireModule(’dijit.layout.TabContainer’)
    ->requireModule(’etc, etc’);
    It’s described here: http://framework.zend.com/manual/en/zend.dojo.view.html#zend.dojo.view.dojo

    Maybe there is an easier way. As I said that was my first little test with Zend_Dojo and the Dojo Toolkit, I don’t know all the details yet.

  3. Johan Says:

    Like so?
    //layout script:
    $tab1 = $this->tabContainer(…);
    doctype() ?>

    if ($this->dojo()->isEnabled()):
    $this->dojo()->setLocalPath(’/js/dojo/dojo.js’)
    ->addStyleSheetModule(’dijit.themes.tundra’);
    echo $this->dojo();
    endif; ?>

    tab1;
    $this->layout()->content;
    ?>

  4. Johan Says:

    edit:

    $this->tab1; or $tab1;

  5. Mike Rötgers Says:

    Here is a sample layout.phtml which works:

    <?php
    $this->dojo()->enable();
    $this->tabContainer()->captureStart('tab1', array(), array('style' => 'width:800px;height:500px;'));

        // First tab "Pane 1"
        $this->contentPane()->captureStart('pane1', array(), array('title' => 'Pane 1'));
            echo 'ContentPane1';
        echo $this->contentPane()->captureEnd('pane1');
       
        // Second tab "Pane 2"
        $this->contentPane()->captureStart('pane2', array(), array('title' => 'Pane 2'));
            echo 'ContentPane2';
        echo $this->contentPane()->captureEnd('pane2');

    $tab = $this->tabContainer()->captureEnd('tab1');


    echo $this->doctype() ?>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>roetgers.org Dojo Demo</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <?php
        echo $this->headLink()->setStylesheet('/css/my.css');
        if ($this->dojo()->isEnabled()):
            $this->dojo()->setLocalPath('/js/dojo/dojo.js')
                ->addStyleSheetModule('dijit.themes.tundra');
            echo $this->dojo();
        endif;
        ?>
    </head>
    <body class="tundra">
    <?php echo $tab ?>
    <?php echo $this->layout()->content ?>
    </body>
    </html>
  6. Johan Says:

    Thx a lot!!! :)

  7. Rex Says:

    I did not enable dojo in my view script, even I disabled it, however, the dojo library was still included in my layout.phtml. I already followed your steps, why?

  8. Rex Says:

    I found that if I echo a zend form in my view script it will enable dojo automatically regardless calling $this->dojo()->disable().

    // like this:
    // In my view script
    $this->dojo()->disable();

    echo $this->form; // Generated by Zend_Form

    // In my layout
    if ($this->dojo()->isEnabled()) { // This will return true.
    ….
    }

  9. Mike Rötgers Says:

    echo $this->form; // Generated by Zend_Form

    I guess this isn’t Zend_Form but Zend_Dojo_Form, is it? If that’s the case, it would make sense to activate dojo automatically.

  10. Willem Luijk Says:

    Very nice tut but i miss the inter component action, the replacement of parts of the screen where the ajax paradigm stands for. For example Zend + Dojo forms and grids that run alternating in the same tab steered by a navigation tree without refesh of the whole page. An idea for your Next Steps with Zend_Dojo?

  11. Mike Rötgers Says:

    Unfortunately I didn’t make any progress with the Dojo Toolkit. In my current project at work the combination of Prototype/Scriptaculous is still used, so I didn’t had the chance yet to dig deeper into Dojo at work.
    Probably Matthew’s webinar today will cover a lot of stuff which isn’t mentioned in this blog post.

  12. Nico Says:

    Very helpful example, thank you a lot. Also looking forward to your next steps, as I’m taking mine at the moment :-)

  13. Gilles Says:

    Very nice tutorial !

    I’ve an install problem :

    in /public/styles -> put here all the DOJO stuff ?

    ie :
    /public/styles/dojo/dijit
    /dojo
    /dojox
    /utils

    In this case must I use :
    if ($this->dojo()->isEnabled()):
    $this->dojo()->setLocalPath(’/public/styles/dojo/dojo/dojo.js’)
    ->addStyleSheetModule(’dijit.themes.tundra’); // How can it find it ????
    echo $this->dojo();
    endif;

    Am I right ?

    Gilles

  14. James Says:

    Hi, I found your blog on this new directory of WordPress Blogs at blackhatbootcamp.com/listofwordpressblogs. I dont know how your blog came up, must have been a typo, i duno. Anyways, I just clicked it and here I am. Your blog looks good. Have a nice day. James.

  15. Alex Says:

    Hi! This is really a great example, thanks!

    But I’m wondering, why it’s not working in IE?

  16. Jean-Marc Rigade Says:

    Really great example !
    I am looking for a simple example of autocompletion using ZF1.6 with Zend_Dojo class and a database table.
    The ZF documentation for that is not usefull for me.
    Do you know where I can find some example that really work ?

    Thank you

  17. snl Says:

    Just wanted to give a heads-up that the tabs seem not to render in Internet Explorer 7.

  18. Mike Rötgers Says:

    Thanks for reporting the IE issue. I’ll investigate that next week.

  19. Jean Says:

    For easy Dojo application, check your Apache http.conf and your .htaccess (same directory as the index.php bootstap). It works perfectly with IE.

    ie. httpd.conf

    ServerAdmin webmaster@localhost.localdomain
    DocumentRoot “c:/travail/www/testdojo/public”
    ServerName testdojo
    ErrorLog logs/testdojo-error.log
    CustomLog logs/testdojo-access.log common

    DirectoryIndex index.php
    AllowOverride All
    Order allow,deny
    Allow from all

    and the .htaccess (don’t forget to start the corresponding mods in php.ini)

    # PHP values we need to set
    # - timezone should be set
    # - need short open tags for view scripts
    php_value date.timezone “UTC”
    php_value short_open_tag 1
    php_value error_reporting 8191
    php_flag display_errors Off
    php_flag display_startup_errors Off

    # Rewrite Rules
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} -s [OR]
    RewriteCond %{REQUEST_FILENAME} -l [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^.*$ - [NC,L]
    RewriteRule ^.*$ /index.php [NC,L]

    # Expires/ETags
    # You’ll want to turn off the ExpiresActive setting when actively developing.
    # In production, however, these settings follow the Y!Slow guidelines.
    ExpiresActive On
    ExpiresByType text/css “access plus 1 month”
    ExpiresByType application/x-javascript “access plus 1 month”
    ExpiresByType image/png “access plus 1 month”
    ExpiresByType image/gif “access plus 1 month”
    FileETag none

    # Gzip CSS and JS by default
    AddOutputFilterByType DEFLATE text/css application/x-javascript

  20. Jean Says:

    This is a great example ! thanks !

    Just a question, how do you send data from your controller to an textaera element ?

  21. ruddy Says:

    Jean you are a life saver! My example wasn’t working until I fixed my htaccess file. Nice blog Mike, definitely a useful resource.

  22. ruddy Says:

    Note: I’m not sure if it’s because I’m using modules, but to correct Jeans note, change -
    RewriteRule ^.*$ /index.php [NC,L]
    to
    RewriteRule ^.*$ index.php [NC,L]

  23. Andrew Wickham Says:

    I had to take it a step further on my rewrite rule and tell it to exclude JS, CSS, etc. This wasn’t a problem with this example, but when putting it inside of a BorderControl, it became quite a problem.

    RewriteEngine on
    RewriteCond %{REQUEST_FILENAME} -f [NC,OR]
    RewriteCond %{REQUEST_FILENAME} -d [NC]
    RewriteRule .* - [L]
    RewriteRule !\.(js|ico|gif|jpg|png|css)$ index.php

    I found this rewrite rule on Gavin Williams’ blog, just another developer (http://blog.justanotherdeveloper.co.uk/).

  24. Buddha Soumpholpahkdy Says:

    Very informative! We’re also working with Zf and using prototype & scriptaculous at our workplace. But lately I’ve been making moves to try out Dojo with Zf. It’s awesome! I started learning Dojo independently from Zf. So it was pretty simple to implement Dojo Form Elements. :) Good write up man

  25. Ryan Donnelly Says:

    Thank you, thank you, thank you. I’ve been trying to get the Zend_Dojo stuff to work for a couple hours going through various tutorials and none of them have worked until now. I really appreciate it!

  26. Ilyas Iqbal Says:

    Hi Mike,
    I am the newbie of ZF and facing many problems in ZendFramework. Actually, I’m trying to add Zend_Dojo in combination with AJAX.

    Could you help me regarding this thing by putting any example begineer level example?
    Could you please provide its complete source code of this Tab container example?

    Ilyas

  27. Biji Says:

    Thanks for the post! very useful

Leave a Reply