4.3.0 • Published 2 years ago

instem-sidebar v4.3.0

Weekly downloads
-
License
-
Repository
-
Last release
2 years ago

InstemSidebar Overview

If you want to use the sidebar you also need to use the mobile nav element, as they'll automatically switch between each other based on screen size.

You must pass an instance of the sidebar into the mobile nav, because it uses it once opened.

Below is a simple example layout using both the <instem-sidebar> and <instem-topnav>. This example shows the original way to add the cofiguration, there are now two ways to configure the menu items which are described later.

    <div class="page-row">
        <instem-sidebar #sidebar [sidebarConfig]="sidebarConfig"></instem-sidebar>

        <div class="page-column">
            <instem-topnav [sidebar]="sidebar"></instem-topnav>

            <!-- your main page content goes here -->

        </div>
    </div>

You must also have the styles from instem.shared.ux imported globally for the layout to work, and the element containing the sidebar must be set to display:flex. If you use the page-row class shown above, everything should work nicely.

Sidebar Configuration

There are now two ways that you are able to configure the sidebar.

Via the markup (Original)

You can set the sidebar menu items using the config model described below in 'Main Configuration Model' within the markup whare the sidebar is placed.

Here in the example below, the config is passed into the markup via the sidebarConfig parameter...

    <div class="page-row">
        <instem-sidebar #sidebar [sidebarConfig]="sidebarConfig"></instem-sidebar>
        <div class="page-column">
            <instem-topnav [sidebar]="sidebar"></instem-topnav>

            <!-- your main page content goes here -->

        </div>
    </div>

By default, this is the expected method of passing a configuration so that the sidebar remains backwards compatible. If a configuration is set via sidebarConfig, the configuration data in this parameter will be used and replace any configuration set by other means.

Via the import of 'InstemSideBarModule'

You can now also configure the sidebar via the module where you have imported the InstemSdieBarModule.

There is now a 'forRoot' method that allows the configuration to be loaded and set as part of the declarations. The forRoot method accepts a special object in the form of a 'Provider'. Here is an example ...

    @NgModule({
    declarations: [
        AppComponent,
        DefaultLayoutComponent
    ],
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        InstemSidebarModule.forRoot({ 
            config: {
                provide: InstemSidebarConfigProvider,
                useClass: SideBarConfig
            }
        }),
        HomeModule
    ],
    providers: [],
    bootstrap: [AppComponent]
    })
    export class AppModule { }

In the code snippet above, you construct an object that contains a 'config' property. The 'config' property expects a provider of InstemSidebarConfigProvider which is a special provider designed to load a dynamically constructed class into the sidebar as it is constructed. The configuration for the menu items can be added to the module above and then specified in the useClass property, or it can reside in a separate code file and be imported. Here is an example of the class used in the snippet above ...

    export class SideBarConfig implements InstemSidebarConfigProvider {
        config: InstemSidebarConfig =
            {
                header: {},
                mainNavItems: [],
                footerNavItems: [],
                texts: {
                    expand: 'Expand',
                    collapse: 'Collapse'
                }
            };

        configData$: Observable<InstemSidebarConfig> = of(this.config);
    }

One important thing to note, the configuration is stored in an observable for the 'forRoot' method. This has been done so that the menu items can be dynamically changed on the fly without having to reload configurations. It is important to build the configuration payload object before adding it to the observable as shown. There can be occassions where adding the payload directly to the observable produces errors that are not actually there, so the example shown should be followed. The original method is not an observable and still takes the configuration as before.

Main Configuration Model

You must provide a config for the sidebar and this is broken down into 4 main parts which are:

Header - This is where you provide content for the very top of the Sidebar. This requires:

  • homelink - This is where you supply the route that should be used when clicking on the top icon, this should be the root of your application
  • largeLogo - This is for the logo that should be used when the sidebar is expanded
  • smallLogo - This is for the logo that should be used when the sidebar in not expanded
  • navItems - This can be used to add some nav items into the header for example settings or logout functionality that shouldn't be in the main nav items

Main Nav Items - This is where you should supply all the nav items you want in the navigation pane, which link to different routes in your nav.

Footer Nav Items - These are nav items that should be pinned to the bottom of your nav, and be displayed by the >> button which expands the sidebar.

Texts - This is where you can override any text hardcoded in the library. Currently this is only the tooltip text for the expand/collapse button, as any other texts should be part of the nav item config.

Nav Items

This will explain how to build up your nav items to be used in the config supplied to the sidebar. Each item should have:

  • text - This is the text that will appear in the sidebar (this should already be translated)
  • id - This is an id you can use to identify the individual items in the sidebar should you need to do any processing on it
  • faIcon - You can supply the name of a FontAwesome icon that will be displayed in the sidebar
  • imageUrl - You can supply this to provide your own image for the icon rather than using a FontAwesome icon
  • svgPath - You can supply this to use an svg for the icon rather than a FontAwesome icon or imageUrl
  • activeRoute - Specifies the route that must be matched to show the 'active' styling
  • enabled - This is a callback function that can be specified that determines whether the link should be enabled or disabled
  • roles - This is an array of strings that specify the roles that are expected to display this menu item. These will cause 'enabled' to be toggled via the new method toggleMenuItemEnabled().
  • permissions - This is an array of strings that specify the permissions that are expected to display this menu item. These will cause 'enabled' to be toggled via the new method toggleMenuItemEnabled().
  • dynamicMenuItem - This is an object of DynamicMenuItem that allows a drop down menu item to host a component sent from the host application that the sidebar is added to. More about this feature is detailed further down this README.

After specifying these you have 4 options for what the item should do in the sidebar. You can only use one of these per item!

  • routerLink - This is a simple Angular routerLink that will direct you to a link in your application.
  • action - This specifies a function that will run when the user clicks this item. This can be used for things like logging out, opening an external link, etc.
  • content - This is another array of Nav Items - this is how you get the accordion / folder effect in the nav. If you specify this, clicking the top nav item will open a second level with whatever you place inside this array. This is recursive.
  • divider - This adds a divider to the sidebar. At present, the divider only displays as a line ( set 'text' to an empty string), or a line with a caption above (set 'text' to the caption to display). Add either 'line' or 'text-line' to this property to add the divider. leaving this unset does not add a divider.

Here is an example configuration ...

{
      header: {
        homeLink: "/",
        smallLogo: { src: './assets/img/instem_logo_small.svg', alt: 'Instem-Logo' },
        largeLogo: { src: './assets/img/instem_logo_large.svg', alt: 'Instem-Logo' },
        navItems: [{
            text: 'Test User',
            imageUrl: './assets/img/generic_user.png',
            id: 'sidebarUserProfileMenuOption',
            content: [{
                text: 'LogOut',
                faIcon: 'fad fa-sign-out',
                roles: ['MyApp'],
                permissions: ['no-permissions'],
                action: () => signOutUser(),
                enabled: () => { return true },
                id: 'sidebarSignOutMenuOption'
            }]
        }]
      },
      mainNavItems: [
        {
            text: 'Dynamic Parent',
            faIcon: 'fad fa-book',
            activeRoute: '/',
            id: 'sidebarDynamicMenuOption',
            dynamicMenuItem: new DynamicMenuItem(ComponentFromHost, { some data from host for component}),
            content: undefined
        },
        {
            text: 'A Divider',
            id: 'sidebarMenuDivider',
            divider: 'text-line',
        },
        {
          text: 'Main Parent',
          faIcon: 'fad fa-search',
          activeRoute: '/home',
          id: 'sidebarMenuTopLevel',
          content: [
            {
              id: 'sidebarItemOne',
              text: 'Main Child #1',
              faIcon: 'fad fa-chart-pie',
              routerLink: '/home/page-one',
              roles: ['MyApp'],
              permissions: ['MyApp.PageOne.View', 'MyData.View'],
              enabled: () => { return true }
            },
            {
              id: 'sidebarItemTwo',
              text: 'Main Child #2',
              faIcon: 'fad fa-chart-bar',
              routerLink: '/home/page-two',
              roles: ['MyApp'],
              permissions: ['MyApp.PageTwo.View', 'MyData.View'],
              enabled: () => { return true }
            },
          ]
        },
        {
            text: '',
            id: 'sidebarMenuDividerLine',
            divider: 'line',
        },
        {
            text: 'Simple Action Link',
            faIcon: 'fad fa-alien',
            id: 'sidebarInsightsMenuAction',
            routerLink: '/somewhere-else',
        },
        {
            text: 'Simple Action Button',
            faIcon: 'fad fa-alien',
            id: 'sidebarInsightsMenuAction',
            action: () => fakeAction(),
        },
      ],
      footerNavItems: [],
      texts: {
        expand: 'Expand',
        collapse: 'Collapse'
      }
    }

Dynamic Drop Down Menu Items

A dynamic menu item can be added to the menu which consists of a dropdown container into which, a component within the host application can be dynamically loaded into the dropdown container. These menu items require a special object ( DynamicMenuItem ) to be added to the property dynamicMenuItem within the menu configuration. Conceivably, ANY component can be loaded into the dropdown container, however, consideration should be taken as to how much the component will obscure the main user interface and other menu items.

The special object is made up as follows:

    export class DynamicMenuItem {
        constructor(public component: Type<any>, public data: any) {}
    }

A dynamic menu item can be added as follows:

    {
        text: 'Dynamic Parent',
        faIcon: 'fad fa-book',
        activeRoute: '/',
        id: 'sidebarDynamicMenuOption',
        dynamicMenuItem: new DynamicMenuItem(
            ComponentFromHost,
            { some data from host for component }
        ),
        content: undefined
    }

...where ComponentFromHost is the component you wish to load into the dynamic dropdown and { some data from host for component } is any data payload the component may require.

Content Projection

Any non-standard content can be added to various sections of the sidebar like so:

<instem-sidebar>
    <ng-container top-panel>
        <!-- Content to put in the top panel -->
    </ng-container>

    <ng-container body-panel>
        <!-- Content in the middle section! -->
    </ng-container>

    <ng-container bottom-panel>
        <!-- Content in the bottom panel -->
    </ng-container>
</instem-sidebar>

Roles/Permissions Checking

The sidebar component is now able to check an authenticated user's roles and/or permissions and enable/disable menu items as the sidebar loads. To check roles and permissions, three elements must be in place.

  • User's Roles and/or Permissions - The sidebar needs to know what the user has in terms of their roles and/or permissions. These are passed into a new method named toggleMenuItemEnabled().
  • Expected Roles and/or Permissions on menu items - The sidebar also needs to know what roles and/or permissions to look for. These are defined as part of the sidebar configuration and simply string arrays of the roles/permission names.
  • Option to check switched on - Finally, the option 'useSidebarRolesAndPermissionsValidation' must be set to true to enable the checking to take place. You can enable this in your component hosting the sidebar.

    @Component({
        selector: 'app-default-layout',
        templateUrl: './default-layout.component.html',
        styleUrls: ['./default-layout.component.scss']
    })
    export class DefaultLayoutComponent implements AfterViewInit {
        @ViewChild('sidebar', { static: false }) sidebar: InstemSidebarComponent;
        public sidebarConfig: InstemSidebarConfig;

        constructor() {
            this.sidebar.useSidebarRolesAndPermissionsValidation(true);
        }
    }

Code scaffolding

Run ng generate component component-name --project instem-sidebar to generate a new component. You can also use ng generate directive|pipe|service|class|guard|interface|enum|module --project instem-sidebar.

NOTE: Don't forget to add --project instem-sidebar or else it will be added to the default project in your angular.json file.

Build

Run ng build instem-sidebar to build the project. The build artifacts will be stored in the dist/ directory.

Publishing

After building your library with ng build instem-sidebar, go to the dist folder cd dist/instem-sidebar and run npm publish.

Running unit tests

Run ng test instem-sidebar to execute the unit tests via Karma.

Further help

To get more help on the Angular CLI use ng help or go check out the Angular CLI Overview and Command Reference page.

Changelog:

Version 4.3.0

Version 4.2.0

  • Updated Instem.Shared.UX to 4.20.0
  • Added the ability to add a dynamic menu item as a dropdown that can host a component contained within the host application
  • Added the ability to insert a divider as just a basic line or with a caption.
  • Updated and refactored styling to current Instem requirements for a sidebar
  • Updated test project to show new features for developer guidance

Version 4.1.1

  • Updated to Angular 13.3
  • Added ability to send configuration from a 'forRoot' method via the app.module of an Angular project
  • Added additional fields to the menu item models to allow each menu item to have a list of permissions expected.
  • Added ability to dynamically enable/disable menu items based on the authenticated users permissions using the new method toggleMenuItemEnabled() and option useSidebarRolesAndPermissionsValidation()
  • Added an internal experimental test project Instem-Sidebar-Checker to allow experimetal development of the siderbar features in isolation. This is NEVER deployed!

Version 4.0.0

  • Updated to Angular 13
  • Updated all other packages to appropriate latest versions.
  • Changed from tslint to eslint and fixed linting issues.

Version 3.0.1

  • Reverted RxJs package to back to 6.6.7 version as Angular 12 does not support RxJs V7 yet.
  • Updated to latest Angular 12 revision of 12.1.1.
  • Updated Instem UX package to latest version.

Version 3.0.0

  • Updated to Angular 12.
  • Updated packages to latest version except Bootstrap and body-scroll-lock packages.

Version 2.1.0

  • Added slots for content projection Anything can now be added to all three of the main sidebar sections.

Version 2.0.0

  • Updated to Angular 11.
  • Updated to instem.shared.ux 3.5.0.
  • Updated to Typescript 4.1.5.
  • Update jasmine and karma packages.
  • Updated peer dependencies to match updated package version.

Version 1.0.1

  • Changed import to import just the variables rather than the entire instem-shared ux.

Version 1.0.0

  • Fixed icons on unexpanded menu select when using img or svg.

Version 0.0.5

  • Fixed default text to match Gateway.
  • Updated readme to specify you must import the instem ux globally.
  • Added simple svg support for icons.

Version 0.0.2

  • Added correct dependencies to peer dependencies so that consuming applications know what to install.
  • Added texts to config to supply expand and collapse texts used in tooltips (these default to English if not supplied).
  • Updated readme to explain how to use the library and what to supply in the config.
  • Added description to project so that it populates in the artifact library.

Version 0.0.1

  • This library was initially generated with Angular CLI version 10.2.4.
  • All sidebar specific code has been moved to the library from Gateway.
  • Changed selectors to be more descriptive.
  • Inlined styles from the IUX.
  • Changed the action of a nav item to be a callback so it can be controlled from the calling application.
  • Changed the enabled property of a nav item to be a callback for the same reason.
  • Added a config object Input property to sidebar component to pass in nav links / icons / actions etc.