i2 Notebook SDK
Search results for

    Show/hide table of contents

    Accessing data from a plug-in

    The i2 Notebook Web API gives your plug-in access to two kinds of information:

    • Application data, such as the current user, theme, and locale.
    • Chart data, such as the schema, the records on the chart, the current selection, and the view.

    This page shows you how to read both kinds of data, and how to safely combine reads and writes when your code involves asynchronous operations.

    Application data

    Data that's relevant to the whole application, such as user, theme, and locale data, is available directly from the root API object — both the entry point API and the tool view API extend the IApplication interface.

    const api = await getToolViewApi();
    
    const user = api.user;
    const appearance = api.theme.appearance;
    const locale = api.formattingLocale;
    

    Did you know? When the i2 Notebook web client opens a tool view, it includes some theme and locale data in the URL as query parameters. This is useful when you want to render your tool view immediately, before await getToolViewApi() resolves. The available parameters are:

    • ?baseTextDirection
    • ?flowDirection
    • ?formattingLocale
    • ?translationLocale
    • ?appearance
    • ?themeName (deprecated — use ?appearance instead)

    Chart data

    Chart data is also available directly from the root API object. Both IEntryPointApi and IToolViewApi extend IApplicationContents, which provides chart and view properties.

    const api = await getToolViewApi();
    
    // The schema describes what types of records can appear on the chart.
    const personType = api.chart.schema.getItemType(personAnalyzeItemTypeId);
    
    // Records, elements, and the current selection are all on `api.chart`.
    const selectedRecords = api.chart.selection.records;
    const allRecords = api.chart.records;
    
    // The view describes what the user is currently looking at.
    const zoomScale = api.view.zoomScale;
    

    Note: When you use the entry point API, chart and view are only available after you call await api.initializationComplete(). The tool view API has them available as soon as getToolViewApi() resolves.

    What's available on api.chart

    The api.chart object provides access to everything on the chart:

    • api.chart.schema — the schema: record types, property types, notes, and security settings.
    • api.chart.records — all records on the chart, including their property data, metadata, notes, source references, and security information.
    • api.chart.elements — the nodes and edges on the chart surface.
    • api.chart.selection — the currently selected records and elements.

    For more information about the chart schema and how to use it, see Chart schema and identifiers.

    Visual data

    Visual data comes in two forms. The chart view describes what the chart itself looks like — its center, extent, and zoom level — and is available through api.view.

    The chart elements — the nodes and edges that users interact with on the chart surface — are available through api.chart.elements.

    Record data

    Every element on an i2 Notebook chart can contain records. Each record contains:

    • Property data
    • Metadata, including creation date and time, display name, and principal name
    • Notes, source references, and security information

    You can get information about all the records on the chart through api.chart.records. Some event handlers also receive more specific record data. For example, the chartchange event payload contains the records (and elements) that changed. The onExecute() method of a command receives an IRecordsContext representing the records that were selected when the user invoked the command.

    Reacting to changes

    You can register event handlers to respond when the chart changes. For example, the chartchange event fires when records are added, removed, or modified — whether by the user or by another plug-in:

    api.addEventListener('chartchange', (change, applicationContents) => {
      // Respond to records or elements that have changed.
      const changedRecords = change.records;
      const changedElements = change.elements;
    });
    

    You can also listen for selection and view changes. The chartselectionchange event payload includes an ISelection object, while the chartviewchange event provides direct access to the IChartView interface:

    api.addEventListener('chartselectionchange', (selection, applicationContents) => {
      const selectedRecords = selection.records;
      // Update your UI to reflect the new selection.
    });
    
    api.addEventListener('chartviewchange', (view, applicationContents) => {
      const zoomScale = view.zoomScale;
      // Respond to the user panning or zooming the chart.
    });
    

    For the full list of events, see ApplicationEventMap.

    Did you know? Most event handlers also receive an IApplicationContents argument, so you can access the rest of the chart from inside the handler — for example, applicationContents.chart.schema and applicationContents.view.

    Using transactions with async operations

    Reading chart data directly from api is fine for synchronous code. However, if you await an asynchronous operation, the chart might change in the meantime — another plug-in could add records, or the user could change the selection. After the await, values you read earlier might be stale:

    // Not safe — the chart data might change during the await.
    const selected = api.chart.selection.records;
    const enriched = await fetchExtraDataFor(selected);
    
    // By now, `selected` might not match what's on the chart.
    await api.runTrackedMutations((application, mutations) => {
      applyEnrichment(mutations, enriched);
      return { type: 'commit' };
    });
    

    To avoid this, use runTransaction(). The transaction callback receives an applicationContents argument that provides a consistent, point-in-time view of the chart — even across await boundaries. Any mutation that follows will wait until the transaction is complete before executing:

    let enriched;
    api.runTransaction(async (applicationContents) => {
      // Read from applicationContents, not from api — this is guaranteed to be consistent.
      const selected = applicationContents.chart.selection.records;
      enriched = await fetchExtraDataFor(selected);
    });
    
    // This call waits until the transaction above is complete before executing.
    await api.runTrackedMutations((application, mutations) => {
      applyEnrichment(mutations, enriched);
      return { type: 'commit' };
    });
    

    Note: If you only need to make changes (without an async step between read and write), you can call runTrackedMutations() or runUntrackedMutations() directly. Tracked mutations are added to the undo stack as a single entry; untracked mutations are not. See Mutations and Mutation commands for details.

    Further reading

    • ApplicationEventMap — the full list of events you can listen for.
    • Mutations and Mutation commands — how to make changes to the chart.
    • The Angular, React, and Vue plug-in tutorials — end-to-end examples that combine data access, events, and mutations.
    In this article
    Back to top © N. Harris Computer Corporation