Yii 1.1: How to work with flash messages

43 followers

Summary

Set your messages in a controller:

Yii::app()->user->setFlash('success', "Data1 saved!");
Yii::app()->user->setFlash('error', "Data2 failed!");
Yii::app()->user->setFlash('notice', "Data3 ignored.");

Display them in your view:

<?php
    foreach(Yii::app()->user->getFlashes() as $key => $message) {
        echo '<div class="flash-' . $key . '">' . $message . "</div>\n";
    }
?>

Setting flash messages

A flash message is used in order to keep a message in session through one or several requests of the same user. By default, it is removed from session after it has been displayed to the user. Flash messages are usually used in combination with HTTP redirections, because in this case there is no view, so messages can only be displayed in the request that follows redirection.

A flash message has a name and a content (AKA key and value). It is an entry of an associative array. The name is a string: often "notice", "success", or "error", but it can be anything. The content is usually a string. You can put HTML tags in your message if you display it raw. You can also set the message value to a number or an array: it will be serialized and kept in session like a string.

Flash messages can be set using the setFlash() Method of CWebUser. For example, if you would like to inform the user that his changes were successfully saved, you could add the following line to your Controller:

<?php
Yii::app()->user->setFlash('success', "Data saved!");
$this->redirect(array('thing/view', 'id' => 1));

In this example we used the key 'success'. If you want to define more than one flash messages, you will have to use different keys.

Displaying flash messages

To check for flash messages we use the hasFlash() Method and to obtain the flash message we use the getFlash() Method. Since Yii v1.1.3, there is also a method getFlashes() to fetch all the messages.

By default, fetching a message deletes it from the session. This means that a message is meant to be displayed only on the first page served to the user. The fetching methods have a boolean parameter that can change this behavior. See the API links in the previous paragraph.

Displaying statically

So showing of the flash message defined above in a view is done by

<?php if(Yii::app()->user->hasFlash('success')):?>
    <div class="info">
        <?php echo Yii::app()->user->getFlash('success'); ?>
    </div>
<?php endif; ?>

These few lines of code will make a flash message with the key "success" visible to the user within a div of class "info". The message will be displayed until this or another page is (re)loaded in the browser.

If you want to always display all the flash messages, then you should add a block to your layout (by default protected/views/layout/main.php). Here is a more elaborate example:

<?php
$flashMessages = Yii::app()->user->getFlashes();
if ($flashMessages) {
    echo '<ul class="flashes">';
    foreach($flashMessages as $key => $message) {
        echo '<li><div class="flash-' . $key . '">' . $message . "</div></li>\n";
    }
    echo '</ul>';
}
?>

The default CSS created by the Yii script yiic webapp has directives for three classes of flash messages on a div tag: flash-error, flash-notice, flash-success.

The best way to know if some flash messages are set is to check if Yii::app()->user->getFlashes() is empty. Since v1.1.7, Yii keeps an associative array of the flash keys in the form array("key1" => 0, ...), or null if not flash message is set. You can fetch this with Yii::app()->user->getState(CWebUser::FLASH_COUNTERS) but this is not recommended, as Yii could change this internal process.

Displaying dynamically (with Javascript)

If you want the flash message to appear somewhere above the content and then automatically fade out after a few seconds, you will have to add the following lines to your view:

<?php
Yii::app()->clientScript->registerScript(
   'myHideEffect',
   '$(".info").animate({opacity: 1.0}, 3000).fadeOut("slow");',
   CClientScript::POS_READY
);
?>

With these lines of code we register a piece of jQuery (already included with YII) javascript code, using 'myHideEffect' as ID. It will be inserted in the jQuery's ready function (CClientScript::POS_READY). Due to the chainablity of jQuery the little script will run two effects on the .info DIV sequentially:

.animate({opacity: 1.0}, 3000)

Normally this would animate the .info DIV to a full opacity within 3 seconds. But the DIV is already rendered with full opacity upon page load, so calling this effect will just cause a delay for 3 seconds.

.fadeOut("slow")

This is the fadeOut effect which will hide the .info DIV at slow speed.

Further readings (JS):

Links

Total 10 comments

#17495 report it
mem at 2014/06/23 10:00am
POST_END

When using POST_READY on certain situations, you may notice a initial undesired blink. You can try to fix it, by using CSS and display:none; however, when you have several flash messages to display instead of just one, you have to play with foreach flags and so forth...

I found out that, on certain situations, if instead of POST_READY I use POST_END, no more blinking undesired effect appears.

Hope it saves some time to someone.

#5978 report it
junxiong at 2011/12/02 03:39am
autoUpdateFlash

This thing has caused me headache, hope can help others too..

Yii's flash message only persist on first and second request. On the third request it will disappear. To prevent this behavior we must set the CWebUser's autoUpdateFlash to false. That way, the flash message will only deleted after calling getFlash()

'user'=>array(
        ...
        'autoUpdateFlash' => false, // add this line to disable the flash counter
),

Reference : http://www.yiiframework.com/forum/index.php?/topic/21077-flash-messages-and-redirect/

#4627 report it
klod at 2011/07/27 04:12am
Javascript Delays

jquery delay method

$(".info").delay(3000).fadeOut("slow");
#4369 report it
sidtj at 2011/06/29 05:38pm
Since 1.1.3 we can use...
<?php foreach(Yii::app()->user->getFlashes() as $key => $message) {
    if ($key=='counters') {continue;} //no need next line since 1.1.7
    echo "<div class='flash-{$key}'>{$message}</div>";
} ?>
#4167 report it
dinhtrung at 2011/06/12 04:21am
Not work with Ajax Validation

On CActiveForm widget, which usually generated by Gii, when the form is submit, there are 2 request, one for sending the data normally from the Submit button, and one for perform Ajax validation. Strange that the ajax validation request is performed after the normal one. So there is no way to save the Flash session data for 3rd request (the redirect page). I have to disable ajax validation to make it work.

#2686 report it
cheeserolls at 2011/01/29 01:17am
Update to post by 'sova'

Since v1.1.3 the CWebUser::getFlashes method is available, which makes automatic display of flash messages even easier:

<?php foreach(Yii::app()->user->getFlashes() as $key => $message) {
    if ($key=='counters') {continue;}
    echo "<div class='flash-{$key}'>{$message}</div>";
} ?>
#1 report it
tax14 at 2010/10/15 11:00am
Works great!

I tried the following code in my view file. Works Great!

<?php
    Yii::app()->clientScript->registerScript(
       'myHideEffect',
       '$(".flash-success").animate({opacity: 1.0}, 3000).fadeOut("slow");',
       CClientScript::POS_READY
    );
?>
 
<?php if(Yii::app()->user->hasFlash('success')):?>
    <div class="flash-success">
        <?php echo Yii::app()->user->getFlash('success'); ?>
    </div>
<?php endif; ?>
#282 report it
Myth Thrazz at 2010/07/21 06:48am
JavaScript delays

This will not work.

setTimeout(3000, function(){ $(".info").fadeOut("slow"); });

This one does.

setTimeout(function(){ $(".info").fadeOut("slow"); },3000);
#453 report it
sova at 2010/05/29 11:46am
Automated display of flash messages

The main.css file from the default set of CSS files coming with Yii defines these three classes: div.flash-error, div.flash-notice and div.flash-success. You can use them to automate display of flash messages to the user in accordance with their type ("error", "notice" or "success"). Here is how.

Step 1. Put this method into your WebUser class:

/**
 * @return array flash message keys array
 */
public function getFlashKeys()
{
    $counters=$this->getState(self::FLASH_COUNTERS);
    if(!is_array($counters)) return array();
    return array_keys($counters);
}

Step 2. Put this piece of code into your layout or view where a flash message would be appropriate:

<?php
    $user=Yii::app()->getUser();
    foreach($user->getFlashKeys() as $key):
        if($user->hasFlash($key)): ?>
        <div class="flash-<?php echo $key; ?>">
            <?php echo $user->getFlash($key); ?>
        </div>
<?php
        endif;
    endforeach; ?>

Step 3. Put lines of code similar to these where appropriate to notify the user of the corresponding event types:

Yii::app()->getUser()->setFlash('error','Could not save data to the database.');
Yii::app()->getUser()->setFlash('notice','There was nothing to save.');
Yii::app()->getUser()->setFlash('success','The data was successfully saved to the database.');
#1465 report it
killermonk at 2009/07/27 10:38pm
Javascript Delays
`$(".info").animate({opacity: 1.0}, 3000).fadeOut("slow");`

The animate call on this line of code is used as a hack to perform a delay. As specified shortly after it was written. However, the one problem with using this method is that it consumes CPU resources for no real purpose. You can use this instead:

`setTimeout(3000, function(){ $(".info").fadeOut("slow"); });`

This method will not consume resources for the delay.

On another note, however. If you want to display information to a user, it is usually recommended that you leave the information on the screen until the user supplies input to say they want it to go away. There is nothing more annoying than having an error message fadeOut before you have time to read the whole thing.

You can do this by put a close image/button/link somewhere in the message area that the user can click and use the following line (assuming the id of your link is 'close_btn':

`$('#close_btn').click(function(){ $(".info").fadeOut("slow"); });`

Leave a comment

Please to leave your comment.

Write new article