How to create alert notifications and modals
Concrete CMS v8 provides multiple methods for creating dialog modals, confirm modals, and notifications.
The dialog() and confirm() methods are concrete wrappers for jQuery UI. The concrete notifications use PNotify.js and can be created using the ConcreteAlert JavaScript object, the PNotify JavaScript object, and the PHP UserInterface service (helper/concrete/ui).
The ConcreteAlert object is created in alert.js and is combined with PNotify and other scripts as app.js (concrete/js/app.js). When logged in, app.js is loaded by the concrete interface, with the script added near the closing body tag. To make sure app.js has been loaded before using it, use jQuery .ready(), or a similar method, to make sure ConcreteAlert and PNotify are available. When using the UserInterface service notify() method, it will return a script tag with a PNotify object and options wrapped in a jQuery .ready() shorthand method.
Translatable strings in JavaScript should be wrapped in json_encode()
and t()
and t()
in PHP. The json_encode()
method will escape quotes and t()
is used for core translation.
PNotify
https://github.com/sciactive/pnotify
The full list of PNotify options can be found here (some options are only available when using PNotify directly or the UserInterface service).
https://github.com/sciactive/pnotify/blob/v3.2/README.md#configuration-defaults--options
Dialog Modals
dialog()
dialog(title, message, onCloseFn)
concrete/js/build/core/app/alert.js
- title - the title for the dialog modal
- message - the dialog modal message (plain text or HTML)
- onCloseFn - an optional inline function or named function, called when the dialog modal is closed
Example:
ConcreteAlert.dialog(
<?php echo json_encode(t('My Dialog Modal Title')); ?>,
<?php echo json_encode(t('My dialog modal message.')); ?>
);
Example: inline on close function
ConcreteAlert.dialog(
<?php echo json_encode(t('My Dialog Modal Title')); ?>,
<?php echo json_encode(t('My dialog modal message.')); ?>,
function() {
// do this when the modal is closed
}
);
Example: named on close function
function myOnCloseFunction() {
// do this when the modal is closed
}
ConcreteAlert.dialog(
<?php echo json_encode(t('My Dialog Modal Title')); ?>,
<?php echo json_encode(t('My dialog modal message.')); ?>,
myOnCloseFunction
);
Confirm Modals
confirm()
confirm(message, onConfirmation, btnClass, btnText)
concrete/js/build/core/app/alert.js
- message - the confirm modal message (plain text or HTML)
- onConfirmation - an inline function or named function, called when the modal confirm button is clicked
- btnClass - the confirmation button class (the default class is "btn-primary")
- available Bootstrap 3 button classes
- btn-default
- btn-primary
- btn-success
- btn-info
- btn-warning
- btn-danger
- available Bootstrap 3 button classes
- btnText - the confirmation button text (the default button text is "Go")
Example: inline on close function
ConcreteAlert.confirm(
<?php echo json_encode(t('My confirm message.')); ?>,
function() {
// do this when the modal is confirmed
}
);
Example: named on close function
function myOnConfirmationFunction() {
// do this when the modal is confirmed
}
ConcreteAlert.confirm(
<?php echo json_encode(t('My confirm message.')); ?>,
myOnConfirmationFunction
);
Example: button class
function myOnConfirmationFunction() {
// do this when the modal is confirmed
}
ConcreteAlert.confirm(
<?php echo json_encode(t('My confirm message.')); ?>,
myOnConfirmationFunction,
'btn-warning'
);
Example: button class and button text
function myOnConfirmationFunction() {
// do this when the modal is confirmed
}
ConcreteAlert.confirm(
<?php echo json_encode(t('My confirm message.')); ?>,
myOnConfirmationFunction,
'btn-danger',
<?php echo json_encode(t('Delete')); ?>
);
Please note Confirm Modals are only available from concrete 8.3.x
How to use Confirm Modals
When using normal browser confirm message, the browser takes care of preventing any action until a choice has been made in the confirm message, either accept or cancel.
With these custom Confirm Modals, we have to take care of everything ourselves.
Typically you will have 2 different situations, either the link or button you click on has an action attached to it or it doesn't.
Let's first deal with the first situation: the element does have an action attached to it.
For instance, a link can have a URL set as it's HREF attribute, a button can submit a form. So the first thing we must do before calling our modal is to prevent the default action from happening.
Let's say my link or button has a class name of action
and I want to open my modal on click. Using the preceding examples we would modify them as follow:
function myOnCloseFunction() {
// do this when the modal is confirmed
}
$('.action').on('click', function(event) {
event.preventDefault();
ConcreteAlert.dialog(
<?php echo json_encode(t('My Dialog Modal Title')); ?>,
<?php echo json_encode(t('My dialog modal message.')); ?>,
myOnCloseFunction
);
});
Having done so we will show the confirm message without triggering the default link or button's action.
If the user clicks the cancel button we have nothing more to do. We already cancelled the default action, nothing is going to happen other than the Confirm Modal closing.
If, however, the user clicks the OK button and confirms the action we now need to trigger the default action we previously cancelled. It's time to use our custom myOnCloseFunction()
Let's modify the code once again:
function myOnCloseFunction(button) {
// do this when the modal is confirmed
button.unbind('click').click();
}
$('.action').on('click', function(event) {
var button = $(this);
event.preventDefault();
ConcreteAlert.dialog(
<?php echo json_encode(t('My Dialog Modal Title')); ?>,
<?php echo json_encode(t('My dialog modal message.')); ?>,
myOnCloseFunction(button)
);
});
First, on click, we grab the current button in a variable. I called it button you can call it anything.
Then we modify our custom functin to accept a parameter because we will send it our button to work with. Our function now looks like this myOnCloseFunction(button)
Finally, in our function we have 2 tasks: first we use unbind()
to remove the previous click action attached to the button. Because we used event.preventDefault() on the button when setting our click action, we can't count on that button to trigger any action anymore so we cancel that.
Then we trigger a click on the button by calling the very aptly named click()
function on it so it will do what it was supposed to do all along.
And we're done with this one.
Now let us deal with the situation where the button or link didn't have any action attached to it. Maybe that link or button was mean to be used through Javascript all along and is used purely as a trigger.
Here the idea is the same as in the previous situation with 2 differences: we do not have a default action to prevent since there's no action at all and we do not have an action to trigger once the user confirms their choice.
The solution is to use a redirect if it's a link or manually submit the form if it's a form we're dealing with.
I'll let you look at triggering a form submit on your own, it's not complicated to figure out.
I'm going to focus on redirection and look at the possible scenarii: through JavaScript or through PHP.
If your script is in a JS file you will have no choice but to redirect through JS. One drawback of that situation is your link better be static.
More often than not, however, our link will be dynamic with parameters sent from PHP (a file ID for instance) and that would complicate things. In that case you'll have to devise a way to make your script aware of those parameters.
The way concrete deals with this is to set the whole URL as an attribute on the triggering element (generated through PHP) so the script can grab it easily. For instance:
<button data-action="http://mysite.com/myaction?fID=3">
All the JS needs to do is to grab that data-action value and redirect to it to achieve the desired result.
Redirecting in JS can be done easily:
function myOnCloseFunction(button) {
// do this when the modal is confirmed
window.location.href = button.attr('data-action');
}
I know treating a data attribute as a simple attribute instead of a data store is not best but it ensure maximum compatibility with all kinds of browsers so just humour me on this one.
Now if your JS code is hard-coded in a PHP file, you can simplify things. Just remove references to our button since we won't need them anymore:
function myOnCloseFunction() {
// do this when the modal is confirmed
window.location.href = "<?php \URL::to('/path/to/action', 'oneparameter', 'anotherparameter') ?>";
}
$('.action').on('click', function(event) {
event.preventDefault();
ConcreteAlert.dialog(
<?php echo json_encode(t('My Dialog Modal Title')); ?>,
<?php echo json_encode(t('My dialog modal message.')); ?>,
myOnCloseFunction()
);
});
Notifications
info()
info(defaults)
concrete/js/build/core/app/alert.js
- defaults
- type - info
- icon - Font Awesome question icon minus the "fa-" prefix
- title - the notification title (plain text or HTML) displayed as an h4 element
- message - the notification message (plain text or HTML)
Example:
ConcreteAlert.info({
title: <?php echo json_encode(t('My Notification Title')); ?>,
message: <?php echo json_encode(t('My notification message.')); ?>
});
error()
error(defaults)
concrete/js/build/core/app/alert.js
- defaults
- type - error
- icon - Font Awesome exclamation-circle icon minus the "fa-" prefix
- title - the notification title (plain text or HTML) displayed as an h4 element
- message - the notification message (plain text or HTML)
Example:
ConcreteAlert.error({
title: <?php echo json_encode(t('My Notification Title')); ?>,
message: <?php echo json_encode(t('My notification message.')); ?>
});
notify()
notify(defaults)
concrete/js/build/core/app/alert.js
- defaults
- type - success
- icon - Font Awesome check icon minus the "fa-" prefix
- delay - 2000 (milliseconds)
- title - the notification title (plain text or HTML) displayed as an h4 element
- message - the notification message (plain text or HTML)
- callback - an optional inline function or named function, called when the notification is closed or hidden after a delay
Example:
ConcreteAlert.notify({
title: <?php echo json_encode(t('My Notification Title')); ?>,
message: <?php echo json_encode(t('My notification message.')); ?>
});
Example: inline function callback
ConcreteAlert.notify({
title: <?php echo json_encode(t('My Notification Title')); ?>,
message: <?php echo json_encode(t('My notification message.')); ?>,
callback: function() {
// do this when the notification is closed or hidden
}
});
Example: named function callback
function myNotificationCallbackFunction() {
// do this when the notification is closed or hidden
}
ConcreteAlert.notify({
title: <?php echo json_encode(t('My Notification Title')); ?>,
message: <?php echo json_encode(t('My notification message.')); ?>,
callback: myNotificationCallbackFunction
});
Example: type, icon, title, message, and hide options
ConcreteAlert.notify({
type: 'info',
icon: 'internet-explorer',
title: <?php echo json_encode(t('Old Browser Alert')); ?>,
message: <?php echo json_encode(t('Ewwww you are using an old version of Internet Explorer!')); ?>,
hide: false
});
Using PNotify Directly
PNotify()
Example:
new PNotify({
type: 'success',
icon: 'fa fa-thumbs-up',
title: <?php echo json_encode(t('Page Errors')); ?>,
text: <?php echo json_encode(t('Your page has no errors.')); ?>,
hide: false
});
UserInterface "helper/concrete/ui" Service
notify()
notify($arguments)
concrete/src/Application/Service/UserInterface.php
- defaults
- type - success
- icon - fa fa-check-mark
- hide - false
- addclass - ccm-notification-page-alert
- form - false
- title - the notification title (plain text or HTML) displayed as an h4 element
- text - the notification message (plain text or HTML)
- buttons - an optional array() of one or more notification buttons
Example:
echo Core::make('helper/concrete/ui')->notify(
[
'type' => 'error',
'icon' => 'fa fa-user',
'title' => t('Editor Permissions Disabled'),
'text' => t('Please contact the site administrator.')
]
);
Example: display a notification with a button
echo Core::make('helper/concrete/ui')->notify(
[
'type' => 'info',
'icon' => 'fa fa-question',
'title' => t('Member Survey'),
'text' => t('Please take a moment to fill out the yearly member survey.'),
'buttons' => [
sprintf('<a href="%s" class="btn btn-primary">%s</a>', \URL::to('/survey'), t('Click Here'))
]
]
);
Example: display a notification with two buttons
echo Core::make('helper/concrete/ui')->notify(
[
'type' => 'info',
'icon' => 'fa fa-hourglass',
'title' => t('Site Task Reminder'),
'text' => t('You have site task maintenance to perform.'),
'buttons' => [
sprintf('<a href="%s">%s</a>', \URL::to('/go-to-tasks'), t('Go to tasks')),
sprintf('<a href="%s">%s</a>', \URL::to('/remind-me-later'), t('Remind me later'))
]
]
);