Current Version

Angular 9 and PrimeNG 9

Dependencies

Ultima has no direct dependency. More information about dependencies is available at Why PrimeNG Templates article.

Getting Started

Ultima is a true native application template for Angular and is distributed as a CLI project. If you don't have CLI installed already run the following commands to set it up. In case you have an application that do not use CLI, skip the Integration with an Existing Non CLI Application part.

npm install -g @angular/cli

Once CLI is ready in your system, extract the contents of the ultima zip file distribution, cd to the directory, install the libraries from npm and then execute "ng serve" to run the application in your local environment at http://localhost:4200/.

cd ultima
npm install
ng serve

That's it, you may now start with the development of your application.

Important CLI Commands

Following commands are derived from CLI.

Run 'ng serve' for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.

Run 'ng generate component component-name' to generate a new component. You can also use `ng generate directive/pipe/service/class/module`.

Run 'ng build' to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build.

Run 'ng test' to execute the unit tests via [Karma](https://karma-runner.github.io).

Run 'ng e2e' to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).

Run 'ng help' for more options.

Structure

Ultima consists of 3 main parts; the application layout, layout resources and theme resources for PrimeNG components. app.component.html inside app folder is the html template for the base layout, required resources for the layout are placed inside the src/assets/layout folder and similarly theme resources are inside src/assets/theme folder.

Template

Main layout is the html view of the app.component.ts, it is divided into a couple of sections such as topbar, profile, menu and footer. Here is the code for the main template. The component class app.component.ts implements the logic such as opening menus, layout modes and so on.


<div class="layout-wrapper" [ngClass]="{'layout-compact':layoutCompact}" (click)="onLayoutClick()">

    <div #layoutContainer class="layout-container"
         [ngClass]="{'menu-layout-static': !isOverlay(),
            'menu-layout-overlay': isOverlay(),
            'layout-menu-overlay-active': overlayMenuActive,
            'menu-layout-horizontal': isHorizontal(),
            'menu-layout-slim': isSlim(),
            'layout-menu-static-inactive': staticMenuDesktopInactive,
            'layout-menu-static-active': staticMenuMobileActive}">

        <app-topbar></app-topbar>

        <div class="layout-menu" [ngClass]="{'layout-menu-dark':darkMenu}" (click)="onMenuClick($event)">
            <app-inline-profile *ngIf="profileMode=='inline'&&!isHorizontal()"></app-inline-profile>
            <app-menu></app-menu>
        </div>

        <div class="layout-main">
            <app-breadcrumb></app-breadcrumb>

            <div class="layout-content">
                <router-outlet></router-outlet>

                <app-footer></app-footer>
            </div>
        </div>

        <app-rightpanel></app-rightpanel>
        <app-config></app-config>

        <div class="layout-mask"></div>
    </div>

</div>

Menu

Menu is a separate component defined in app.menu.component.ts file based on PrimeNG MenuModel API. In order to define the menuitems, navigate to this file and define your own model as a nested structure. Here is the menu component from the sample application.


import {Component, OnInit} from '@angular/core';
import {AppMainComponent} from './app.main.component';

@Component({
    selector: 'app-menu',
    template: `
		<ul class="ultima-menu ultima-main-menu clearfix">
			<li app-menuitem *ngFor="let item of model; let i = index;" [item]="item" [index]="i" [root]="true"></li>
		</ul>
    `
})
export class AppMenuComponent implements OnInit {

    model: any[];

    constructor(public app: AppMainComponent) {}

    ngOnInit() {
        this.model = [
            {label: 'Dashboard', icon: 'dashboard', routerLink: ['/']},
            {
                label: 'Components', icon: 'list', badge: '2', badgeStyleClass: 'teal-badge', routerLink: ['/components'],
                items: [
                    {label: 'Sample Page', icon: 'desktop_mac', routerLink: ['/components/sample']},
                    {label: 'Forms', icon: 'input', routerLink: ['/components/forms']},
                    {label: 'Data', icon: 'grid_on', routerLink: ['/components/data']},
                    {label: 'Panels', icon: 'content_paste', routerLink: ['/components/panels']},
                    {label: 'Overlays', icon: 'content_copy', routerLink: ['/components/overlays']},
                    {label: 'Menus', icon: 'menu', routerLink: ['/components/menus']},
                    {label: 'Messages', icon: 'message', routerLink: ['/components/messages']},
                    {label: 'Charts', icon: 'insert_chart', routerLink: ['/components/charts']},
                    {label: 'File', icon: 'attach_file', routerLink: ['/components/file']},
                    {label: 'Misc', icon: 'toys', routerLink: ['/components/misc']}
                ]
            },
            {
                label: 'Template Pages', icon: 'get_app', routerLink: ['/pages'],
                items: [
                    {label: 'Empty Page', icon: 'hourglass_empty', routerLink: ['/pages/empty']},
                    {label: 'Invoice', icon: 'content_paste', routerLink: ['/pages/invoice']},
                    {label: 'Wizard', icon: 'star', routerLink: ['/wizard']},
                    {label: 'Help', icon: 'help', routerLink: ['/pages/help']},
                    {label: 'Landing Page', icon: 'flight_land', url: 'assets/pages/landing.html', target: '_blank'},
                    {label: 'Login Page', icon: 'verified_user', routerLink: ['/login'], target: '_blank'},
                    {label: 'Error Page', icon: 'error', routerLink: ['/error'], target: '_blank'},
                    {label: '404 Page', icon: 'error_outline', routerLink: ['/404'], target: '_blank'},
                    {label: 'Access Denied Page', icon: 'security', routerLink: ['/accessdenied'], target: '_blank'}
                ]
            },
            {
                label: 'Menu Hierarchy', icon: 'menu',
                items: [
                    {
                        label: 'Submenu 1', icon: 'subject',
                        items: [
                            {
                                label: 'Submenu 1.1', icon: 'subject',
                                items: [
                                    {label: 'Submenu 1.1.1', icon: 'subject'},
                                    {label: 'Submenu 1.1.2', icon: 'subject'},
                                    {label: 'Submenu 1.1.3', icon: 'subject'},
                                ]
                            },
                            {
                                label: 'Submenu 1.2', icon: 'subject',
                                items: [
                                    {label: 'Submenu 1.2.1', icon: 'subject'},
                                    {label: 'Submenu 1.2.2', icon: 'subject'}
                                ]
                            },
                        ]
                    },
                    {
                        label: 'Submenu 2', icon: 'subject',
                        items: [
                            {
                                label: 'Submenu 2.1', icon: 'subject',
                                items: [
                                    {label: 'Submenu 2.1.1', icon: 'subject'},
                                    {label: 'Submenu 2.1.2', icon: 'subject'},
                                    {label: 'Submenu 2.1.3', icon: 'subject'},
                                ]
                            },
                            {
                                label: 'Submenu 2.2', icon: 'subject',
                                items: [
                                    {label: 'Submenu 2.2.1', icon: 'subject'},
                                    {label: 'Submenu 2.2.2', icon: 'subject'}
                                ]
                            },
                        ]
                    }
                ]
            },
            {label: 'Utils', icon: 'build', routerLink: ['/utils']},
            {label: 'Documentation', icon: 'find_in_page', routerLink: ['/documentation']}
        ];
    }
}

Integration with an Existing CLI Project

To setup Ultima in an existing project, copy the src/assets folder to your projects folder with the same name and replace the contents of app.component.ts, app.component.html with their counterparts in Ultima under src/app folder.

Install PrimeNG

npm install primeng@latest --save
npm install primeicons@latest --save

Add PrimeNG CSS at styles section in angular.json.


"styles": [
    "../node_modules/primeng/resources/primeng.min.css",        //required: PrimeNG components
    "node_modules/primeicons/primeicons.css",                   //required: PrimeIcons
    "styles.scss"                                               //your styles and overrides
]

Last part is adding theme and layout css files, in the CLI app they are defined using link tags in index.html so the demo can switch them on the fly by changing the path however if this is not a requirement, you may also add them to the styles configuration so they go inside the bundle.

Integration with an Existing Non-CLI Project

For an existing project that do not use CLI, setup steps are more or less similar. Start with installing the dependencies listed above in package.json

Copy the src/assets folder to your application and include the resources listed above with a module bundler like webpack or using link-script tags.

Finally copy the contents of app.component.html to your application's main component template such as app/application.html along with the sub components which are app.menu.component.ts, app.profile.components.ts, app.topbar.component.ts and app.footer.component.ts.

Size

Ultima uses EM units for scalability and comes in two built-in sizes, default is closer to the material design specification with bigger fonts and paddings whereas the alternative compact size shrinks the dimensions of the UI elements. To activate the compact mode add "layout-compact" style class to the .layout-wrapper element in application.html which is the enclosing div of whole content.

Theme

Ultima provides 12 PrimeNG themes out of the box, setup of a theme simple including the css of theme to your page that are located inside resources/theme folder.

  • theme-blue
  • theme-blue-grey
  • theme-brown
  • theme-cyan
  • theme-dark-blue
  • theme-dark-green
  • theme-green
  • theme-grey
  • theme-indigo
  • theme-purple-amber
  • theme-purple-cyan
  • theme-teal

A custom theme can be developed by the following steps.

  • Choose a custom theme name such as theme-myown.
  • Create a file named theme-myown.scss under assets/theme folder.
  • Define the variables listed below and import the /sass/theme/_theme.scss file.
  • Build the scss to generate css
  • Include the generated theme.css to your page.

Here are the variables required to create a theme, you may need to change the last line according to the relative path of the sass folder in your application.


$primaryColor: #009688;
$primaryDarkColor: #00695C;
$primaryLightColor: #80CBC4;
$accentColor: #CDDC39;
$accentDarkColor: #9E9D24;
$accentLightColor: #E6EE9C;
$accentTextColor: #212121;

@import '../sass/theme/_theme';

An example sass command to compile the css would be;

sass src/assets/theme-myown/theme.scss src/assets/theme-myown/theme.css

Watch mode is handy to avoid compiling everytime when a change is made, instead use the following command so that sass generates the file whenever you make a customization. This builds all css files whenever a change is made to any scss file.

sass --watch src/:src/ --no-source-map

Same can also be applied to layout itself;

  • Choose a layout name such as layout-myown.
  • Create an empty file named layout-myown.scss inside assets/layout/css folder.
  • Define the variables listed below and import the /sass/layout/_layout.scss file.
  • Build the scss to generate css
  • Serve the css by importing it using a link tag or a bundler.

Here are the variables required to create a layout, you may need to change the last line according to the relative path of the sass folder in your application.


$primaryColor: #3F51B5;
$primaryDarkColor: #283593;
$primaryLightColor: #9fa8da;
$accentColor: #E91E63;
$accentDarkColor: #ad1457;
$accentLightColor: #f48fb1;
$accentTextColor: #ffffff;
$darkMenuBgColor: #424242;
$darkMenuHoverColor: #676767;
$darkMenuRouterLinkActiveColor: #9fa8da;
$lightMenuRouterLinkActiveColor: #3F51B5;
$horizontalLightMenuRouterLinkActiveColor: #9fa8da;

@import '../../sass/layout/_layout';

Common SASS Variables

In case you'd like to customize the shared variables, the _variables.scss files are where the options are defined for both layout and theme.

sass/_variables.scss


/* Common */
$textColor:#212121;
$textSecondaryColor:#757575;
$fontSize:16px;
$fontFamily:"Roboto","Helvetica Neue",sans-serif;
$lineHeight:1.5em;
$transitionDuration:.3s;
$borderRadius:3px;
$inputOptionPadding:.625em .875em;
$hoverBgColor:#e8e8e8;
$hoverTextColor:#000000;
$activeMenuItemBadgeColor:#ffffff;
$activeMenuItemBadgeTextColor:#212121;
$dividerColor:#bdbdbd;
$letterSpacing:.25px;

/* Compact */
$c-fontSize:14px;
$c-lineHeight:18px;

$blueGrey:#607D8B;
$blueGreyHover:#37474F;
$cyan:#00BCD4;
$cyanHover:#00838F;
$teal:#009688;
$tealHover:#00695C;
$red:#F44336;
$redHover:#C62828;
$green:#4CAF50;
$greenHover:#2E7D32;
$deepOrange:#FF5722;
$deepOrangeHover:#D84315;
$purple:#673AB7;
$purpleHover:#4527A0;
$pink:#E91E63;
$pinkHover:#AD1457;
$amber:#FFC107;
$amberHover:#FF8F00;
$orange:#FF9800;
$orangeHover:#EF6C00;
$brown:#795548;
$brownHover:#4E342E;
$indigo:#3F51B5;
$indigoHover:#283593;
$blue:#03A9F4;
$blueHover:#0277BD;
$secondary:#ffffff;
$grayBgColor:#757575;

sass/layout/_variables


@import "../variables";

/* Layout */
$bodyBgColor:#f7f7f7;
$maskBgColor:#424242;
$formGroupPadding:1em;

/* Topbar */
$topbarButtonColor:#ffffff;
$topbarButtonHoverColor:#e8e8e8;
$topbarSearchBorderColor:#ffffff;
$topbarSearchColor:#ffffff;
$topbarIconColor:#ffffff;
$topbarIconHoverColor:#e8e8e8;
$topbarMenuBgColor:#ffffff;
$topbarSubmenuBgColor:#ffffff;

/* Menus */
$darkMenuColor:#ffffff;
$layoutMenuBgColor:#ffffff;
$layoutMenuScrollbarBgColor:#aaaaaa;
$layoutMenuItemIconColor:#757575;
$layoutMenuItemActiveColor:#e8e8e8;
$horizontalLayoutMenuItemTextColor:#ffffff;
$horizontalLayoutMenuItemHoverBgColor:#e8e8e8;
$horizontalLayoutMenuSubMenuBgColor:#ffffff;
$horizontalLayoutMenuSubMenuActiveBgColor:#e8e8e8;
$horizontalDarkLayoutMenuItemTextColor:#ffffff;
$slimLayoutMenuSubMenuBgColor:#ffffff;
$slimMenuTooltipColor:#ffffff;
$rightPanelBgColor:#ffffff;
$profileMenuBorderBottomColor:#d6d5d5;
$profileMenuDarkBorderBottomColor:#545454;

sass/theme/_variables


@import "../variables";
$iconFontSize:1.5em;
$primaryTextColor:#ffffff;

$headerPadding:.714em 1em;
$headerBgColor:$primaryColor;
$headerTextColor:#ffffff;
$headerIconColor:#ffffff;
$headerFontWeight:500;
$headerFontSize:1em;

$contentPadding:.857em 1em;
$contentBorderColor:#bdbdbd;
$contentBgColor:#ffffff;
$contentFontSize:1em;
$contentIconColor:#757575;

$inputBorderColor:#bdbdbd;
$inputInvalidBorderColor:#e62a10;
$inputBgColor:transparent;
$inputErrorTextColor:#e62a10;
$inputHeaderPadding:.714em 1em;
$inputBorderErrorColor:#e62a10;
$inputFieldLabelTextColor:#999999;
$inputFieldBoxBgColor:#f7f7f7;
$inputFieldFillBgColor:#f7f7f7;
$inputAutoFillBorderColor:#bdbdbd;
$textboxBgColor:#f7f7f7;

//inputs with lists
$inputListPadding: .5em 0;

//groups
$inputGroupBorderColor:#bdbdbd;
$inputGroupBgColor:transparent;
$inputGroupTextColor:$textSecondaryColor;
$inputGroupIconColor:$textSecondaryColor;
$inputGroupAddonMinWidth:2*$fontSize;
$checkboxWidth:18px;
$checkboxHeight:18px;
$inputGroupPadding:2px 2px 1px 2px;
$inputGroupIconFontSize: 1.5em;

//panels
$accordionHeaderBgColor:$primaryColor;
$accordionHeaderTextColor:#ffffff;
$accordionHeaderHoverBgColor:$primaryDarkColor;
$accordionHeaderHoverTextColor:#ffffff;

$panelContentLineHeight:1.5;

$buttonTextColor:#ffffff;

$listItemPadding:.571em .857em;

$radioButtonBorderColor:#757575;
$checkboxBorderColor:#757575;

$errorMessageFontSize:11px;
$errorMessageIconFontSize:13px;

//data
$dataTableHeaderPadding:.857em;
$dataTableCellPadding:.714em .857em;
$dataTableRowBgColorEven:#f4f4f4;
$paginatorPadding:.714em 1em;

//menus
$menuitemPadding:.571em .857em;
$menuListPadding: .5em 0;

Menu Item Badges

Badges are numerical indicators associated with a link. The badge property is the value of the badge and badgeStyleClass is style class of the badge.


label: 'Components', icon: 'list', badge: '2', badgeStyleClass: 'red-badge'

Default badge uses the accent color of ultima layout and there are three more alternative colors.

  • red-badge
  • purple-badge
  • teal-badge

Menu Modes

Menu has 4 modes, static, overlay, slim and horizontal. Layout container element in application.html is used to define which mode to use by adding specific classes. List below indicates the style classes for each mode. In addition menu

  • Static: "layout-wrapper menu-layout-static"
  • Overlay: "layout-wrapper menu-layout-overlay"
  • Slim: "layout-wrapper menu-layout-static menu-layout-slim"
  • Horizontal: "layout-wrapper menu-layout-static menu-layout-horizontal"

For example to create a horizontal menu, the div element should be in following form;


<div class="layout-wrapper layout-compact">
    <div class="layout-container menu-layout-static menu-layout-horizonal">

It is also possible to leave the choice to the user by keeping the preference at a component and using an expression to bind it so that user can switch between modes. Sample application has an example implementation of such use case. Refer to app.component.ts for an example.

Dark Menu

Default color scheme of menu is light and alternative dark mode can be activated by adding layout-menu-dark style class to the menu container that is an element having .layout-menu as its class.


<div class="layout-menu layout-menu-dark">

Profile Modes

There are two possible locations for the user profile menu, first version is inline located inside the main menu and second option is the topbar menu. For inline mode, profile content should be placed above the menu and for inline mode content goes in topbar-items list. The sample demo application provides examples for both cases.

Utilities

Ultima provides various helper features such as material iconset compatible with PrimeNG components and helper classes. Visit utils page for details.

Breadcrumb

Ultima has an optional built-in breadcrumb section right below the topbar. The items are dynamically generated using a BreadcrumbService where each main page that goes into the router-outlet should provide a collection of MenuItem instances. Here is an example component that updates the breadcrumb.


import {Component} from '@angular/core';
import {BreadcrumbService} from '../../breadcrumb.service';

@Component({
    templateUrl: './emptydemo.component.html'
})
export class ControlPanelComponent {

    constructor(private breadcrumbService: BreadcrumbService) {
        this.breadcrumbService.setItems([
            {label: 'Admin'},
            {label: 'Control Panel', routerLink: ['/controlpanel']}
        ]);
    }

}

Result will be reflected at application breadcrumb component such as "Home Icon" -> "Admin" -> "Control Panel".

Grid CSS

Ultima uses PrimeNG Grid CSS (ui-g-*) throughout the samples, we strongly suggest using Grid CSS or PrimeFlex as your layout framework as it is well tested and supported by PrimeNG. Grid CSS is available inside primeng.css whereas PrimeFlex requires to be installed.

Customizing Styles

It is suggested to add your customizations in the following sass files under the override folder instead of adding them to the scss files under sass folder to avoid maintenance issues after an update.

  • _layout_variables: Variables of the layout.
  • _layout_styles: Styles for the layout.
  • _theme_variables: Variables of the theme.
  • _theme_styles: Styles for the theme.

Migration Guide

8.0.1 to 9.0.0

Angular 9 and PrimeNG 9

  • Update dependencies with ng update.
  • Update theme.css and layout.css files.
  • Update app.menu.component.ts while retaining your MenuModel.
  • Include app.menuitem.component.ts under app folder and define it app.module.ts with declarations property.
  • Include app.menu.service.ts under app folder and define it app.module.ts with providers property.

8.0.0 to 8.0.1

  • Update layout css files.
  • Update theme css files.

7.1.1 to 8.0.0

  • Update your project to Angular 8 with ng update. View the official update guide -https://update.angular.io/- for more information.
  • Update app.main.component.ts.
  • Update app.menu.component.ts.
  • Update app.rightpanel.component.ts.
  • Update layout css files.
  • Update theme css files.

7.1.0 to 7.1.1

  • Update layout css files.
  • Update theme css files.

7.0.1 to 7.1.0

  • Update layout css files.
  • Update theme css files.

7.0.0 to 7.0.1

  • Update theme css files.

6.1.1 to 7.0.0

  • Update layout css files.
  • Update theme css files.

6.1.0 to 6.1.1

  • Update layout css files.
  • Update theme css files.

6.0.0 to 6.1.0

Adds support for new features in PrimeNG 6.1.x

  • Update theme css files.

5.2.4 to 6.0.0

Brings support for Angular 6 and RxJS 6, adds theming for new components in PrimeNG such as the new TreeTable and improves behaviors of the layout menus.

  • Update app.module.ts and app.component.ts.
  • Update app.topbar.component.ts.
  • Update app.profile.component.ts.
  • Update app.menu.component.ts.
  • Update app.breadcrumb.component.ts and breadcrumb.service.ts.
  • Update layout css files.
  • Update theme css files.

5.2.3 to 5.2.4

  • Update theme css files.

5.2.2 to 5.2.3

  • Update layout css files.
  • Update theme css files.

5.2.1 to 5.2.2

  • Update layout css files.
  • Update theme css files.

5.2.0 to 5.2.1

Aligns input focus animation with the Material specs.

  • Update layout css files.
  • Update theme css files.

5.0.0 to 5.2.0

Adds support for PrimeNG 5.2.0 (e.g. TurboTable), replaces nanoscroller with PrimeNG ScrollPanel and reimplements ripple effect to run outside of NgZone for better performance.

  • Remove nanoscroller as it is replaced by ScrollPanel component of PrimeNG.
  • Update app.component.ts and app.component.html.
  • Update app.menu.component.ts.
  • Update app.rightpanel.component.ts.
  • Update layout css files.
  • Update theme css files.

4.3.0 to 5.0.0

  • Update app.component.ts and app.component.html.
  • Define breadcrumbservice as a provider in your app.module
  • Update layout css files.
  • Update theme css files.

4.2.0 to 4.3.0

  • Update theme css files.

4.1.1 to 4.2.0

  • Update app.*.ts and app.*.html files under app folder.
  • Update theme css and layout css files.

4.0.1 to 4.1.0

  • Update layout css files.
  • Update theme css files.
  • Update AppSubmenu component in app.menu.component.ts.

4.0.0 to 4.0.1

  • Update layout css files.

2.1 to 4.0.0

  • Includes version updates to PrimeNG 4 and Angular 4.
  • Update theme css files.

2.0.5 to 2.1.0

  • Project is updated to CLI RC2, Angular 4-RC3 and PrimeNG 4-RC1.
  • Add import {trigger,state,style,transition,animate} from '@angular/animations'; to app.menu.components.ts and remove these imports from 'angular/core'.
  • Add import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; to app.module.ts and import the module to your application.
  • Update theme css files, there are no changes to the layout.

2.0.4 to 2.0.5

  • No change required, missing .angular-cli.json file in 2.0.4 is added.

2.0.3 to 2.0.4

  • No change required, only CLI version is updated to RC

2.0.2 to 2.0.3

  • Update AppSubmenu component in app.menu.component.ts by replacing the itemClick method implementation.
  • Update layout css files, there are no changes on themes.
  • Update app.component.ts by changing onTopbarMenuButtonClick method implementation to add event.preventDefault() at the end.
  • Remove [ngClass]="{'menu-button-rotate': app.rotateMenuButton}" from menu-button in app.topbar.component.ts.

2.0.1 to 2.0.2

  • Update AppSubmenu component in app.menu.component.ts
  • Update layout css files, there are no changes on themes.
  • Update app.component.ts.
  • Add pInputText to search input at app.topbar.component.ts

2.0.0 to 2.0.1

  • Update AppSubmenu component in app.menu.component.ts
  • Update layout css and theme css files.
  • Update app.component.ts.

1.1.0 to 2.0.0

  • Update PrimeNG to at least 2.0.
  • Replace app.component.ts and app.component.html
  • Remove layout.js
  • Update the scripts and styles section at angular-cli.json
  • Define menu using PrimeNG MenuModel

1.0.3 to 1.1.0

  • Update css files of layout and theme.

1.0.2 to 1.0.3

  • Update css files of layout and theme.

1.0.1 to 1.0.2

  • Update layout.js

1.0.0 to 1.0.1

  • Update layout.js