# Upgrading ember-cli-flash
## Upgrading to v7
### Configuration via Environment is Removed
**This is a breaking change.** The addon no longer reads configuration from `config/environment.js`. You should now extend the service and override the `flashMessageDefaults` getter.
#### Before (v6)
```javascript
// config/environment.js
module.exports = function (environment) {
const ENV = {
// ...
flashMessageDefaults: {
timeout: 5000,
extendedTimeout: 1000,
priority: 200,
sticky: false,
showProgress: true,
type: 'info',
types: ['success', 'info', 'warning', 'danger', 'alert', 'secondary'],
preventDuplicates: true,
},
};
return ENV;
};
```
#### After (v7)
Create your own flash-messages service that extends the base service:
```typescript
// app/services/flash-messages.ts
import { FlashMessagesService } from 'ember-cli-flash';
export default class MyFlashMessages extends FlashMessagesService {
get flashMessageDefaults() {
return {
...super.flashMessageDefaults,
timeout: 5000,
extendedTimeout: 1000,
priority: 200,
showProgress: true,
preventDuplicates: true,
};
}
}
```
### Default Options Reference
Here are all available default options you can configure:
| Option | Type | Default | Description |
| ------------------- | ---------- | ---------------------------------------------------------------- | ------------------------------------------------------------------- |
| `timeout` | `number` | `3000` | Milliseconds before flash message is automatically removed |
| `extendedTimeout` | `number` | `0` | Milliseconds to add 'exiting' class before removal (for animations) |
| `priority` | `number` | `100` | Higher priority messages appear first in `arrangedQueue` |
| `sticky` | `boolean` | `false` | If `true`, message won't auto-dismiss (must be clicked) |
| `showProgress` | `boolean` | `false` | Show a progress bar indicating time remaining |
| `type` | `string` | `'info'` | Default type when using `add()` without specifying type |
| `types` | `string[]` | `['success', 'info', 'warning', 'danger', 'alert', 'secondary']` | Available type methods on the service |
| `preventDuplicates` | `boolean` | `false` | Prevent adding duplicate messages (based on message text) |
| `destroyOnClick` | `boolean` | `true` | Whether clicking the message destroys it |
### Configuration Examples
#### Example 1: Basic Customization
```typescript
// app/services/flash-messages.ts
import { FlashMessagesService } from 'ember-cli-flash';
export default class FlashMessages extends FlashMessagesService {
get flashMessageDefaults() {
return {
...super.flashMessageDefaults,
timeout: 5000, // 5 seconds instead of 3
showProgress: true, // Always show progress bar
preventDuplicates: true, // No duplicate messages
};
}
}
```
#### Example 2: Animated Flash Messages
For smooth animations when messages appear and disappear:
```typescript
// app/services/flash-messages.ts
import { FlashMessagesService } from 'ember-cli-flash';
export default class FlashMessages extends FlashMessagesService {
get flashMessageDefaults() {
return {
...super.flashMessageDefaults,
timeout: 4000,
extendedTimeout: 500, // Adds 'exiting' class 500ms before removal
};
}
}
```
Then animate with CSS:
```scss
.alert {
opacity: 0;
transform: translateX(100px);
transition: all 500ms ease-out;
&.active {
opacity: 1;
transform: translateX(0);
&.exiting {
opacity: 0;
transform: translateX(100px);
}
}
}
```
#### Example 3: Custom Message Types
Register custom types for your application:
```typescript
// app/services/flash-messages.ts
import { FlashMessagesService } from 'ember-cli-flash';
import type { FlashObjectOptions } from 'ember-cli-flash';
export default class FlashMessages extends FlashMessagesService {
// Declare custom types for TypeScript (base types like success, warning are already typed)
declare notice: (message: string, options?: FlashObjectOptions) => this;
declare error: (message: string, options?: FlashObjectOptions) => this;
declare system: (message: string, options?: FlashObjectOptions) => this;
get flashMessageDefaults() {
return {
...super.flashMessageDefaults,
type: 'notice',
types: ['notice', 'success', 'error', 'warning', 'system'],
};
}
}
```
Now you can use:
```typescript
this.flashMessages.notice('Check this out!');
this.flashMessages.system('Maintenance scheduled for tonight.');
this.flashMessages.error('Something went wrong!');
```
#### Example 4: Sticky Messages with Custom Close
For messages that require user interaction:
```typescript
// app/services/flash-messages.ts
import { FlashMessagesService } from 'ember-cli-flash';
export default class FlashMessages extends FlashMessagesService {
get flashMessageDefaults() {
return {
...super.flashMessageDefaults,
sticky: true, // Don't auto-dismiss
destroyOnClick: false, // Allow interaction without dismissing
};
}
}
```
Then in your template, use the `close` action:
```handlebars
{{#each this.flashMessages.queue as |flash|}}
{{flash.message}}
{{/each}}
```
#### Example 5: High-Priority System Notifications
```typescript
// app/services/flash-messages.ts
import { FlashMessagesService } from 'ember-cli-flash';
export default class FlashMessages extends FlashMessagesService {
get flashMessageDefaults() {
return {
...super.flashMessageDefaults,
priority: 100, // Base priority
};
}
// Custom method for high-priority system alerts
systemAlert(message: string) {
return this.add({
message,
type: 'danger',
priority: 500, // Higher than default
sticky: true,
showProgress: false,
});
}
}
```
### TypeScript Support with Generics
The service now supports TypeScript generics for custom fields:
```typescript
// app/services/flash-messages.ts
import { FlashMessagesService } from 'ember-cli-flash';
interface MyCustomFields {
id: string;
userId?: number;
actionUrl?: string;
}
export default class MyFlashMessages extends FlashMessagesService {
get flashMessageDefaults() {
return {
...super.flashMessageDefaults,
timeout: 5000,
};
}
}
```
Then use custom fields when creating messages:
```typescript
this.flashMessages.success('Saved!', {
id: 'save-notification',
userId: 123,
actionUrl: '/dashboard',
});
// Find and remove by custom field
const flash = this.flashMessages.findBy('id', 'save-notification');
this.flashMessages.removeBy('userId', 123);
```
The `FlashMessage` component is also generic and infers the type from the `@flash` arg, giving you type-safe access to custom fields in templates:
```gjs
{{#each this.flashMessages.queue as |flash|}}
{{flash.message}}
{{flash.actionUrl}} {{! ✓ Typed as string | undefined }}
{{/each}}
```
### New Methods: `findBy` and `removeBy`
Two new methods have been added to the service for finding and removing flash messages by any field:
```typescript
// Find a flash message by any field
const message = this.flashMessages.findBy('id', 'notification-123');
// Remove a flash message by any field (returns boolean)
const wasRemoved = this.flashMessages.removeBy('id', 'notification-123');
```
### Component is Now a Glimmer Component
The `FlashMessage` component has been converted to a Glimmer component (`.gts` format). The public API remains the same, but if you were extending it, you'll need to update your code.
### Removed: `_destroyLater` Internal Method
The internal `_destroyLater` method has been removed. Use `destroyMessage()` instead.
---
## Upgrading to v6
### FlashObject is no longer an EmberObject
Most apps will be unaffected by this – unless they call `getFlashObject` to access flash messages.
Prior to v6 `FlashObject` extended [EmberObject](https://api.emberjs.com/ember/release/classes/emberobject/) and supported methods like `get`, `getProperties`, `set`, and `setProperties`.
It's now a native class, and property access can be done using regular dot syntax, eg `flash.get('message')` should be replaced with `flash.message`.
## Upgrading to v5
### Test helpers
In previous versions an install-time blueprint would add a test helper to `tests/helpers/flash-message.js` and import it in `tests/test-helper.js`.
This was used to disable the timeout functionality where a flash message is removed after a delay. For most test suites this is a sensible default.
Apps in which the blueprint ran will have a `tests/helpers/flash-message.js` file.
Take note of whether this helper is present in your app.
#### Helper was present
You should remove the test helper and its import.
```diff
// tests/helpers/flash-message.js
-import { FlashObject } from 'ember-cli-flash';
-
-FlashObject.reopen({ init() {} });
```
```diff
// tests/test-helper.js
import Application from 'example-app/app';
import config from 'example-app/config/environment';
import * as QUnit from 'qunit';
import { setApplication } from '@ember/test-helpers';
import { setup } from 'qunit-dom';
import { start } from 'ember-qunit';
- import './helpers/flash-message';
setApplication(Application.create(config.APP));
setup(QUnit.assert);
start();
```
Flash messages should behave as they did before in your test runs.
#### Helper was not present
Try running your app tests. If they pass then you have nothing more to do.
If your tests failed then they may have been relying on flash message timeouts being enabled.
You may import and invoke the `enableTimeout` helper within your `tests/test-helper.js`. This should restore the flash message timeout behaviour that your tests expect.
```diff
// tests/test-helper.js
import Application from 'example-app/app';
import config from 'example-app/config/environment';
import * as QUnit from 'qunit';
import { setApplication } from '@ember/test-helpers';
import { setup } from 'qunit-dom';
import { start } from 'ember-qunit';
+ import { enableTimeout } from 'ember-cli-flash/test-support';
+ enableTimeout();
setApplication(Application.create(config.APP));
setup(QUnit.assert);
start();
```