Documentation

Dialog

General:

Dialog

Entity selection dialog is a pop-up window, containing list of items that can be grouped by tabs.

Additionally, dialog window can have an integrated search bar with option to create new items, as well as special footer containing links to external interfaces.

Items

Item — is a listed element.

Usually, items are shown in specific tabs. This condition is optional, however. If an item is not bound to any tab, it still can be found via search.

Each item is uniquely identified by the two attributes: id and entityId:

  • id — numerical or string item ID.
  • entityId — entity string ID.

entityId attribute defines the item association to a specific entity. That's why the dialog allows simultaneously show and select items of different entities.

const dialog = new Dialog({
    items: [
        { id: 1, entityId: 'my-entity', title: 'Item A, tabs: 'my-tab' },
        { id: 2, entityId: 'my-entity', title: 'Item B', tabs: 'my-tab' },
        { id: 3, entityId: 'my-entity', title: 'Item C', tabs: 'my-tab' },
        { id: 1, entityId: 'my-user', title: 'John Smith', tabs: 'my-tab' },
        { id: 2, entityId: 'my-user', title: 'Christopher Matthews', tabs: 'my-tab' },
        { id: 'USD', entityId: 'my-currency', title: 'USD', tabs: 'my-tab' },
    ],
    tabs: [
        { id: 'my-tab', title: 'My Tab' }
    ],
    showAvatars: false,
    dropdownMode: true
});

dialog.show();

Entities

Entity — is a unique type of item that can define the following:

Entity settings are defined either by globally (recommended), or directly when creating a dialog object (option entities).

Adding items to dialog

Completing item dialog is performed by two methods:

  • Statically — item and tab data is directly passed into class constructor Dialog.

    const button = document.getElementById('button');
    const dialog = new Dialog({
      targetNode: button,
      width: 400,
      height: 300,
      dropdownMode: true,
      showAvatars: false,
      compactView: true,
      tabs: [
          { id: 'cities', title: 'Cities', itemOrder: { 'title': 'asc' }  },
          { id: 'countries', title: 'Countries', itemOrder: { 'title': 'asc' } },
      ],
      items: [
          { id: 1, entityId: 'city', tabs: 'cities', title: 'Los Angeles' },
          { id: 2, entityId: 'city', tabs: 'cities', title: 'New York' },
          { id: 3, entityId: 'city', tabs: 'cities', title: 'Dallas' },
          { id: 4, entityId: 'city', tabs: 'cities', title: 'Salt Lake City' },
          { id: 5, entityId: 'city', tabs: 'cities', title: 'Oklahoma' },
          { id: 6, entityId: 'city', tabs: 'cities', title: 'Las Vegas' },
          { id: 7, entityId: 'city', tabs: 'cities', title: 'Warsaw' },
          { id: 8, entityId: 'city', tabs: 'cities', title: 'Berlin' },
          { id: 1, entityId: 'country', tabs: 'countries', title: 'Germany' },
          { id: 2, entityId: 'country', tabs: 'countries', title: 'United States of America' },
          { id: 3, entityId: 'country', tabs: 'countries', title: 'France' },
          { id: 4, entityId: 'country', tabs: 'countries', title: 'England' },
          { id: 5, entityId: 'country', tabs: 'countries', title: 'Poland' },
          { id: 6, entityId: 'country', tabs: 'countries', title: 'Italy' },
        ],
    });
    
    dialog.show();
    

  • Dynamically — data is uploaded from the backend using data providers.

    const button = document.getElementById('button');
    const dialog = new Dialog({
      targetNode: button,
      enableSearch: true,
      context: 'MY_MODULE_CONTEXT',
      entities: [
          {
              id: 'user', // users
          },
          {
              id: 'department', // company structure: selecting users only
          },
      ],
    });
    
    dialog.show();
    

    Opened dialog queries the backend and gets data from corresponding provides. Necessity of backend query is determined by available entities (entities option), having the property dynamicLoad set as true. Standard entities have a dynamicLoad set globally, that's why there's no need to specify this entity (see. example above).

Both methods can be used simultaneously.

Item DOM nodes

Each dialog item can have several visual representations. This allows to display the same item at different tabs or at different levels of tree representation.

This dialog item is represented by the class Item, and its visual presentation by the class ItemNode. In other words, class ItemNode represents the item's DOM-node.

Data (title, avatar and etc.), displayed by DOM node can be specified for both specific presentation and item. In this case, all DOM nodes will look the same. Also there's an option to set visual parameters for the item globally in entity settings.

Tabs

Tabs allow to dialog items into tabbed groups. By default, dialog creates two system tabs: "Recent" and "Search". The "Recent" tab shows items (on dynamic load), selected by the user at the last time. The "Search" tab is hidden by default and is activated only at the moment of search phrase input.

When tab doesn't have items, shows the "stub". instead of empty list. This "stub" can be customized as desired.

"Recent" tab

When user selects items in the dialog, this fact is memorized at the backend. Next time, when opening the dialog, these items will be automatically displayed at the "Recent" tab.

Items selected by user are memorized within the context — character identifier, specified when creating dialog in option of context. Context ID is used for both creating various lists of "recent" items, as well as for setting them as the same within, for example, a single service.


Note: If when creating a dialog, service is not specified, selected items won't be memorized.

The same item can be selected in various dialogs and contexts. To easily manage (using data provider) the list of items for "Recent" tab, there are two types of context:

  • Local (current) context — context (indicated when creating a dialog), with automatically selected items at the "Recent" tab.

    There are following methods available in the provider for handling the local context items:


  • Global context — all the rest of contexts with user selecting items of various entities.

    To get items from global context in data provider, user the method getGlobalRecentItems().

Search

Search form is enabled by the option enableSearch: true.

By default, search is performed by all dialog items. You can cancel the search globally for all entity items (option searchable), as well as for specific item (similar option searchable).

Search phrase is searched in the item title and subtitle. You can expand fields for search, as well as for specifying their priority using the option searchFields in entity settings.

Creating new item from search

As an extra feature, you can create a new item using the search form. This option is enabled using the option searchOptions.allowCreateItem.

Creating new item is delegated to external code, executed at the event Search:onItemCreateAsync.

const button = document.getElementById('button');
button.addEventListener('click', function() {
   dialog.show();
});

const dialog = new Dialog({
    targetNode: button,
    width: 400,
    height: 300,
    dropdownMode: true,
    enableSearch: true,
    compactView: true,
    showAvatars: false,
    tabs: [
        { id: 'cities', title: 'Cities', itemOrder: { sort: 'asc',  title: 'asc' } },
        { id: 'countries', title: 'Страны', itemOrder: { 'title': 'asc' } },
    ],
    items: [],
    searchOptions: {
        allowCreateItem: true,
        footerOptions: {
            label: 'Create city:'
        }
    },
    events: {
        'Search:onItemCreateAsync': (event) => {
            return new Promise((resolve) => {

                const { searchQuery } = event.getData();
                const dialog = event.getTarget();

                setTimeout(() => { // asynchronous action emulation
                    let tab = dialog.getTab('cities');
                    const item = dialog.addItem({
                        id: Text.getRandom(),
                        entityId: 'city',
                        title: searchQuery.getQuery(),
                        tabs: 'cities',
                        // can be used for item sorting at the tab
                        // cities tab indicates sorting by this field.
                        sort: 1 
                    });

                    if (item)
                    {
                        item.select();
                    }

                    dialog.selectTab(tab.getId());
                    resolve();

                }, 1000);
            });
        }
    }
});

Search query caching

By default, dialog caches search queries to reduce number of backend queries. It's deemed, that provider fully passes all data for indicated search phrase when processing a search query at the backend. For example, if provider has returned data by the phrase "John", the dialog won't send a query to the backend for the "Smith" phrase.

You can cancel caching algorithm by default using the two methods:

Footer

Dialog interface provides for footer containing additional links or arbitrary layout.

Footer can be specified as both globally for the complete dialog, as well as separately for specific tab.

The following examples show different variants for footer:

const options = {
	footer:
		`<a href="/" class="ui-selector-footer-link ui-selector-footer-link-add">Invite employee</a>
		<span class="ui-selector-footer-conjunction">or</span>' +
		<a href="/" class="ui-selector-footer-link">invite a guest</a>`,
};

const options = {
	footer: Tag.render`<span class="ui-selector-footer-link" onclick="${this.handleCLick}">invite</span>`,
};

const options = {
	footer: [
		Tag.render`<span class="ui-selector-footer-link" onclick="${this.handleCLick}">invite</span>`,
		Tag.render`<span class="ui-selector-footer-link" onclick="${this.handleMore}">more</span>`,
    ]
};

Custom footer based on default footer:

class MyStandardFooter extends DefaultFooter
{
    constructor(dialog: Dialog, options: { [option: string]: any })
    {
        super(dialog, options);
    }

    getContent(): HTMLElement | HTMLElement[] | string | null
    {
        return this.cache.remember('content', () => {
            const showLabel = this.getOption('showLabel', false);
            return Tag.render`
                <div class="my-module-footer-class">
                    ${showLabel ? 'My Footer' : ''}
                </div>
            `;
        });
    }
}

const options = {
    footer: MyStandardFooter, // Or full class name as a string 'Vendor.MyModule.MyStandardFooter'.
    footerOptions: {
        showLabel: true
    }
};

Footer with fully arbitrary layout:

class MySpecialFooter extends BaseFooter
{
    constructor(dialog: Dialog, options: { [option: string]: any })
    {
        super(dialog, options);
    }

    render(): HTMLElement
    {   
        return this.cache.remember('content', () => {
            const showLabel = this.getOption('showLabel', false);
            return Tag.render`
                <div class="my-module-footer-container">
                    <div class="my-module-footer-class">
                        ${showLabel ? 'My Footer' : ''}
                    </div>
                </div>
            `;
        });
    }
}

const options = {
    footer: MySpecialFooter, // Or full class name as a string 'Vendor.MyModule.MyStandardFooter'
    footerOptions: {
        showLabel: true
    }
};


© «Bitrix24», 2001-2024