# Theming You can override pretty much all the HTML generated by ng-admin, at different levels. ## Stylesheet Ng-admin CSS is composed of styles from [sb-admin](http://ironsummitmedia.github.io/startbootstrap-sb-admin-2/), on top of [Bootstrap 3](http://getbootstrap.com/). By using your own CSS in addition to the ng-admin CSS, you can customize the look and feel of every displayed component. To ease styling, ng-admin adds custom classes for the entities and fields currently displayed, to allow a finer styling. For instance, the datagrid in the list view always uses a class named `ng-admin-entity-[entityName]`. In the datagrid also, each header in the table uses a class named `ng-admin-column-[fieldName]`, which should allow precise sizing of columns. Don't hesitate to inspect the generated source to look for the right CSS selector. ## Custom Classes To ease theming, you can add a custom class to your fields in every view, using the `cssClasses()` method. ```js myEntity.listView().fields([ nga.field('title').cssClasses(['foo', 'bar']) ]); ``` `cssClasses()` can optionally accept a function, to return a class depending on the current entry. ```js myEntity.listView().fields([ nga.field('title').cssClasses(function(entry) { if (entry && entry.values && entry.values.publishDate >= Date.now()) { return 'bg-success'; } }) ]); ``` The `listView` calls `cssClasses()` for each datagrid cell, and for the datagrid headers. There is no active 'entry' in headers, that's why you should always check that the `entry` parameter is defined in a `cssClasses` function. ## Customizing The Template For A Given Field All field types support the `template()` method, which makes it easy to customize the look and feel of a particular field, without sacrificing the native features. For instance, if you want to customize the appearance of a `NumberField` according to its value: ```js listview.fields([ nga.field('amount', 'number') .format('$0,000.00') .template('') ]); ``` The template scope exposes the following variables: * `value`, `field`, `entry`, `entity`, and `datastore` in `listView` and `showView` * `value`, `field`, `values`, and `datastore` in filters * `value`, `field`, `entry`, `entity`, `form`, and `datastore` in `editionView` and `creationView` In `showView`, `editionView`, and `creationView`, the template zone covers only the field itself - not the label. To force the template to replace the entire line (including the label), pass `true` as second argument to the `template()` call. This can be very useful to conditionally hide a field according to a property of the entry: ```js post.editionView() .fields([ nga.field('category', 'choice') .choices([ { label: 'Tech', value: 'tech' }, { label: 'Lifestyle', value: 'lifestyle' } ]), nga.field('subcategory', 'choice') .choices(function(entry) { return subCategories.filter(function (c) { return c.category === entry.values.category; }); }) // display subcategory only if there is a category .template('', true), ]); ``` Most of the time, `template()` is used to customize the existing ng-admin directives (like `ma-number-column>` in the previous example), for instance by decorating them. If you want to learn about these native directives, explore the [column](../src/javascripts/ng-admin/crud/column), [field](../src/javascripts/ng-admin/crud/field), and [fieldView](../src/javascripts/ng-admin/crud/fieldView) directories in ng-admin source. ## Customizing Directives Templates Using Angular's [`$provide`](https://docs.angularjs.org/api/auto/service/$provide) service, and the ability to decorate another provider, you can customize the template of any directive used by ng-admin for your entire application. Here is an example of customization of the 'text' input field: ```js var myApp = angular.module('myApp', ['ng-admin']); myApp.config(function(NgAdminConfigurationProvider, $provide) { // Override textarea template $provide.decorator('maTextFieldDirective', ['$delegate', function ($delegate) { // You can modify directly the template $delegate[0].template = angular.element($delegate[0].template).addClass('MyClass')[0].outerHTML; // or use a templateURL (loaded from a file or a tag) $delegate[0].template = ''; $delegate[0].templateUrl = 'string.html'; return $delegate; }]); // ... }); ``` ## Customizing The View Template For A Given Entity For a given entity, each of the main views (`list`, `show`, `create`, `edit`, `delete`) can use a custom HTML template instead of the default one. Just pass it to the `template()` function on the view: ```js var myTemplate = require('text!./path/to/list.html'); var myEntity = nga.entity('foo_endpoint'); myEntity.listView().template(myTemplate); // continue myEntity configuration // ... var admin = nga.application('My Application'); admin.addEntity(myEntity); ``` ## Customizing The View Templates For The Entire Application You can use the `app.customTemplate()` method to customize the template of a given view across the entire application (for all entities). This method expects a function argument, which should return the template as a string. ```js var myTemplate = require('text!./path/to/list.html'); var admin = nga.application('My Application'); admin.customTemplate(function(viewName) { if (viewName === 'ListView') { return myTemplate; } }) ``` ## Customizing the Dashboard If you want to use a custom template dashboard, you must [define a custom dashboard configuration](Dashboard.md). This will give you access to the `dashboard.template()` function: ```js var myTemplate = require('text!./path/to/dashboard.html'); var admin = nga.application('My Application'); admin.dashboard(nga.dashboard() .template(mytemplate) }) ``` ## Customizing the Application Header If you want to override the application header (for instance to add authentication status on the top bar), use the `admin.header()` setter with a valid HTML content. Angular directives are executed in the context of the layout. For instance, to display a custom title and a right aligned link, use the following code: ```js var customHeaderTemplate = '' + ''; var admin = nga.application('My Application'); admin.header(customHeaderTemplate); ``` ## Customizing the Application Layout If the header is not enough, and you need to override the entire application layout use the `admin.layout()` setter: ```js var myLayout = require('text!./path/to/layout.html'); var admin = nga.application('My Application'); admin.layout(myLayout); ``` The original layout can be found in [src/javascripts/ng-admin/Main/view/layout.html](../src/javascripts/ng-admin/Main/view/layout.html). ## Customizing Error Messages You can use the `app.errorMessage()`, `entity.errorMessage()` or `view.errorMessage()` methods to customize the message displayed when an error occurred with the API. These methods expect a function argument with the response as parameter, which should return the message as a string. ```js entity.errorMessage(function (response) { return 'Global error: ' + response.status + '(' + response.data + ')'; }); ``` ## Customizing HTTP Error Messages If you want to override, patch or extend the way HTTP errors are handled by the ng-admin [Http Error Service](../src/javascripts/ng-admin/Main/component/provider/HttpErrorService.js) then you may use an [Angular decorator](https://docs.angularjs.org/guide/decorators), as per the below example: Create a decorator, HttpErrorDecorator.js ```js // Change HTTP 403 error notification to display them as information // and not errors ('humane-flatty-info' instead of 'humane-flatty-error') export const HttpErrorDecorator = ($delegate, $translate, notification) => { $delegate.handle403Error = error => { $translate('STATE_FORBIDDEN_ERROR', { message: error.data.message, }).then(text => notification.log(text, { addnCls: 'humane-flatty-info', })); throw error; }; return $delegate; } HttpErrorDecorator.$inject = ['$delegate', '$translate', 'notification']; export default HttpErrorDecorator; ``` Bind the decorator to your application: ```js myApp.decorator('HttpErrorService',require('HttpErrorDecorator')); ```