Quick Start

Create Dependent Model

Steps

Model Specification

Create a new file at src/models/dependent/types/index.d.ts

  1. Create the model Options

// src/models/dependent/types/index.d.ts

declare interface IDependentModelOptions {
  color: string;
}
  1. Create the model specification

// src/models/dependent/types/index.d.ts

declare interface IDependentModel
  extends IDependentModelOptions,
    IKosDataModel {
  id: string;
}

Create the Model Factory

Create a new file at src/models/dependent/dependent-model-factory.ts

import { modelFactory } from "@coca-cola/kos-ui-core";
export const DEPENDENT_MODEL_TYPE = "dep";
export const DependentModelFactory = modelFactory<
  IDependentModel,
  IDependentModelOptions
>(DEPENDENT_MODEL_TYPE);

Create the Model Data Service

// src/models/dependent/services/dependent-model-services.ts

import { ServiceFactory, resolveServiceUrl } from "@coca-cola/kos-ui-core";

const { URL } = resolveServiceUrl("DEPENDENT_MODEL_SERVICE");
const { getOne } = ServiceFactory.build({
  destinationAddress: "",
  basePath: `${URL}/dependent`,
});

interface DependentModelResponse {
  color: string;
}
/**
 * @category Service
 * Retrieves the list of Directorys.
 */
export const getDependentData = async () => {
  const response = await getOne<DependentModelResponse>({});
  return response;
};

Create the Model Implementation

Create a new file at src/models/dependent/dependent-model.ts

// src/models/dependent/dependent-model.ts

import {
  kosModel,
  kosTopicHandler,
  KOS_MODEL_ID,
} from "@coca-cola/kos-ui-core";
import type { ApiCallback } from "@coca-cola/kos-ui-core";
import { DependentModelFactory } from "./dependenty-model-factory";
import { getDependentData } from "./services/dependent-model-services";

import log from "loglevel";
import { kosAction } from "@coca-cola/kos-ui-components";

@kosModel<IDependentModel, IDependentModelOptions>(DependentModelFactory.type)
export class DependentModel implements IDependentModel {
  id: string;
  color: string;
  constructor(modelId: string, options: IDependentModel) {
    // assign the id from the passed in model id
    this.id = modelId;
    this.color = options.color;
  }

  async init(): Promise<void> {
    log.info("initialized dependent model");
  }

  /**
   * The load lifecycle method provides an opportunity to hydrate the model with data fetched
   * from the backend.
   *
   */
  async load(): Promise<void> {
    log.info("loading dependent model");
    try {
      const response = await getDependentData();
      log.info(`received response ${response}`);
      kosAction(() => {
        const newColor = response?.data.color;
        if (newColor) {
          this.color = newColor;
        }
      });

      // alternately could call updateName rather than using the kosAction closure.
    } catch (e) {
      log.error(e);
      throw e;
    }
  }

  @kosTopicHandler({
    topic: `/dependent/update`,
    websocket: true,
  })
  handleUpdate(data: ApiCallback) {
    log.info("update received");
    const body: { color: string } = JSON.parse(data.body);
    log.warn(`updating color to ${body.color}`);
    this.color = body.color;
  }
}

Create a Model Creator Function

// src/models/dependent/dependent-model-creator.ts

import type { IKosDataModelCreator } from "@coca-cola/kos-ui-core";
import { DependentModel } from "./dependent-model";

export const dependentModelCreator: IKosDataModelCreator<IDependentModel> = ({
  modelTypeId,
  id,
}) => {
  const options = { id: id || modelTypeId, color: "lightblue" };
  return new DependentModel(id || modelTypeId, options);
};

Register the new model

  1. Add the new model to the registry for the application at src/App.tsx.

// src/App.tsx

import { DemoFactory } from "./models/demo/demo-factory";
import { DemoModel } from "./models/demo/demo-model";
import { DependentModel } from "./models/dependent/dependent-model";
import { dependentModelCreator } from "./models/dependent/dependent-model-creator";

export const Registry: IKosRegistry = {
  models: {
    [DemoFactory.type]: {
      class: DemoModel,
    },
    [DependentModelFactory.type]: {
      class: DependentModel,
      create: dependentModelCreator,
      singleton: true,
    },
  },
  preloadModels: [DependentModelFactory.type],
};

Add the dependency to the demo model

// /src/models/demo/demo-model.ts

import {
  kosModel,
  kosTopicHandler,
  kosDependency,
  KOS_MODEL_ID,
} from "@coca-cola/kos-ui-core";
import type { ApiCallback } from "@coca-cola/kos-ui-core";
import { DemoFactory } from "./demo-factory";
import { getDemo } from "./services/demo-services";

import log from "loglevel";
import { kosAction } from "@coca-cola/kos-ui-components";
import { DependentModelFactory } from "../dependent/dependenty-model-factory";

@kosModel<IDemoModel, IDemoModelOptions>(DemoFactory.type)
export class DemoModel implements IDemoModel {
  id: string;
  name: string;
  lastUpdate: number;

  @kosDependency({ modelType: DependentModelFactory.type })
  depModel!: IDependentModel;
  constructor(modelId: string, options: IDemoModelOptions) {
    // assign the id from the passed in model id
    this.id = modelId;
    this.name = options.name;
    this.lastUpdate = 0;
  }

  get backgroundColor() {
    return this.depModel?.color || "red";
  }
  get computedName() {
    return `${this.name} - ${this.lastUpdate}`;
  }
  async init(): Promise<void> {
    console.log("initialized model");
  }

  /**
   * The load lifecycle method provides an opportunity to hydrate the model with data fetched
   * from the backend.
   *
   */
  async load(): Promise<void> {
    try {
      log.info("loading demo model");
      const response = await getDemo(this.id);
      log.debug(`received response ${response}`);
      kosAction(() => {
        const newName = response?.data.name;
        if (newName) {
          this.name = newName;
        }
      });
    } catch (e) {
      log.error(e);
      throw e;
    }
  }

  @kosTopicHandler({
    topic: `/demo/update/${KOS_MODEL_ID}`,
    websocket: true,
  })
  handleUpdate(data: ApiCallback) {
    log.info("update received");
    const body: { update: number } = JSON.parse(data.body);
    this.lastUpdate = body.update;
  }
}

Update Demo Component

Modify the Demo component to allow the created model have it’s id based on passed in props.

This is a bit nonsensical as the model ID would typcially already be known and the instance would likely not be created in the component. However, this is helpful for explaining the concept.
// src/Demo.tsx

import { kosComponent, useKosModel } from "@coca-cola/kos-ui-components";
import { DemoFactory } from "./models/demo/demo-factory";
interface Props {
  indx?: number;
}
export const DemoComponent = ({ indx = 1 }: Props) => {
  const { model, ready } = useKosModel<IDemoModel, IDemoModelOptions>({
    modelId: `demo${indx}`,
    factory: DemoFactory,
    options: { name: "demo-name" },
  });

  const isReady = ready && model;

  return isReady ? (
    <div style={{ backgroundColor: model.backgroundColor }}>
      Hello: {model.computedName}
    </div>
  ) : (
    <div>LOADING</div>
  );
};

export const Demo = kosComponent(DemoComponent);

Update the Application To Support multiple Components

// src/App.tsx

function App() {
  return (
    <ErrorBoundaryWithFallback>
      <Suspense fallback={<div>LOADING</div>}>
        <KosCoreContextProvider>
          <Demo indx={1}></Demo>
          <Demo indx={2}></Demo>
        </KosCoreContextProvider>
      </Suspense>
    </ErrorBoundaryWithFallback>
  );
}

export default App;
Previous
Next
On this page
Java Development
Seamlessly transition from Legacy+ systems to Freestyle microdosing and advanced distributed dispense systems.
UI Development
Using KOS SDKs, integrating Consumer and Non-consumer facing UIs becomes seamless, giving you less hassle and more time to create.
Video Library
Meet some of our development team, as they lead you through the tools, features, and tips and tricks of various KOS tools.
Resources
Familiarize yourself with KOS terminology, our reference materials, and explore additional resources that complement your KOS journey.
Copyright © 2024 TCCC. All rights reserved.