Table of Contents

Legacy JavaScript API (deprecated)

Warning

This is the legacy client-side JavaScript API of the pre-React MVC pipeline. New code must use the React hooks documented in React Hooks & Events. This page is preserved only as a migration reference for maintaining surviving legacy MVC components.

The legacy MVC pipeline exposed a global MIB.Template.Manager object on window. Custom MVC components registered callbacks against its lifecycle events. Inline <script> blocks were embedded via the Razor @Html.DelayedScript helper. None of this is used by the modern React shell.

A thin compatibility shim that still exposes MIB.Template.Manager on window may ship for some deployments — do not write new code against it. It will be removed in a future major version.

@Html.DelayedScript — inline <script> blocks in Razor views

Inline scripts inside a legacy component view must be wrapped in the DelayedScript helper so they are moved to the end of the page, after all component DOM nodes have rendered:

@using MibServer3.Model.Extensions

@Html.DelayedScript(
  @<script type="text/javascript">
    // Scripts go here
  </script>
)

Without this helper, scripts run in source order — typically before their target DOM nodes exist — and break.

The helper buffers each component's script blocks during render and flushes them into a single <script> block at the end of the body. This is the only mechanism by which a legacy component contributes JS to the page.

GetScripts() / GetStyles()

Legacy components also implement IRenderableComponent.GetScripts() and GetStyles(), returning a List<string> of URLs that the BFF injects into the page's <head> / before </body>. These are global across the page, not scoped to the component.

Modern replacement. Bundle the JS / CSS inside a federated React remote — see Shipping Custom JavaScript. Module Federation handles scoping and deduplication.

MIB.Template.Manager.RefreshComponentView — re-render

Refreshes a single component without a full-page reload:

MIB.Template.Manager.RefreshComponentView(
  { TemplateComponentKey: 'my_key', JsonData: {} },
  function (data) { /* updated viewdata */ }
);

The data parameter must be a CollectDataResult:

function CollectDataResult() {
    this.TemplateComponentKey = '';
    this.JsonData = new Object();
}

The callback receives a data object containing the information returned from the server-side.

Modern replacement. Implement IRefreshableComponentV2<TConfig, TViewData> on the C# side; the React shell exposes a refresh() callback on the widget's props that re-pulls the component's data:

const MyWidget = ({ refresh }: MibComponentProps<S, D>) => (
  <button onClick={() => refresh?.()}>Refresh</button>
);

See Component Authoring — Refresh.

Persist workflow — OnCollectData / OnPersistDeliverResponses

The legacy save flow was a two-step round-trip:

MIB.Template.Manager.OnCollectData(callback, templateComponentKey);
MIB.Template.Manager.OnPersistDeliverResponses(callback, templateComponentKey);

OnCollectData is called when the user clicks Save, and must return a CollectDataResult with the data to send to the server. During this step all validation runs on the client; if a component detects an invalid value it throws an exception, which stops the persist process.

OnPersistDeliverResponses is called after the server-side save, receiving a DeliverResponseResult with the data the C# side sent via OnAfterSave plus a deliver callback:

function DeliverResponseResult() {
    this.TemplateComponentKey = '';
    this.JsonData = new Object();
    this.Status = '';
    this.ErrorMessage = '';
}

Status values:

var DeliverResponseStatus = {
    "Success":             0,
    "SuccessNoContent":    1,
    "Error":               2,
    "NoOperation":         3,
    "ValidationException": 4
};

If a component threw PersistenceValidationException on the server, its callback must invoke the deliver callback with a DeliverResponseCollectResult:

function DeliverResponseCollectResult() {
    this.TemplateComponentKey = '';
    this.Operation = '';
    this.Message = '';
}

var DeliverResponseOperation = {
    None: 0,
    ShowError: 1,
};

If the manager receives a result with ShowError, it shows a modal popup with the error message. A typical legacy implementation:

MIB.Template.Manager.OnPersistDeliverResponses(
  function (deliverResult, deliverCallback) {
    if (deliverResult.Status == DeliverResponseStatus.ValidationException) {
      var collectResult = new DeliverResponseCollectResult();
      collectResult.TemplateComponentKey = 'my_key';
      collectResult.Message = deliverResult.ErrorMessage;
      collectResult.Operation = DeliverResponseOperation.ShowError;

      deliverCallback(collectResult);
    }
  }, '<my_template_component_key>'
);

When a component on a page succeeds but another component on the same page fails, each succeeding component receives a result with NoOperation status.

Modern replacement. The React shell exposes useContentEdition().onSave() from @agilecontent/mib-modules:

const { onSave } = useContentEdition();
useEffect(() => onSave(async () => {
    await api.persistMyWidgetState(localState);
}), [localState]);

The shell awaits every registered onSave callback in parallel; any thrown error / rejected promise aborts the save and surfaces an error notification automatically. The DeliverResponseStatus enum is not part of the React-era contract. See React Hooks & Events — useContentEdition.

MIB.Template.Manager.OnConfirm — pre-save confirmation gate

Added in MIB v5.0.5 to allow components to insert asynchronous behaviour before save:

MIB.Template.Manager.OnConfirm(callback);

The callback receives a confirmCallback that must be invoked for the save to proceed. Every registered OnConfirm callback must call its confirmCallback; if any doesn't, the save stalls.

Example pattern — ask the user before continuing:

MIB.Template.Manager.OnConfirm(function (confirmCallback) {
    if (MyLib.MyClass.ShouldAskForConfirmation()) {
        MIB.Alerts.Confirmation("Do you really want to continue?", confirmCallback);
    } else {
        confirmCallback();
    }
});

Modern replacement. useContentEdition().onConfirm() returns a Promise<boolean>. If any registered callback resolves to false, the save is aborted:

const { onConfirm } = useContentEdition();
useEffect(() => onConfirm(async () => {
    if (await needsApproval()) return confirm('Submit for approval?');
    return true;
}), []);

MIB.Selection.Open — aside selector

Opens the legacy aside selector:

MIB.Selection.Open(callback, mediaType, options);
Parameter Meaning
callback Receives an array of { id, name } objects when the operator confirms a selection
mediaType The mediatype to list
options Reserved (single/multi mode etc. — implementation varies)

The callback receives:

[
  { id: 1, name: "First Item" },
  { id: 2, name: "Second Item" }
]

Pre-open filters — MIB.Selection.OnBeforeOpen

MIB.Selection.OnBeforeOpen(function (mediaType, fieldCollectCallback) {
    var fields = new Array();
    fields.push({ Field: 'NAME',         Operator: 'STARTSWITH', Value: 'MIB' });
    fields.push({ Field: 'SOURCE[ID]',   Operator: 'EQUAL',
                  Value: '[mib_form.SOURCE]' });
    fieldCollectCallback(fields);
});

SelectionFilter shape:

function SelectionFilter() {
    this.Field    = '';
    this.Operator = '';
    this.Value    = '';
}

Supported operators:

EQUAL, NOTEQUAL,
GREATERTHAN, GREATEROREQUAL,
LESSTHAN, LESSOREQUAL,
CONTAINS, STARTSWITH, ENDSWITH,
IN

Value can be a static value or a reference to a field in a default MIB FormComponent via [<templateComponentKey>.<field>].

Modern replacement. useSelection().open(...) returns a Promise<Selected[]>; pre-open filters are passed as initialFilters in the same call:

const { open } = useSelection();
const picked = await open({
    mediaType: 'AUTHORS',
    multi: false,
    initialFilters: [{ field: 'ACTIVE', operator: 'EQUAL', value: true }],
});

See React Hooks & Events — useSelection.

Form-field change — MIB.Component.Form.OnChange

Subscribe to changes on any form field:

MIB.Component.Form.OnChange(function (changeResult) {
    console.log(changeResult);
});

// changeResult shape:
function ChangeResult() {
    this.TemplateComponentKey = "";
    this.MediaType            = "";
    this.Ids                  = "";
    this.Field                = "";
    this.Value                = "";
}

Modern replacement. The stock React form component dispatches changes via its own callback prop / context (useFormContext from the form widget's package). For cross-widget reactions, prefer the shared-hook pattern documented under React Hooks & Events — Cross-widget communication.

MIB.Alerts.* — modal alerts

MIB.Alerts.Confirmation('Continue?', callback);
MIB.Alerts.Error('Something went wrong');

Modern replacement. useNotification():

const { error, modal } = useNotification();
modal({ title: 'Continue?', onOk: () => proceed() });
error('Something went wrong');

MIB.User.Preferences.Save — user preferences

The legacy global for persisting user preferences (interface language, page-state etc.):

var preferenceList = [];
var preference = new PreferenceData();
preference.key   = "interface_language";
preference.value = "pt-br";
preferenceList[0] = preference;

MIB.User.Preferences.Save(preferenceList, function () { });

Modern replacement. Send a POST /api/preferences with the same key/value semantics. The React shell does this internally for the user's language preference; for ad-hoc programmatic preference changes, call the endpoint directly with an authenticated session cookie.

MIB.Template.Manager.GetHandlerUrl — URL of a /Handler/ endpoint

Builds the URL of an IHandlerComponent endpoint:

var url = MIB.Template.Manager.GetHandlerUrl(templateComponentKey);

The returned URL is /Handler/<currentPageKey>/<templateComponentKey>.

Modern replacement. Register a standard ASP.NET Core controller or minimal-API endpoint in the customisation. The React shell calls it like any other HTTP endpoint via the @agilecontent/mib-api-connector package or fetch directly.

Compatibility shim

A thin shim that exposes the MIB.Template.Manager, MIB.Selection.*, MIB.Alerts.*, and MIB.Component.Form.* globals on window may still ship for some deployments to support straggler legacy components. Do not write new code against it. The shim is best-effort and will be removed in a future major version.

See also