v2.2.0

Placement Manager Class

Used for managing the placement of widgets in the Bitrix24 application.

Learn more

Getters

title

get title(): string

Alias of placement. Returns the placement title ('DEFAULT' when no title was provided by the parent window).

placement

get placement(): string

Returns the placement title. By default, returns 'DEFAULT' if the title is not set.

isDefault

get isDefault(): boolean

Returns true if the placement title is 'DEFAULT'.

options

get options(): Readonly<Record<string, unknown>>

That return type is exported as PlacementOptions, so a helper taking these can name it rather than restate the expansion:

import type { PlacementOptions } from '@bitrix24/b24jssdk'

The parameters this frame was opened with, always as a frozen object — the freeze is one level deep, so a nested value is still the portal's own object. Including every parameter you passed to slider.openSliderAppPage, which is how place reaches the new frame.

Values are unknown, so narrow before you use one. This data crosses a postMessage boundary from the portal; the type says so instead of pretending otherwise.

const place = $b24.placement.options['place']
if ('string' === typeof place) {
  console.log(`opened from ${place}`)
}
Four inputs are normalised before they get here. Measured on one on-premise build (SM_VERSION 26.150.0), the portal sends an object, an empty string when the placement was opened with no parameters at all, or nothing at all — that last one is what #485 hit, because Object.freeze(undefined) is undefined and a field declared object held it anyway. A JSON string is handled too, though it was not observed on this path: it belongs to the form-resubmit route, and parsing it costs one typeof.Each becomes an object, so options is never undefined and needs no ?. — an empty placement is an empty object. The cost of that: an absent value, '', a genuinely empty object, an array and an unparseable string are now indistinguishable, and there is no accessor for the raw value.
Key case is the portal's choice, not a convention. For the default placement the object is the frame URL's query string, so the keys are whatever the opener wrote; for a registered placement they are whatever the application stored at bind time. Do not assume either case.

isSliderMode

get isSliderMode(): boolean

Returns true if the widget is operating in slider mode (option IFRAME is 'Y').

It is derived from PLACEMENT_OPTIONS.IFRAME, so do not use it to decide whether placement data arrived at all. Gating slider diagnostics on it is a trap: the flag is computed from the very data whose absence you would be trying to diagnose, so the log line goes quiet exactly when you need it.

// ... /////
$b24 = await initializeB24Frame()
// ... /////
if ($b24.placement.isSliderMode) {
    $b24.parent.setTitle('SliderMode') // updates the layout #pagetitle, not the slider header or browser tab
}

Methods

getInterface

async getInterface(): Promise<any>

Getting information about the JS interface of the current embedding location: a list of possible commands and events.

// ... /////
$b24 = await initializeB24Frame()
// ... /////
const value: any = await $b24.placement.getInterface()

bindEvent

async bindEvent(
  eventName: string,
  callBack: (...args: any[]) => void
): Promise<any>

Setting up the event handler for the interface.

ParameterTypeDescription
eventNamestringName of the interface event to handle.
callBack(...args: any[]) => voidHandler invoked when the event fires.

call

async call(command: 'setValue', parameters: { value: string }): Promise<any>
async call(command: string, parameters?: Record<string, any>): Promise<any>

Call the registered interface command.

import { LoggerFactory } from '@bitrix24/b24jssdk'
// ... /////
const logger = LoggerFactory.createForBrowser('Demo', true)

$b24 = await initializeB24Frame()
// ... /////
$b24.placement.call('reloadData')
  .then((respose: any) => {
    logger.info('reload call')
  })
The setValue command is special: the parent window calls JSON.parse(value) on the received payload, so valuemust be a JSON-serialized string. Passing a raw string or an object directly will fail (SyntaxError from JSON.parse, or silent corruption to "[object Object]").Prefer the setValue helper, which serializes for you. If you use call('setValue', ...) directly, the SDK will throw a TypeError when value is not a string.
// ✗ throws TypeError — value is not a string
await $b24.placement.call('setValue', { value: 'test' })

// ✓ works — value is a JSON string
await $b24.placement.call('setValue', { value: JSON.stringify('test') })
await $b24.placement.call('setValue', { value: JSON.stringify({ id: 1 }) })

setValue

async setValue(value: unknown): Promise<any>

Convenience wrapper around placement.call('setValue', ...) that performs JSON.stringify on the value for you. Accepts any JSON-serializable value (string, number, boolean, object, array).

$b24 = await initializeB24Frame()
// ... /////
await $b24.placement.setValue('test')
await $b24.placement.setValue({ id: 1, title: 'demo' })

callCustomBind

async callCustomBind(
  command: string,
  parameters: null | string | Record<string, any>,
  callBack: (...args: any[]) => void
): Promise<any>

Calls an interface command and registers a callback that receives subsequent events from the command. Use this for commands that emit ongoing events (e.g. progress updates) instead of resolving once.

parameters accepts three shapes:

  • null — no payload.
  • string — sent as singleOption.
  • Record<string, any> — spread into the message payload.
$b24 = await initializeB24Frame()
// ... /////
$b24.placement.callCustomBind('subscribe', { topic: 'crm:deal' }, (event) => {
  console.log('event', event)
})