Open Closed

After upgrading to Abp 9 our sidebar is missing #10016


User avatar
0
JanneHarju created
  • Exception message and full stack trace: -
  • Steps to reproduce the issue:

We are using lepton theme with angular. Angular is updated to 20 when Abp was updated to 9.3.4. Now after updates I managed to get UI open there is no side bar at left. I noticed in browser that there is empty layout inside dynamic layout instead of application layout which contains all necessary things. Do you have experience with Abp 9 with lepton theme?


20 Answer(s)
  • User Avatar
    0
    AI-Bot created
    Support Team ABP Agent
    • With ABP 9.x and Angular 20, the LeptonX theme and its layout system have changed. In recent versions, the side menu and layout components were refactored, and some component names were updated. If your sidebar is missing, it is likely due to outdated imports or configuration.

    Steps to resolve:

    1. Update LeptonX Theme Packages

      • Ensure you are using the latest compatible version of @abp/ng.theme.lepton-x (for open-source) or @volosoft/abp.ng.theme.lepton-x (for commercial) that matches your ABP version.
    2. Update Angular Module Imports

      • In your app.module.ts, remove any old Lepton/LeptonX theme modules and import the new ones:
    import { ThemeLeptonXModule } from '@abp/ng.theme.lepton-x';
         import { SideMenuLayoutModule } from '@abp/ng.theme.lepton-x/layouts';
    
         @NgModule({
           imports: [
             // ...
             ThemeLeptonXModule.forRoot(),
             SideMenuLayoutModule.forRoot(),
           ],
           // ...
         })
         export class AppModule {}
    
    • For commercial: use @volosoft/abp.ng.theme.lepton-x and AbpSideMenuLayoutModule.
    1. Check angular.json Styles
      • Remove any direct Bootstrap CSS import. Add the LeptonX CSS and Bootstrap Icons:
    "styles": [
           "node_modules/@volo/ngx-lepton-x.lite/styles/sidemenu-layout.min.css",
           "node_modules/bootstrap-icons/font/bootstrap-icons.css"
         ]
    
    • For commercial, use the corresponding @volosoft/ngx-lepton-x paths.
    1. Migration Changes

      • In ABP 7.0+, the layout component names changed:
        • eThemeLeptonXComponents.NavbareThemeLeptonXComponents.Toolbar
        • eThemeLeptonXComponents.SidebareThemeLeptonXComponents.Navbar
      • If you use replaceable components, update their references as per the new naming.
    2. Clear Cache and Rebuild

      • Delete node_modules, run npm install or yarn, and rebuild your project.
    3. Verify Layout Usage

      • Ensure your main layout uses the correct dynamic layout selector for LeptonX. If you customized layouts, update them to use the new component structure.

    If you still see an empty layout:

    • Double-check that you are not mixing old and new LeptonX modules.
    • Compare your app.module.ts and angular.json with a fresh ABP 9.x Angular template using LeptonX.

    References:


    This response was generated by AI. If it didn’t solve your problem, feel free to post a new answer — our support team will jump in to help you soon.

  • User Avatar
    0
    JanneHarju created

    So we are not using LeptonX-theme. We have exported theme-lepton in our angular project and we have made some modifications. It was working in 8.3.4 version what we were using earlier.

  • User Avatar
    0
    JanneHarju created

    Here is our ThemeLeptonModule if problem is related to it:

    import { APP_INIT_ERROR_HANDLERS, CoreModule } from '@abp/ng.core';
    import { ThemeSharedModule } from '@abp/ng.theme.shared';
    import { ModuleWithProviders, NgModule } from '@angular/core';
    import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
    import {
      NgxValidateCoreModule,
      VALIDATION_ERROR_TEMPLATE,
      VALIDATION_INVALID_CLASSES,
      VALIDATION_TARGET_SELECTOR,
    } from '@ngx-validate/core';
    import { PROFILE_PICTURE_PROVIDERS } from '@volo/abp.commercial.ng.ui/config';
    import { AccountLayoutComponent } from './components/account-layout/account-layout.component';
    import { AccountLogoComponent } from './components/account-layout/account-logo/account-logo.component';
    import { AuthWrapperComponent } from './components/account-layout/auth-wrapper/auth-wrapper.component';
    import { TenantBoxComponent } from './components/account-layout/tenant-box/tenant-box.component';
    import { ApplicationLayoutComponent } from './components/application-layout/application-layout.component';
    import { CurrentUserImageComponent } from './components/current-user-image/current-user-image.component';
    import { EmptyLayoutComponent } from './components/empty-layout/empty-layout.component';
    import { FooterComponent } from './components/footer/footer.component';
    import { HeaderComponent } from './components/header/header.component';
    import { HttpErrorComponent } from './components/http-error/http-error.component';
    import { LogoComponent } from './components/logo/logo.component';
    import { CurrentUserComponent } from './components/nav-items/current-user.component';
    import { FullScreenComponent } from './components/nav-items/full-screen.component';
    import { LanguagesComponent } from './components/nav-items/languages.component';
    import { NavItemsComponent } from './components/nav-items/nav-items.component';
    import { NavbarMobileComponent } from './components/navbar-mobile/navbar-mobile.component';
    import { NavbarComponent } from './components/navbar/navbar.component';
    import { PageAlertContainerComponent } from './components/page-alert-container/page-alert-container.component';
    import { RoutesComponent } from './components/routes/routes.component';
    import { SettingsComponent } from './components/settings/settings.component';
    import { SidebarComponent } from './components/sidebar/sidebar.component';
    import { ValidationErrorComponent } from './components/validation-error/validation-error.component';
    import { LEPTON_THEME_NAV_ITEM_PROVIDERS } from './providers/nav-item.provider';
    import { LEPTON_THEME_SETTING_TAB_PROVIDERS } from './providers/setting-tab.provider';
    import { LEPTON_THEME_STYLES_PROVIDERS, removeLeptonLoader } from './providers/styles.provider';
    import { LEPTON_THEME_USER_MENU_PROVIDERS } from './providers/user-menu.provider';
    import { CUSTOM_STYLE } from './tokens/custom-style.token';
    import { LEPTON_THEME_FEATURES_PROVIDERS } from './tokens/features.token';
    import { CONTENT_AFTER_ROUTES, CONTENT_BEFORE_ROUTES } from './tokens/routes-content.token';
    import { AngularSvgIconModule } from 'angular-svg-icon';
    import { FeatureBadgeModule } from '@SCM/common/base-forms/components/feature-badge/feature-badge.module';
    import { Options } from './models/theme-lepton';
    
    export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, EmptyLayoutComponent];
    
    const COMPONENTS = [
      SettingsComponent,
      ValidationErrorComponent,
      HttpErrorComponent,
      LogoComponent,
      RoutesComponent,
      NavItemsComponent,
      CurrentUserImageComponent,
      LanguagesComponent,
      CurrentUserComponent,
      FullScreenComponent,
      NavbarComponent,
      NavbarMobileComponent,
      HeaderComponent,
      FooterComponent,
      SidebarComponent,
      PageAlertContainerComponent,
      AuthWrapperComponent,
      TenantBoxComponent,
      AccountLogoComponent,
    ];
    
    @NgModule({
      declarations: [...LAYOUTS, ...COMPONENTS],
      exports: [...LAYOUTS, ...COMPONENTS],
      imports: [
        CoreModule,
        ThemeSharedModule,
        NgbDropdownModule,
        NgxValidateCoreModule,
        AngularSvgIconModule,
        FeatureBadgeModule
      ],
    })
    export class BaseThemeLeptonModule { }
    
    @NgModule({
      exports: [BaseThemeLeptonModule],
      imports: [BaseThemeLeptonModule],
    })
    export class ThemeLeptonModule {
      static forRoot(options = {} as Options): ModuleWithProviders<ThemeLeptonModule> {
        return {
          ngModule: ThemeLeptonModule,
          providers: [
            LEPTON_THEME_NAV_ITEM_PROVIDERS,
            LEPTON_THEME_USER_MENU_PROVIDERS,
            LEPTON_THEME_STYLES_PROVIDERS,
            LEPTON_THEME_SETTING_TAB_PROVIDERS,
            PROFILE_PICTURE_PROVIDERS,
            LEPTON_THEME_FEATURES_PROVIDERS,
            {
              provide: VALIDATION_ERROR_TEMPLATE,
              useValue: ValidationErrorComponent,
            },
            {
              provide: VALIDATION_INVALID_CLASSES,
              useValue: 'input-validation-error',
            },
            {
              provide: VALIDATION_TARGET_SELECTOR,
              useValue: '.form-control',
            },
            {
              provide: CONTENT_AFTER_ROUTES,
              useValue: options.contentAfterRoutes || [],
            },
            {
              provide: CONTENT_BEFORE_ROUTES,
              useValue: options.contentBeforeRoutes || [],
            },
            {
              provide: CUSTOM_STYLE,
              useValue: options.customStyle || false,
            },
            {
              provide: APP_INIT_ERROR_HANDLERS,
              useValue: removeLeptonLoader,
              multi: true,
            },
          ],
        };
      }
    }
    
  • User Avatar
    0
    JanneHarju created

    And features.token.ts looks like this

    import { ConfigStateService, featuresFactory } from '@abp/ng.core';
    import { inject, InjectionToken, provideAppInitializer } from '@angular/core';
    import { ModuleVisibility, setModuleVisibilityFactory } from '@volo/abp.commercial.ng.ui/config';
    import { SettingTabsService } from '@abp/ng.setting-management/config';
    import { Observable } from 'rxjs';
    import { eLeptonThemeSettingTabNames } from '../enums/setting-tab-names';
    
    export const LEPTON_THEME_FEATURES = new InjectionToken<Observable<ModuleVisibility>>(
      'LEPTON_THEME_FEATURES',
      {
        providedIn: 'root',
        factory: () => {
          const configState = inject(ConfigStateService);
          const featureKey = 'LeptonManagement.Enable';
          const mapFn = features => ({
            enable: features[featureKey].toLowerCase() !== 'false',
          });
    
          return featuresFactory(configState, [featureKey], mapFn);
        },
      },
    );
    
    export const SET_LEPTON_THEME_SETTING_TAB_VISIBILITY = new InjectionToken(
      'SET_LEPTON_THEME_SETTING_TAB_VISIBILITY',
      {
        providedIn: 'root',
        factory: () => {
          const settingTabs = inject(SettingTabsService);
          const stream = inject(LEPTON_THEME_FEATURES);
    
          setModuleVisibilityFactory(
            stream,
            settingTabs,
            eLeptonThemeSettingTabNames.LeptonThemeManagement,
          ).subscribe();
        },
      },
    );
    
    export const LEPTON_THEME_FEATURES_PROVIDERS = [
      provideAppInitializer(() => {
        inject(SET_LEPTON_THEME_SETTING_TAB_VISIBILITY);
        return;
      }),
    ];
    
  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Hello,

    Thank you for explaining your problem by giving details. Since you have migrated from 8.3.4 to 9.3.4 , I need to remind you that we have made some set of adjustments on our side. The most important one is the standalone migration.

    You can check details from here

    1. 🔗 Migration guides
    2. 🔗 9.3 Migration
    3. 🔗 Standalone support

    If you have also migrated your application to the new builder system, this could make a difference.

    Thant is to say, the module and the token you have shared seem functional and not problematic. However, that would be the best if you could share

    • how you have provided them
    • the customizations you have done that could affect here

    If you prefer, you could also share a minimal reproducible example via e-mail. Here is my address: sumeyye.kurtulus@volosoft.com

    Thank you for your cooperation.

  • User Avatar
    0
    JanneHarju created

    Do you mean that how I provide LEPTON_THEME_FEATURES_PROVIDERS? Because SET_LEPTON_THEME_SETTING_TAB_VISIBILITY and LEPTON_THEME_FEATURES are only used in this features.token.ts file. ThemeLeptonModule is only one where LEPTON_THEME_FEATURES_PROVIDERS is in provided list.

    Do you believe that problem might be related to those injection tokens what I provided earlier? This was how they were earlier before I removed APP_INITIALIZER usage.

    export const LEPTON_THEME_FEATURES_PROVIDERS = [
      {
        provide: APP_INITIALIZER,
        useFactory: noop,
        deps: [SET_LEPTON_THEME_SETTING_TAB_VISIBILITY],
        multi: true,
      },
    ];
    

    I have used that new angular build system already in 8.3.4 version. I have read all those related migration guides. Our project is so big so for now we are staying with module style and not going to switch to standalone components. I have tried that angular standalone migration tool but it didn't made good work so it would be huge work to migrate rest by hand and figure out what modules/components need to be imported into each component. We have over 320 components and over 184 modules. It would be quite hard to provide any minimal reproducible example because we are no going to share all of our code and I have no idea what parts are related. Maybe theme-lepton module? I do not have list about what customizations we have done to lepton-theme.

    Problem might be related to how layout is selected. Now there is empty layout in use. Are these keys changed at your side?

  • User Avatar
    0
    JanneHarju created

    Here is what I get from application-configuration related to lepton theme So I didn't figure out yet how layout is selected (empty, application, account)

  • User Avatar
    0
    JanneHarju created

    I just tried how this would work and it seems that it fixed issue but I don't think this is correct solution. So I replaced empty layout component with application lyout component.

    export function initLayouts(injector: Injector) {
      const replaceableComponents = injector.get(ReplaceableComponentsService);
      replaceableComponents.add({
        key: eThemeLeptonComponents.ApplicationLayout,
        component: ApplicationLayoutComponent,
      });
      replaceableComponents.add({
        key: eThemeLeptonComponents.AccountLayout,
        component: AccountLayoutComponent,
      });
      replaceableComponents.add({
        key: eThemeLeptonComponents.EmptyLayout,
        component: ApplicationLayoutComponent,
      });
    }
    
  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Hello again,

    Thank you for providing extra details. I am suspecting that the abp-application-layout is not initialized correctly. Do you see any error thrown somewhere like this

    export function injectStyle(injector: Injector) {
      const rendererFactory = injector.get(RendererFactory2);
      const domInsertion = injector.get(DomInsertionService);
      const _document = injector.get(DOCUMENT);
    
      rendererFactory
        .createRenderer(_document.body, null)
        .addClass(_document.body, 'abp-application-layout');
    
      const appStyles: HTMLElement = _document.querySelector('link[rel="stylesheet"][href*="styles"]');
      let content: StyleContentStrategy;
      if (appStyles) {
        const domStrategy = DOM_STRATEGY.BeforeElement(appStyles);
        content = new StyleContentStrategy(styles, domStrategy, undefined, {
          id: LEPTON_STYLE_ELEMENT_ID,
        });
      } else {
        content = CONTENT_STRATEGY.AppendStyleToHead(styles, { id: LEPTON_STYLE_ELEMENT_ID });
      }
    
      domInsertion.insertContent(content);
    }
    
  • User Avatar
    0
    JanneHarju created

    I debugged this part and no exceptions occured. Execution goes inside if statement. What about my latest comment about this change.

    replaceableComponents.add({
        key: eThemeLeptonComponents.EmptyLayout,
        component: ApplicationLayoutComponent,
      });
    

    Where I replace empty component for empty key by ApplicationLayoutComponent. This makes the sidebar to show. But this seems to me pretty forced solution. But this might help you understand where problem might be.

  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    This trick is supposed to replace the empty layout and it does so. However, it is a forced solution as you say. So, if you could share how you provide the lepton theme in your app.module.ts or app.config.ts, I would be able to assist based on this.

  • User Avatar
    0
    JanneHarju created

    Here is app.module.ts

    @NgModule({
      declarations: [AppComponent, HelpComponent],
      bootstrap: [AppComponent],
      imports: [
        AngularSvgIconModule.forRoot(),
        BrowserModule,
        AppRoutingModule,
        CoreModule,
        ThemeSharedModule,
        AccountAdminConfigModule,
        IdentityConfigModule,
        SaasConfigModule,
        AuditLoggingConfigModule,
        SettingManagementConfigModule,
        MenuSearchModule.forRoot({ limit: 3 }),
        ThemeLeptonModule.forRoot({
          customStyle: true,
        }),
        CommercialUiConfigModule,
        MasterDataManagementConfigModule.forRoot(),
        IntegrationConfigModule.forRoot(),
        ControlsConfigModule.forRoot(),
        SettingsConfigModule.forRoot(),
        AccountConfigModule.forRoot(),
        KendoFormsModule,
        ...dev,
        ServiceWorkerModule.register('ngsw-worker.js', {
          enabled: !isDevMode(),
          // Register the ServiceWorker as soon as the application is stable
          // or after 30 seconds (whichever comes first).
          registrationStrategy: 'registerWhenStable:30000',
        }),
      ],
      providers: [
        APP_ROUTE_PROVIDER,
        USER_MENU_ADDED_ITEMS,
        KendoIntlService,
        provideAbpCore(
          withOptions({
            environment,
            registerLocaleFn: registerLocale(),
          }),
        ),
        provideHttpClient(
          withInterceptorsFromDi(),
          withXsrfConfiguration({
            cookieName: 'XSRF-TOKEN',
            headerName: 'RequestVerificationToken',
          }),
        ),
        provideAbpThemeShared(
          withHttpErrorConfig({
            errorScreen: {
              component: HttpErrorComponent,
              forWhichErrors: [401, 403, 404, 500],
              hideCloseIcon: true,
            },
          }),
        ),
        provideAnimations(),
        provideAbpOAuth(),
        provideIdentityConfig(),
        provideSettingManagementConfig(),
        provideAccountAdminConfig(),
        provideAccountPublicConfig(),
        provideCommercialUiConfig(),
        provideSaasConfig(),
        provideAuditLoggingConfig(),
        provideOpeniddictproConfig(),
        provideTextTemplateManagementConfig(),
        provideLanguageManagementConfig(),
        {
          provide: IntlService,
          useExisting: KendoIntlService,
        },
        {
          provide: LOCALE_ID,
          deps: [LocalizationService],
          useFactory: (localizationService: LocalizationService) => localizationService.currentLang,
        },
        { provide: MessageService, useExisting: KendoMessagesService },
        { provide: PAGE_RENDER_STRATEGY, useClass: ScmPageRenderStrategy },
        {
          provide: VALIDATION_BLUEPRINTS,
          useValue: {
            ...DEFAULT_VALIDATION_BLUEPRINTS,
            pattern: 'AbpValidation::InvalidPatternPleaseReviewYourInput',
            min: 'AbpValidation::ThisFieldMustBeGreaterThanOrEqualTo{0}[{{ min }}]',
            max: 'AbpValidation::ThisFieldMustBeLessThanOrEqualTo{0}[{{ max }}]',
            calculationPeriodStartDate: 'AbpValidation::StartDateCanNotBeInFuture',
            duplicatePriority: 'AbpValidation::PriorityIsAlreadyInUse',
            duplicateName: 'AbpValidation::NameIsAlreadyInUse',
            dateIsInPast: 'AbpValidation::DateCanNotBeInPast',
            maxDecimals: 'AbpValidation::ThisFieldMustContainLessThanOrEqualDecimals{0}[{{ maxDecimals }}]',
            greaterThanField: 'AbpValidation::ThisFieldMustBeGreaterThan{0}[{{ field }}]',
            greaterThanZero: 'AbpValidation::ThisFieldMustBeGreaterThan{0}[0]',
            lessThanField: 'AbpValidation::ThisFieldMustBeLessThan{0}[{{ field }}]',
            invalidValues: 'AbpValidation::InvalidValues{0}ValidValues{1}[{{ invalidField }},{{ validField }}]',
            missingRequiredValues: 'AbpValidation::MissingRequiredValues{0}[{{ field }}]',
            dateIsNotInPastOrToday: 'AbpValidation::DateCanNotBeInPastOrToday',
          },
        },
        { provide: CUSTOM_ERROR_HANDLERS, useExisting: SCMCustomErrorHandlerService, multi: true },
        { provide: ErrorHandler, useClass: ApplicationInsightsErrorHandler },
        {
          provide: NAVIGATE_TO_MANAGE_PROFILE,
          deps: [Router],
          useFactory: (router: Router) => () => router.navigate(['/account/manage']),
        },
        TawkService,
        BeamerService,
      ],
    })
    export class AppModule {}
    
  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Thank you for sharing details about your problem. It looks like the problem occurs for the customStyle input here:

      ThemeLeptonModule.forRoot({
        customStyle: true,
      }),
    

    The issue might be related to a style mismatch. Could you also provide how you managed this custom style and whether this style is loaded properly?

  • User Avatar
    0
    JanneHarju created

    Hello this is whole styles provider ts.

    import {
      ConfigStateService,
      CONTENT_STRATEGY,
      CurrentCultureDto,
      DOM_STRATEGY,
      DomInsertionService,
      ReplaceableComponentsService,
      StyleContentStrategy,
    } from '@abp/ng.core';
    import { inject, Injector, provideAppInitializer, RendererFactory2 } from '@angular/core';
    import { combineLatest, Observable, of } from 'rxjs';
    import { distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators';
    import { AccountLayoutComponent } from '../components/account-layout/account-layout.component';
    import { ApplicationLayoutComponent } from '../components/application-layout/application-layout.component';
    import { LEPTON_STYLE_ELEMENT_ID } from '../constants/lepton-constants';
    import styles from '../constants/styles';
    import { eThemeLeptonComponents } from '../enums/components';
    import { LayoutStateService } from '../services/layout-state.service';
    import { CUSTOM_STYLE } from '../tokens/custom-style.token';
    import { EmptyLayoutComponent } from '../components';
    
    export const LEPTON_THEME_STYLES_PROVIDERS = [
      provideAppInitializer(() => {
        let injector = inject(Injector);
        injectStyle(injector);
        initLeptonStyleHandler(injector);
        initLayouts(injector);
      }),
    ];
    
    export function injectStyle(injector: Injector) {
      const rendererFactory = injector.get(RendererFactory2);
      const domInsertion = injector.get(DomInsertionService);
    
      rendererFactory
        .createRenderer(document.body, null)
        .addClass(document.body, 'abp-application-layout');
        const appStyles: HTMLElement = document.querySelector('link[rel="stylesheet"][href*="styles"]');
      let content: StyleContentStrategy;
      if (appStyles) {
        const domStrategy = DOM_STRATEGY.BeforeElement(appStyles);
        content = new StyleContentStrategy(styles, domStrategy, undefined, {
          id: LEPTON_STYLE_ELEMENT_ID,
        });
      } else {
        content = CONTENT_STRATEGY.AppendStyleToHead(styles, { id: LEPTON_STYLE_ELEMENT_ID });
      }
    
      domInsertion.insertContent(content);
    }
    
    export const getLeptonStyle = (type: number, suffix: string): Observable<string> => {
      return of(`lepton${type}${suffix}`);
    };
    
    export function initLeptonStyleHandler(injector: Injector) {
      const layoutState = injector.get(LayoutStateService);
      const configStateService = injector.get(ConfigStateService);
      const customStyle = injector.get(CUSTOM_STYLE);
    
      if (customStyle) {
        removeLeptonLoader();
        return;
      }
    
      const removeLeptonStyles = (element: HTMLLinkElement, injector: Injector) => {
        const domInsertionService = injector.get(DomInsertionService);
        if (element) { domInsertionService.removeContent(element); };
      };
    
      const style$ = configStateService
        .getSetting$('Volo.Abp.LeptonTheme.Style')
        .pipe(map((style: string) => Number((style || 'Style1').replace('Style', ''))));
      const suffix$ = configStateService
        .getDeep$('localization.currentCulture')
        .pipe(map((currentLang: CurrentCultureDto) => (currentLang?.isRightToLeft ? '.rtl' : '')));
    
      combineLatest([style$, suffix$])
        .pipe(
          distinctUntilChanged((prev, curr) => prev[0] === curr[0] && prev[1] === curr[1]),
          tap(removeLeptonLoader),
          switchMap(([style, suffix]) =>
            loadLeptonStyle(style, suffix).pipe(map(element => ({ element, style }))),
          ),
        )
        .subscribe(result => {
          const styleElement = layoutState.get('styleElement') as HTMLLinkElement;
          removeLeptonStyles(styleElement, injector);
          layoutState.patch({ style: result.style, styleElement: result.element });
        });
    }
    
    export function loadLeptonStyle(type: number, suffix: string): Observable<HTMLLinkElement> {
      const leptonStyles: HTMLElement = document.querySelector(
        `style[id="${LEPTON_STYLE_ELEMENT_ID}"]`,
      );
      const domStrategy = leptonStyles
        ? DOM_STRATEGY.BeforeElement(leptonStyles)
        : DOM_STRATEGY.AppendToHead();
    
      return getLeptonStyle(type, suffix).pipe(
        map(bundleName => {
          const linkElem = document.createElement('link');
          linkElem.setAttribute('rel', 'stylesheet');
          linkElem.setAttribute('href', `${bundleName}.css`);
          linkElem.setAttribute('id', `lepton${type}${suffix}`);
          domStrategy.insertElement(linkElem);
          return linkElem;
        }),
      );
    }
    
    export function removeLeptonLoader() {
      const loader: HTMLElement = document.querySelector('#lp-page-loader');
      if (!loader) {return;}
      loader.style.background = 'var(--background)';
      loader.parentNode?.removeChild(loader);
    }
    
    export function initLayouts(injector: Injector) {
      const replaceableComponents = injector.get(ReplaceableComponentsService);
      replaceableComponents.add({
        key: eThemeLeptonComponents.ApplicationLayout,
        component: ApplicationLayoutComponent,
      });
      replaceableComponents.add({
        key: eThemeLeptonComponents.AccountLayout,
        component: AccountLayoutComponent,
      });
      replaceableComponents.add({
        key: eThemeLeptonComponents.EmptyLayout,
        component: EmptyLayoutComponent,
      });
    }
    
    
  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Thank you again for getting back and giving more details. The problem is probably related to the custom style parameter as I mentioned before. Do you provide the custom style css files in your styles.scss file as it is explained here?

    You need to import your style like this @import 'your-custom-style.css'; .

  • User Avatar
    0
    JanneHarju created

    Ok. Now I understand your question better. Here is example of how I'm using custom styles in styles.scss

    @use 'kendo-theme.scss';
    @use 'projects/theme-lepton/dist/global/styles/lepton7.min.css';
    

    I started to use @use because @import was deprecated and my angular application didn't work if I wouldn't change to use @use. I was forced to make some changes where some scss variables were and how they were used, but after awile I think I succeeded.

    Then I have some other custom styles in angular.json

    "styles": [
                  {
                    "input": "node_modules/@swimlane/ngx-datatable/index.css",
                    "inject": true,
                    "bundleName": "ngx-datatable-index"
                  },
                  {
                    "input": "node_modules/@swimlane/ngx-datatable/assets/icons.css",
                    "inject": true,
                    "bundleName": "ngx-datatable-icons"
                  },
                  {
                    "input": "node_modules/@swimlane/ngx-datatable/themes/material.css",
                    "inject": true,
                    "bundleName": "ngx-datatable-material"
                  },
                  {
                    "input": "node_modules/@fortawesome/fontawesome-pro/css/all.min.css",
                    "inject": true,
                    "bundleName": "fontawesome-all.min"
                  },
                  {
                    "input": "node_modules/@fortawesome/fontawesome-pro/css/v4-shims.min.css",
                    "inject": true,
                    "bundleName": "fontawesome-v4-shims.min"
                  },
                  {
                    "input": "node_modules/flag-icons/css/flag-icons.min.css",
                    "inject": true,
                    "bundleName": "flag-icons.min"
                  },
                  {
                    "input": "node_modules/ng-zorro-antd/tree/style/index.min.css",
                    "inject": false,
                    "bundleName": "ng-zorro-antd-tree"
                  },
                  "src/styles.scss"
                ],
    

    But how styles can affect how dynamic layout component is selecting which layout to use?

    I noticed that in my code there is still some APP_INITIALIZER in use. I will try to refactor them to use new provideAppInitializer instead. Many of those places where APP_INITIALIZER is still in use is those route.provider.ts files where layout is set to each route.

  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Thank you again. This usage should also be working fine.

    This problem shold not be related to the usage of APP_INITIALIZER since it is just depracated. That would be the best if you could share a minimal, reproducible example or a screenshot of how your application is broken (via e-mail if you do not want it to be seen here)

  • User Avatar
    0
    JanneHarju created

    I tried to replace all those APP_INITIALIZER and for some reason it seems that if fixed problem. After I changed every modules route.provider.ts to use provideAppInitializer I got error that says something like this "providers required eather Provider or Type and you provided [...,...,...,...]" . So i tried to spread those SOME_MODULE_ROUTE_PROVIDERS with ... and then I got almost same error. Then I removed spread ... and just removed array from all ROUTE_PROVIDERS that one route.provider.ts had. So result was like this in one of ROUTE_PROVIDERS:

    import { eLayoutType, RoutesService } from '@abp/ng.core';
    import { inject, provideAppInitializer } from '@angular/core';
    import { eIntegrationRouteNames } from '../enums/route-names';
    
    export const INTEGRATION_ROUTE_PROVIDERS = provideAppInitializer(() => {
      configureRoutes(inject(RoutesService));
    });
    
    export function configureRoutes(routes: RoutesService) {
      routes.add([
        {
          path: '/integration',
          name: eIntegrationRouteNames.Integration,
          iconClass: 'fas fa-book',
          parentName: 'AbpUiNavigation::Menu:Administration',
          requiredPolicy: 'Integration.Menu',
          layout: eLayoutType.application,
          order: 3,
        },
      ]);
    }
    
    

    So I only removed [ ]. Related ConfigModule stayed unmodified. After that all started to work for some reason. Do you have any clue what might be reason that this fixed my problem?

    I still have styles broken and then I have some backend problem after update but they are another story.

  • User Avatar
    0
    JanneHarju created

    Original problem was this sidebar was not showing

    And reason was that here was not application layout component instead empty layout component which is not containing sidebar.

    So I was figuring out why there was not application layout component in use like it was before update.

  • User Avatar
    0
    sumeyye.kurtulus created
    Support Team Angular Expert

    Thank you again for checking and responding. Since then the styles are used in a correct way by the customStyle parameter, the problem should be resolved.

    Speaking of APP_INITIALIZER, here is how we have managed these kind of migrations:

    // Before
    export const LEPTON_THEME_NAV_ITEM_PROVIDERS = [
      {
        provide: APP_INITIALIZER,
        useFactory: configureNavItems,
        deps: [NavItemsService],
        multi: true,
      },
    ];
    
    export function configureNavItems(navItems: NavItemsService) {
    	return () => {
        navItems.addItems([
          // ...
        ]);
      };
    } 
    
    // After
    export const LEPTON_THEME_NAV_ITEM_PROVIDERS = [
      provideAppInitializer(() => {
        configureNavItems();
      }),
    ];
    
    export function configureNavItems() {
      const navItems = inject(NavItemsService);
      // No need to return anything, since it is a modular function
      navItems.addItems([
        // ...
      ]);
    }
    

    You can also reach related 🔗 Angular documentation

    It should be something misconfigured that affected this particular part as I suppose.

    export const LEPTON_THEME_STYLES_PROVIDERS = [
      provideAppInitializer(() => {
        configureStyles();
      }),
    ];
    
    export function configureStyles() {
      const injector = inject(Injector);
      // ...
      initLayouts(injector);
    }
    
    export function initLayouts(injector: Injector) {
      const replaceableComponents = injector.get(ReplaceableComponentsService);
      // we do not return this as we use provideAppInitializer instead of APP_INITIALIZER
      replaceableComponents.add({
        key: eThemeLeptonComponents.ApplicationLayout,
        component: ApplicationLayoutComponent,
      });
      replaceableComponents.add({
        key: eThemeLeptonComponents.AccountLayout,
        component: AccountLayoutComponent,
      });
      replaceableComponents.add({
        key: eThemeLeptonComponents.EmptyLayout,
        component: EmptyLayoutComponent,
      });
    }
    

    You can let us know if you need further assistance on this. Thank you for your cooperation.

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.1.0-preview. Updated on October 30, 2025, 06:33