diff --git a/README.md b/README.md index 09f8e84..fde8dd8 100644 --- a/README.md +++ b/README.md @@ -110,16 +110,26 @@ If set to false, the notification will not display the dismiss ('x') button and ### Action -Add a button and a callback function to the notification. If this button is clicked, the callback function is called (if provided) and the notification is dismissed. +Add a button and a callback function to the notification. If this button is clicked, the callback function is called (if provided) and the notification is dismissed (unless `preventDismiss` is true). +Action object has the following properties: + +| Name | Type | Default | Description | +|---------------- |--------------- |--------- |----------------------------------------------------------------------------------------------------------------------------------- | +| label | string | null | Title of the action button | +| preventDismiss | bool | false | If set to true, clicking on the button will not cause a notification to be dismissed, just before the callback is invoked. | +| callback | function | null | Function to be invoked when the button is clicked. A callback function takes two arguments: first is the React's `SyntheticMouseEvent` instance and the second is the `callbackArgument` object. Please note that `this` in a callback function is assigned to the `notification` itself, so you can reference it later in the callback. However, this is valid only in case a callback function is defined like in the example below. Otherwise `this` could have a different value. | +| callbackArgument | object | null | A custom object which will be passed into the callback as the second argument. Passing the callback argument is especially useful when your callback function is not defined inline, but in other place then your notification object. | ```js notification = { [...], action: { label: 'Button name', - callback: function() { - console.log('Notification button clicked!'); + preventDismiss: true, + callback: function(event, param) { + console.log('Callback invoked by the event', event, "with param", param.name); } + callbackArgument: {name: 'foo'} } } diff --git a/example/src/scripts/App.jsx b/example/src/scripts/App.jsx index f3ad327..324f4f7 100644 --- a/example/src/scripts/App.jsx +++ b/example/src/scripts/App.jsx @@ -47,6 +47,21 @@ NotificationSystemExample = React.createClass({ level: 'error', position: 'tl' }, + { + title: 'Ups!', + message: 'Something bad happened :(', + level: 'error', + position: 'tl', + action: { + label: 'Details', + preventDismiss: true, + callback: function (event, param) { + console.log('Details clicked', event, 'in notification', this); + alert(param.code + ': ' + param.message); + }, + callbackArgument: {code: 500, message: 'Internal server error'} + } + }, { title: 'Advise!', message: 'Showing all possible notifications works better on a larger screen', diff --git a/src/NotificationItem.jsx b/src/NotificationItem.jsx index eba803d..5342218 100644 --- a/src/NotificationItem.jsx +++ b/src/NotificationItem.jsx @@ -124,9 +124,14 @@ var NotificationItem = React.createClass({ var notification = this.props.notification; event.preventDefault(); - this._hideNotification(); + if (notification.action.preventDismiss) { + event.stopPropagation(); // do not let _dismiss method (fired on parent onClick event) to be invoked + } else { + this._hideNotification(); + } + if (typeof notification.action.callback === 'function') { - notification.action.callback(); + notification.action.callback.call(notification, event, notification.action.callbackArgument); } }, diff --git a/test/notification-system.test.js b/test/notification-system.test.js index e3aab6f..209f758 100644 --- a/test/notification-system.test.js +++ b/test/notification-system.test.js @@ -190,7 +190,7 @@ describe('Notification Component', function() { done(); }); - it('should not dismiss the notificaion on click if dismissible is false', done => { + it('should not dismiss the notification on click if dismissible is false', done => { notificationObj.dismissible = false; component.addNotification(notificationObj); let notification = TestUtils.findRenderedDOMComponentWithClass(instance, 'notification'); @@ -200,6 +200,20 @@ describe('Notification Component', function() { done(); }); + it('should not dismiss the notification on click if preventDismiss is true', done => { + notificationObj.action = { + label: 'Click me', + preventDismiss: true, + callback: function() {} + }; + component.addNotification(notificationObj); + let button = TestUtils.findRenderedDOMComponentWithClass(instance, 'notification-action-button'); + TestUtils.Simulate.click(button); + let notificationAfterClicked = TestUtils.findRenderedDOMComponentWithClass(instance, 'notification-action-button'); + expect(notificationAfterClicked).toExist(); + done(); + }); + it('should render a button if action property is passed', done => { defaultNotification.action = { label: 'Click me', @@ -228,6 +242,29 @@ describe('Notification Component', function() { done(); }); + it('should execute a callback function with proper arguments when notification button is clicked', done => { + let thisNotification = undefined, + event = undefined, + callArg = undefined; + notificationObj.action = { + label: 'Click me', + callback: function(e, param) { + thisNotification = this; + callArg = param.value; + event = e; + }, + callbackArgument: {value: 'foo'} + }; + + component.addNotification(notificationObj); + let button = TestUtils.findRenderedDOMComponentWithClass(instance, 'notification-action-button'); + TestUtils.Simulate.click(button); + expect('Click me').toEqual(thisNotification.action.label); + expect(callArg).toEqual('foo'); + expect(event).toBeAn('object'); + done(); + }); + it('should accept an action without callback function defined', done => { notificationObj.action = { label: 'Click me'