Upgrading to Angular version 18
Sterling Store Engagement is upgraded to Angular version 18. Make sure that you migrate your extensions to Angular version 18.
Before you begin
Note: If you cannot migrate to Angular version 18, but want to modify your extensions in Angular
version 15, you can continue to build your customizations with the 24.3.9.2-10.0.2409.2 developer
toolkit. To get the most recent features, enhancements, and fixes, you must upgrade to Angular
version 18.
- You must have Angular version 15 workspace from the 24.3.9.2-10.0.2409.2 or any Angular version 15 developer toolkit.
- Make sure that you are on
node.jsversion 18.20.0.
About this task
Note: Make sure to run all commands from <WORKSPACE>/store-frontend-src
folder.
Procedure
-
Update node-sass to version 8.0.0 in both
packages/libs/styles/package.json and
extensions/libs/styles/package.json files, then run one of the following
commands:
yarn bootstrap - Upgrade Angular core and CLI to version 16 by running the following command:
ng update @angular/core@16 @angular/cli@16 --allow-dirty --force - Upgrade Angular core and CLI to version 17 by running the following command:
ng update @angular/core@17 @angular/cli@17 --allow-dirty --force - Upgrade Angular core and CLI to version 18 by running the following command:
ng update @angular/core@18 @angular/cli@18 --allow-dirty --forceNote: When you run this command you encounter an optional migration to use application builderuse-application-builder, press enter to proceed - Search and replace the existing code with the new code in all the
app.component.ts constructor methods within the extension directory. If there
is no occurrence of this code snippet, proceed to step 6.The following code illustrates the existing code:
this.router.events.subscribe((event: RouterEvent) => { this.routingStateService.navigationInterceptor(event); });The following code illustrates the new code:this.router.events.pipe( filter((event: Event | RouterEvent): event is RouterEvent => event instanceof RouterEvent) ).subscribe((event: RouterEvent) => { this.routingStateService.navigationInterceptor(event); });Then, import Event from @angular/router and filter from rxjs/operators.import { filter, take } from 'rxjs/operators'; import { Router, RouterEvent, Event } from '@angular/router'; - If you have extended
packages/libs/common-components/src/lib/components/donut-chart/donut-chart.component.ts,
then search and replace the existing code with the new code in the
donut-chart.component.ts file.The following code illustrates the existing code:
const pie = d3.pie().value((d) => d.count).sort(null);The following code illustrates the new code:const pie = d3.pie().value((d) => d?.['count']).sort(null); - In the angular.json file, search for browserTarget and replace it with buildTarget.
- In the most recent developer toolkit 25.1.3.0-10.0.2503.0, browse to the extensions/libs/styles directory, and copy the package.json and webpack.config.js files to your extension folder.
- Set up a new workspace from the most recent developer toolkit 25.1.3.0-10.0.2503.0 by
completing the steps that follow.
- Copy the angular.json file from the previous workspace to the new workspace.
- Copy the migrated extensions from the previous workspace to the new workspace.
- Rerun the following commands to test extensions:
yarn bootstrapln -s <store-temp>/store-cli/schematics/node_modules <store-temp>/store-cli/node_modulesMake sure that you use absolute path while you run the command before this.
- Merge incoming changes from application-provided code with extensions to make sure that you are on the most recent version of the code and to avoid any compilation errors.
- Consider the next set of steps while you merge your changes.
- With the most recent version of
RxJS,TypeScriptdisplays an error message, if the argument for the next method is not provided. If you do not want to pass an argument, declare the subject with a void type. Alternatively, if the subject is emitting values from another source and integrated by observers, but you do not want to send any value from one source, pass null as the argument to the next method. The following code illustrates the existing code:public addToCartSubject = new Subject<any>(); this.refreshParentComponent.next();The following code illustrates the new code:
public addToCartSubject = new Subject<void>(); this.refreshParentComponent.next(null); - ngbAccordion is changed from component to
directive in version 16.0.0 of ng-bootstrap. Follow the example after this to
make sure all occurrence of ngbAccordion in extensions is upgraded to
directive.
- Change the accordion code in the component.html file as illustrated in the
following example. The following code illustrates the old
code:
<ngb-accordion #acc="ngbAccordion" activeIds="{{activeIds}}" [attr.tid]="componentId+'filterStatus'"> <ngb-panel id="ngb-panel-assignto"> <ng-template ngbPanelTitle> <span [ngClass]="{' app-icon-open-chevron_down_14': isOpen(acc, 'ngb-panel-assignto'), 'app-icon-collapsed-chevron_right_14': !isOpen(acc, 'ngb-panel-assignto') }" class="app-glyphicons"></span> <span translate> filterOptions.LABEL_FilterGroupDisplayValueAssignTo</span> </ng-template> <ng-template ngbPanelContent> <isf-combo-box [attr.tid]="componentId+'filterAssignTo'" [searchText]="selectedUserName" [items]="userList" [columnName]="'name'" [selectedValues]="[selectedUserName]" [placeholder]="'filterOptions.LABEL_SelectAssociate'" [isItemSelected]="selectedUserName" (applySelection)="onSelection($event)" [resetValue]="resetComboBox"></isf-combo-box> </ng-template> </ngb-panel> </ngb-accordion>The following code illustrates the new code:
<div ngbAccordion #acc="ngbAccordion" [attr.tid]="componentId+'filterStatus'"> <div ngbAccordionItem="ngb-panel-assignto" id="ngb-panel-assignto" [collapsed]="!activeIds.includes('ngb-panel-assignto')"> <div ngbAccordionHeader> <button ngbAccordionButton> <span [ngClass]="{' app-icon-open-chevron_down_14': isOpen(acc, 'ngb-panel-assignto'), 'app-icon-collapsed-chevron_right_14': !isOpen(acc, 'ngb-panel-assignto') }" class="app-glyphicons"></span> <span translate> filterOptions.LABEL_FilterGroupDisplayValueAssignTo</span> </button> </div> <div ngbAccordionCollapse> <div ngbAccordionBody> <ng-template> <isf-combo-box [attr.tid]="componentId+'filterAssignTo'" [searchText]="selectedUserName" [items]="userList" [columnName]="'name'" [selectedValues]="[selectedUserName]" [placeholder]="'filterOptions.LABEL_SelectAssociate'" [isItemSelected]="selectedUserName" (applySelection)="onSelection($event)" [resetValue]="resetComboBox"></isf-combo-box> </ng-template> </div> </div> </div> </div> - In the component.ts file, remove the import of
NgbAccordion and add NgbAccordionDirective from
@ng-bootstrap/ng-bootstrap.
import { NgbAccordionDirective } from '@ng-bootstrap/ng-bootstrap'; - In the component.ts file, change the isOpen function
as shown in the code sample that
follows.
public isOpen(acc: NgbAccordion, panelId: string) { return (acc.activeIds.includes(panelId)); }Change as follows:public isOpen(acc: NgbAccordionDirective, panelId: string) { return acc.isExpanded(panelId) } - The PanelChange event is removed in the most recent ngbootsrap. Proceed
with the changes that are mentioned by the following:
- Replace panelChange with show in the
component.htmlfile as shown in the following example:(panelChange)="setSelectedLocation($event)"Replace as follows:(show)="setSelectedLocation($event)" - In component.ts file, change the panelChange event
handler function as shown in the following
example:
public setSelectedLocation(event: NgbPanelChangeEvent) { if (UIUtil.isNotVoid(event.nextState)) { if (UIUtil.isNotVoid(event.panelId)) { this.selectedLocationId = event.panelId; this._setDefaultAttributeSet(this.selectedLocationId); } } else { this.selectedLocationId = ''; } }Change topublic setSelectedLocation(panelId: string) { if (UIUtil.isNotVoid(panelId)) { this.selectedLocationId = panelId; this._setDefaultAttributeSet(this.selectedLocationId); } else { this.selectedLocationId = ''; } }
- Replace panelChange with show in the
- Change the accordion code in the component.html file as illustrated in the
following example. The following code illustrates the old
code:
- If you use ngbDropdown in the bootstrap's navbar, set
display attribute to dynamic as
shown.
<div ngbDropdown display="dynamic"></div>
- With the most recent version of
- Start the application by running the following command:
yarn start-appNote: When you run theyarn start-appcommand and encounter the following error, delete the .angular folder from the workspace and rerun the command.Module not found: Error: node_modules/@angular-devkit/build-angular/node_modules/@babel/runtime/helpers/esm/asyncToGenerator.js'Note: If you use dev or qa cloud instance as a remote server for development purpose, you need to make the changes mentioned in Configuring local development server.