Биндиг (bindTo) свойства поля "visible" на метод.
Версия приложения 7.9.1
Юзкес: привязать свойство справочного поля "visible" некой карточки, к некой бизнес-логике.
Пердпринятые действия
При помощи мастера раздела, и редактора страницы на страницу контакта было добавлено новое справочное поле, н/п в карточке контакта добавлено поле "Страна" (ContactCountry)
см.вложение country.png
Далее в сгенерированной замещающей схеме с группе свойств конфигурационного объекта для поля был добавлен биндинг свойства "visible" к методу "ContactCountryVisibilityController"
и объявлен сам метод.
{
"operation": "insert",
"name": "ContactCountrye97c8637-0ade-42fc-95e1-a37e1971b25e",
"values": {
"layout": {
"colSpan": 12,
"rowSpan": 1,
"column": 12,
"row": 2,
"layoutName": "ContactGeneralInfoBlock"
},
"labelConfig": {},
"enabled": true,
"contentType": 5,
"bindTo": "ContactCountry",
"visible": {"bindTo": "ContactCountryVisibilityController"}
},
"parentName": "ContactGeneralInfoBlock",
"propertyName": "items",
"index": 4
},
...
ContactCountryVisibilityController: function() {
if (this.get("ContactCountry") !== undefined) {
return true;
} else {
return false;
}
}
}
Проблема:
во-первых - если поставить точку останова внутри объявленного выше метода, то код метода при загрузке страницы выполняется 6-10 раз !!!
во-вторых - во время отладки, даже если метод возвращает true (в случае когда целевое поле заполнено), то свойство всё равно не принимает необходимого значения.
(поле в любом случае остается скрытым)
Т.е. биндинг не приносит желаемого результата.
Протестировано как в on-site версии, так и в облачной демо-версии.
Нравится
Здравствуйте!
Задача решается использованием бизнес-правил. Подробнее:
https://academy.terrasoft.ru/documents/technic-sdk/7-9/pravilo-bindpara…
Дело не том как можно.
Я изначально понимаю что есть три пути:
- 1. биндинг на атрибут
(И дальнейшее управление значением атрибута любой бизнес-логикой имеющей к нему прямой или опосредованный, через события, доступ) - 2. биндинг на метод
(Идеальный вариант если логика нужна лишь на этапе инициализации, или если используется функционал, который надо выполнить автоматически но он так-же является полезной нагрузкой какого либо другого элемента) - 3. использование конфигурационного объекта бизнес-правил
(Идеальный вариант для организации сложной логики по валидации и зависимости значений и полей друг от друга на этапе заполнения данных пользователем)
У каждого из подходов есть своя ниша - где его применение наиболее эффективно, просто и т.д.
Дело в том, что один из этих способов - ведет себя не предсказуемо, и не очевидно некорректно!
Вопрос в конечном итоге сводится к плоскости: "Или я дурак, или лыжи не едут ?"
Ну и собственно ежели первое - то хочется учиться у сведующих уму разуму, если второе то чтобы специалисты ТП обратили на нее внимание.
Уточните, пожалуйста, метод ContactCountryVisibilityController вызывается в методе onEntityInitialized?
он "забинжен" на свойство "visible" поля
т.е. должен вызываться при его инициализации
Бог с ней с моей самописной логикой, давайте возьмем базовую поставку
Возьмем к примеру схему BaseProfileSchema (пакет NUI - фактически ядро системы)
Где у нас имеется объявленный метод "getVisibleContent"
Возьмем карточку контрагента и воспользуемся поиском по исходным кодам, чтобы получить представление о количестве биндингов на данный метод или количество его прямых вызовов, возможного абстрагирования в других переменных и т.д. (см.вложение getVisibleContent_UsagesInContragentPage.png).
Оба биндинга принадлежат к той-же схеме "BaseProfileSchema" - это объекты "ProfileContentContainer" и "ProfileModuleActions", их свойство "visible"
Итого
во-первых: установив точку останова внутри метода getVisibleContent - во время загрузки страницы получаем 4-6 вызовов вместо положенных двух.
во-вторых: если на первом вхождении точки останова подменить вызываемую функцию, скорректировав возвращаемое ею значение
т.к. исходный код метода:
getVisibleContent: function() {
return !this.getVisibleBlankSlate();
},
Во время штатного выполнения кода getVisibleContent - возвращает "false" (т.е. забинженное на метод свойство "visible" должно устанавливаться в значение false, тем не менее элементы страницы "Добавить контакт" и "Выбрать" как раз таки отображаются см.вложение BasicFunctionality_ReturnFalse.png)
Если же мы подменим функцию this.getVisibleBlankSlate() таким образом чтобы метод getVisibleContent возвращал "true"
н/п this.getVisibleBlankSlate = function(){return false};
То несмотря на то, что метод начинает возвращать "true" - элементы как раз таки скрываются. см.вложение BasicFunctionality_ReturnTrue.png
Т.е. все с точностью да наоборот от ожидаемого поведения !
Свойство visible принимающее значение true (элемент показывается) значение false (элемент скрывается), по крайней мере если не биндить поле а указывать значение прим в описании схемы - работает по такому принципу.
Никакой разработки НОВОЙ функциональности - Это все штатные системные коды входящие в базовую поставку и их поведение в облачной демо версии!
Прошу Вас объяснить что в данном случае происходит:
1) Почему метод вызывается большее количество раз чем к нему идет обращений/биндингов ?
2) Почему реальное значение получаемое параметром - инвертировано от того что возвращается методом ?
Добрый день!
Вы немного недосмотрели.
Итак, базовая логика. Есть 2 элемента , у которых visible забайнден на getVisibleContent:
{ "operation": "insert", "name": "ProfileModuleActions", "parentName": "ProfileModuleContainer", "propertyName": "items", "values": { ... "visible": {"bindTo": "getVisibleContent"}, ... } { "operation": "insert", "name": "ProfileContentContainer", "parentName": "ProfileModuleContainer", "propertyName": "items", "values": { ... "visible": {"bindTo": "getVisibleContent"}, ... }
Обратим внимание на свойтво name элементов: ProfileModuleActions и ProfileContentContainer
Сам метод работает так как вы и описывали. Теперь если посмотреть на клиенте в HTML коде эти элементы, то увидим, что стиль dispaly: ... соответствует значению visible элементов
То что вы на скрине показали, что элементы видны, то мне кажется, что вы обратили внимание не на свойство "name", а на свойство "parentName"
Теперь что касается нескольких входов в функцию. Всегда будет 2 входа: 1 - это при создании элемента управления происходит инициализация начального значения. 2-й - это при изменении зависимого значения, в данном случае это значение аттрибута модели, который учавствует в функции (ях), на которые произведен bind
см. https://004531-sales-enterprise.bpmonline.com
Админ
Админ
пакет Custom замещающая схема ContactPageV2 - поле UsrCity
Очевидная проблема функционала.
Функция (метод) "забинженная" на свойство поля - вызывается на исполнение 6-ть и более раз,
после чего значение свойства все равно не устанавливается в соответствии с возвращаемым ею значением.
PS: Это как раз тема моего изначального обращения (меня потом начали заворачивать по SLA пришлось искать примеры в базовых кодах)
Добрый день.
На вашей демо-версии всегдя возвращается false. Если изменить код и вставить прямо "return true", то все работает. В вашей схеме вообще нет аттрибута ContactCity, поэтому false всегда. Также, после того как вы изменили код необходимо убедится, что он обновился на клиенте, а не вычитался из кэша. Данный работает корректно, т.к. по всей системе были бы ошибки
Касательно 6 раз - это нужно исследовать, и это уже отдельная история. Именно с темой "метод вызывается 6 раз" вы можете обратится в службу поддержки
Артем, демку разворачивал в "попыхах" действительно допустил опечатку в методе.
Но сути дела это не меняет, я исправил ошибку.
Метод проверяет не атрибут, а поле - его заполненность.
Вот пример 2 контакта у одного поле "Город" (UsrCity) заполнено у другого - нет.
Установим точку останова в методе CityVisibleController
Заходим в карточку контакта - поле которого заполнено:
Мало того что метод вызывается 6-ть раз, смотрим на логику, метод возвращает "true", поле "Город"
в карточке показывается - пока что кажется что все идет нормально, но давайте зайдем в карточку контакта у которого это поле не заполнено:
И ТУТ ВНИМАНИЕ !!!
Браузер Mozilla Firefox
this.get("UsrCity") почему-то возвращает не undefined а пустую строку ""
Браузер Google Chrome
В том же самом месте - возвращает UNDEFINED! (Как и ожидалось)
Какого лешего ? извините за выражение.
И даже в Google Chrome где this.get("UsrCity") возвращает undefined и моя логика срабатывает, т.е. методо возвращает FALSE
ВСЕ РАВНО ПОЛЕ UsrCity остается видимым !
Итак.
Поле из БД приходит нам в схему и ложится в аттрибут. Таким образом чтение/запись аттрибутов и полей одинаковая (this.get() / this.set())
Теперь о undefined и ''.
Мы знаем, что в БД не может хранится значение undefined, поэтому это сравнение некорректное. Оно может быть undefined только тогда, когда вы создаете новую запись, у вас создается модель, которая не содержит значений аттрибутов. Т.е., если для новой записи написать this.get('поле'), то значение будет undefined (если конечно же кто-то в фоне не установил этот аттрибут). После значения всех атррибутов, которые являются "колонками/полями" записывается в БД.
В нашем приложении для полей типа "текст" нельзя записывать в БД значения null (not null) и записывается значение по умолчанию - пустая строка. Поэтому, во время редактирования какой-то записи вам вычитается пустая строка и это значение ляжет в аттрибут. Отсюда у вас и разногласия в значениях
Хорошо, мы пробовали изменить проверку на более корректную, как нам казалось
Т.к. в примерах с сайта академии мы видели проверку поля на пустоту специальным методом this.Ext.isEmpty
т.е. буквально переписали метод следующим образом:
CityVisibleController: function() { var UserCity = this.get("UsrCity"); if (this.Ext.isEmpty("UsrCity")) { return false; } else { return true; } }
Опять же во время отладки, чтобы не содержалось в this.get("UsrCity") - undefined или "" или поле заполнено и там возвращается объект - вердикт метода всегда FALSE (т.е. на undefined и на "" тоже, это как-бы получается "не пустое" поле а какое-же оно ?)
PS: В конечном итоге добились требуемой функциональности вот так:
CityVisibleController: function() { var UserCity = this.get("UsrCity"); if (UserCity !== undefined && UserCity !== "" && UserCity !== 0) { return true; } else { return false; } }
Т.е. проверяя на все подряд, и даже на всякий случай на 0
А так же выяснили что во время 12-ти вызовом метода, в первых 6-ти - this.get("UsrCity") - undefined
А в последних 4-х уже возвращает пустую строку "" (и вот видимо во время одного из таких вызовов и происходит биндинг)
Так что вопрос ПОЧЕМУ метод вызывается 12-ть раз остается открытым.
Вот еще вопрос, юзкейс: свойство биндится на какую-то тяжелую логику включающую в себя ESQ запросы в БД - получается они будут выполнены 12-ть раз ?!
Это баг или фича ? :)
В поддержку даже нет смысла обращаться - будет отклонен по SLA как "пить дать".
Добрый день!
Певрое. Так как это JS, то вы можете использовать следующее выражание - return !!!this.get("UsrCity"),
так как !! от undefined и пустой строки вернет false.
Второе. Касательно 12 раз. Еще раз, каждый аттрибут инициализируется с каким-то значением, потом начинается цепочка зависимостей, в ходе которых происходят еще вызовы этого метода. Вы это можете увидеть в call stack'е.
Третье. Касательно тяжелого ESQ. Вы немного не разобрались. Составление ESQ - синхронная "операция", а получение данных - асинхронная. У вас просто не получится внутрь bind'а "впихнуть" асинхронность. Обычно все байнды завязываются на значения аттрибутов, их комбинаций, клиентской логики, а значение самиъх этих аттрибутов может быть установленно в callback'е любой логики