Прошу у коллективного разума помощи в объяснении происходящего.

Юзкейс:
Верхнее горизонтальное меню. Карточка "Обращения" добавить кнопку-выпадающий список, пункты которого, фактически будут инициировать создание нового Email (активности) с разными входными параметрами и настройками фильтрации в нем относительно полей "Кому", "От кого" и.т.

Предпринятые действия: Уже ставшая обыденной проблема того что карточка может быть открыта в 2-х режимах: "Combined" и "Separated", т.е. это фактически разные схемы, а как следствие модели в текущем окружении.
1) Чтобы по 2 раза не дублировать логику создадим миксин-модуль, и соберем в нем всю необходимую функциональность: метод объявляющий пункты меню, методы-обработчики непосредственно для пунктов меню, вспомогательные методы (н/п метод помогающий получить Id текущей карточки вне зависимости от текущего режима, определяющий его по косвенным признакам и workAreaMode и соответственно получающий или this.get("Id") или this.get("ActiveRow"), или восстанавливающий его из HistoryState, или даже получающие его через "GridData" если все остальные способы не сработали)
2) Выделим в отдельный модуль - наши события, чтобы их собственно 2-ды не определять в карточках карточки и секции, в последних в свою очередь предусмотрим при инициализации карточки - регистрацию событий из объекта зависимости, при помощи this.sandbox.registerMessages, в Миксине объявим метод осуществляющий подписки на события и в схеме карточки и раздела при инициализации вызовем этот метод.
3) У "Обращения" уже предусмотрена деталь "Email", само собой нам надо будет либо вызывать карточку Email (EmailPageV2) из своего кода через openCardInChain и далее реализовывать регистрацию в детали сообщения самостоятельно, или же использовать уже готовую логику детали, и вызывать ее штатный addRecord() метод - что гораздо проще и лаконичнее.
4) Создаем замещающую схему детали в котором подписываемся на событие которое генерирую наши пункты меню, в колбэке-подписчике просто вызываем addRecord(); метод.
...Пока что все получает очень просто.
5) Далее пунктов меню 3-шт. у каждого своя "смысловая нагрузка", стало быть нам требуется организовать логику позволяющую определить какой из пунктов вызвал наш addRecord, для этого в замещающей схеме EmailPageV2 мы при инициализации генерируем событие-запрос и подписываемся на событие-ответ, на которое предварительно установлен подписчик в наших схемах карточки или секции (не важно, так как подписчики вызываются идентично из Миксина), обработчик которого в свою очередь генерирует событие-ответ, и уже в этом событии и передает все необходимые данные, в том числе и "нажатый пункт меню".

И вот тут нас поджидает сюрприз:
Для того чтобы сохранить статус (какой пункт нажат) перед вызовом события - которое инициирует в детали addRecord (это кстати косвено приводит нас к потере окружения, т.к. метод addRecord мы не контролируем лишь знаем что в конечном итоге он откроет EmailPageV2).
Так вот, сохраним значение в текущей модели - this.set("myState", myStateStringIdentifier);
Логика такова: раз наша подписка на событие-запрос осуществленная при инициализации схемы (карточки или секции) т.е. к this, а стало быть к модели, то коллбэк-обработчик которому передать при подписке this вторым аргументом будет выполняться в его окружении, а стало бы с той-же моделью, т.е. в нем можно будет получить сохраненное значение через this.get("myState").

Но это не так... Вся цепочка отлично отрабатывает в случае страницы открытой в Separate режиме - вообще без изъянов.
А вот с Combined режимом получается вот какое поведение:
замещающая схема CaseSection

                methods: {
                        "onEntityInitialized": function() {
                                this.callParent(arguments);
                                this.AskQuestionMixinSUBSRIBER(this);
                                document.scope = this;
                        },
                        "init": function() {
                                this.callParent(arguments);
                                this.sandbox.registerMessages(AksQuestionMessages.messages);
                                this.initAskQuestionMenuCollection();
                        }
                },

AskQuestionMixinSUBSRIBER - метод объявленный в миксин-модуле
                AskQuestionMixinSUBSRIBER: function(scope) {
                        this.sandbox.subscribe(
                                "AskQuestionEmailTypeRequest",
                                function() {
                                        this.sandbox.publish(
                                                "AskQuestionEmailTypeResponse",
                                                {askType: this.get("askType")},
                                                ["AskQuestion_from_Case_" +  this.getCaseID()]
                                        );
                                },
                                scope,
                                ["AskQuestion_from_Case_" + this.getCaseID()]
                        );
                }

Обработка пункта меню приводит к сохранению состояния в this.set("askType", askType)

Но коллбек будучи выполненным из Combined режима - все равно теряет окружение, несмотря на то, что во время подписки ему явно передали "scope"
Т.е. когда он выполняется - this.get("askType") // undefined
Чего кстати не происходит в Sepated режиме.

PS: Пока что я решил вопрос через расширение глобального window.Terrasoft объекта своим свойством в котором сохраняю "askType". Но по мне это "не очень решение".

Нравится

7 комментариев

Здравствуйте, Илья.

Более простым решением будет:

1) Заместить в секции метод initQueryColumns - для подтягивания в GridData колонок, которые есть в карточке, однако не выведены в реестр.

2) При нажатии на кнопки выпадающего меню вызывать метод openCardInChain. Данный метод позволяет не только открывать карточку, а и передавать значения в атрибуты открывшейся карточки. Получать значения необходимо основываясь на режиме карточки.

Пример openCardInChain с передачей значений атрибутов:

this.openCardInChain({
	schemaName: "EmailPageV2",
	operation: "add",
	moduleId: "00000000-0000-0000-0000-000000000000",
	defaultValues: [{name: "atr1", value: "value 1"}, {name: "atr2", value: "value2"}]
});

про openCardInChain и преимущества этого подхода, мне известно.

А вот про

1) Заместить в секции метод initQueryColumns - для подтягивания в GridData колонок, которые есть в карточке, однако не выведены в реестр.

Хотелось бы попросить Вас написать еще пару слов, просто чтобы понимать возможности системы, может в исходных кодах какой либо конфигурации можно посмотреть юзкейз.
Я так понимаю этот метод принимает объект ESQ-запроса на исполнение, т.е. именно он и фактически получает данные в модель - так ?
Я не много не понимаю назначения метода и как с ним положено работать.

PS: у каждого окружения есть "Backbone.Model" - this.model обладающий уникальным cid, можно ли как-то обращаться к конкретной загруженной модели с заведомо известным cid ? или получить модель из БД зная ее идентификатор ?

Метод initQueryColumns по сути принимает esq, которое и будет вытаскивать данные в раздел. В базовой реализации данный метод добавляет к esq базовые колонки (первичная для отображения колонка итд), а также колонки, выведенные в грид.

Для того, чтобы в GridData присутствовали дополнительные колонки - необходимо заместить метод примерно следующим образом:

initQueryColumns: function(esq) {
	this.callParent(arguments);
	esq.addColumn("DayType.NonWorking");
        esq.addColumn("Test");
},

В итоге получить значения в секции можно кодом:

   var a = activeRow.get("DayType.NonWorking");
   var b = activeRow.get("Test");
activeRow.get("DayType.NonWorking");

я так понимаю через this.get() ?
Или activeRow это какой-то особенный объект ?

activeRow это элемент текущей (выделенной) строки.

var activeRow = this.getActiveRow();
var b = activeRow.get("Test");

activeRow насколько я понимаю присутствует только когда карточка открыта в Combined режиме ?

Это свойство самого грида, как в реестре раздела, реестре детали так и в комбинированном режиме.

Показать все комментарии