---
title: Extend the website front end
slug: configured-commerce/docs/best-practices-for-extending-the-website-front-end-in-classic
docTags: 
createdAt: 2026-08-13T10:46:28.000Z
---

:::hint{type="warning"}
**Important**

Classic CMS reached end-of-life in January 2025 and is no longer receiving feature updates or bug fixes. You should \[migrate to Spire CMS]\(../../End user docs/spire-cms/get-started-with-spire-cms/migrate-from-classic-cms-to-spire-cms.mdx).
:::

The TypeScript has been built so all of the Angular services and controllers follow a pattern for event handlers and promises where they call `onEvent`, `promiseCompleted` and `promiseFailed` methods, which can be overridden. In the controllers, the completed method is passed the `response.data` and the failed method is passed the `error.data` which translates to the completed and failed methods are given the actual data returned from the HTTP call instead of the whole response object (which you do have access to in the services).

Code Sample: *some.ts*

```javascript
protected initEvents(): void {
    this.$scope.$on("cartLoaded", (event: ng.IAngularEvent, cart: CartModel) => this.onCartLoaded(event, cart));
    this.settingsService.getSettings().then(
        (settings: core.SettingsCollection) => { this.getSettingsCompleted(settings); },
        (error: any) => { this.getSettingsFailed(error); });
}
protected getSettingsCompleted(settingsCollection: core.SettingsCollection): void {
    this.settings = settingsCollection.cartSettings;
    this.showInventoryAvailability = settingsCollection.productSettings.showInventoryAvailability;
    this.cartService.expand = "cartlines,costcodes";
    if (this.settings.showTaxAndShipping) {
        this.cartService.expand += ",shipping,tax";
    }
    this.cartService.getCart();
}
protected getSettingsFailed(error: any): void {
}
protected onCartLoaded(event: ng.IAngularEvent, cart: CartModel): void {
    this.displayCart(cart);
}
```

For example:

Code Sample: *insite.cart.controller.ts*

```javascript
protected initEvents(): void {
    this.$scope.$on("cartLoaded", (event: ng.IAngularEvent, cart: CartModel) => this.onCartLoaded(event, cart));
    this.settingsService.getSettings().then(
        (settings: core.SettingsCollection) => { this.getSettingsCompleted(settings); },
        (error: any) => { this.getSettingsFailed(error); });
}
protected getSettingsCompleted(settingsCollection: core.SettingsCollection): void {
    this.settings = settingsCollection.cartSettings;
    this.showInventoryAvailability = settingsCollection.productSettings.showInventoryAvailability;
    this.cartService.expand = "cartlines,costcodes";
    if (this.settings.showTaxAndShipping) {
        this.cartService.expand += ",shipping,tax";
    }
    this.cartService.getCart();
}
protected getSettingsFailed(error: any): void {
}
protected onCartLoaded(event: ng.IAngularEvent, cart: CartModel): void {
    this.displayCart(cart);
}
```

This gives you specific override points so you don't have to copy and paste entire methods when you want to change what happens when a call comes back from the server or an event like the cart loaded event happens. Best practice, you should override that method, call super to execute the standard functionality, and put your customization before and after the call to super. For example your derived controller class:

Code Sample: Derived Controller Class

```csharp
module insite.cart {
    "use strict";
    export class MyCartController extends CartController {
        protected getSettingsCompleted(settingsCollection: core.SettingsCollection): void {
            // Put customizations that should happen before standard code here
            super.getSettingsCompleted(settingsCollection);
            // Put customizations that should happen after standard code here
        }
    }
    // You must also change the registration in angular to use your version of the CartController
    angular
        .module("insite")
        .controller("CartController", MyCartController);
}
```

In the services, the completed and failed methods are passed the HTTP response object. For example:

Code Sample: *insite.cart.service.ts*

```javascript
getCarts(filter?: IQueryStringFilter, pagination?: PaginationModel): ng.IPromise<CartCollectionModel> {
    return this.httpWrapperService.executeHttpRequest(
        this,
        this.$http({ method: "GET", url: this.serviceUri, params: this.getCartsParams(filter, pagination) }),
        this.getCartsCompleted,
        this.getCartsFailed
    );
}
protected getCartsParams(filter?: IQueryStringFilter, pagination?: PaginationModel): any {
    const params: any = filter ? JSON.parse(JSON.stringify(filter)) : {};
    if (pagination) {
        params.page = pagination.page;
        params.pageSize = pagination.pageSize;
    }
    return params;
}
protected getCartsCompleted(response: ng.IHttpPromiseCallbackArg<CartCollectionModel>): void {
}
protected getCartsFailed(error: ng.IHttpPromiseCallbackArg<any>): void {
}
```

In the Services we have also supplied an overridable method to control what parameters are passed to the HTTP call, in this case, the `getCartsParams` method. We are not doing anything in the `getCartsCompleted` or `getCartsFailed` methods, they are there as extension points and any errors are handled by the standard error interceptor.
