Всем доброго времени суток. Почему при переносе JavaScript модуля из версии BPMonline 7.2 в 7.6 интерпретатор трактует оператор равенства "==" как ошибку и просит заменить его на оператор идентичности "===" во всех местах, где только встречается оператор "==" ? Из-за чего это ? И может ли эта замена повлиять на логику модуля ?
Подобная замена на логику повлиять не должна, если логика реализована верно. Дело в том, что при использовании оператора равенства JavaScript выполняет автоматическое преобразование типов, что потенциально может привести к ошибке (например, 0 == "0" или true == "1", но это не одни и те же значения). Для того, чтобы избежать потенциальных ошибок в логике, желательно использовать более строгий оператор идентичности.
В BPMonline 7.6 я создал страницу, унаследованную от "Схема отображения карточки контакта ( UIv2 )" и поместил в неё поле Name - ФИО из объекта Contact (Base) и кнопку. Ниже привожу код модуля этой страницы на Java Script. Он небольшой. Я занимаюсь Java Script всего-навсего с понедельника. Пожалуйста, посмотрите - всё ли я написал в своём коде правильно?
OnClientSearchButtonClick:function(){ this.showInformationDialog("Вызов метода OnClientSearchButtonClick модуля RIBClientSearchModule."); } },
details:/**SCHEMA_DETAILS*/{}/**SCHEMA_DETAILS*/, // Настройка визуализации кнопки на нашей странице.
diff:[{ // Метаданные для добавления поля [ФИО]: // Указать на то, что выполняется операция добавления элемента на страницу. "operation":"insert", "parentName":"Header", "propertyName":"items", // Имя добавляемого полоя. "name":"Name", // Дополнительные свойства поля: "values":{ // Настройка расположения поля на странице. "layout":{"column":0,"row":5,"colSpan":15} } }, { // Метаданные для добавления кнопки [Найти клиента для консультации]: // Указать на то, что выполняется операция добавления элемента на страницу. "operation":"insert", // Указать имя системного контейнера на странице, в который будет добавлена кнопка. "parentName":"LeftContainer", // Указать, что кнопка добавляется в коллекцию элементов управления в контейнере, // имя которого указано в parentName. "propertyName":"items", // Мета-имя добавляемой кнопки. "name":"SearchContactButton", // Дополнительные свойства кнопки: "values":{ // Тип добавляемого элемента - кнопка.
itemType: Terrasoft.ViewItemType.BUTTON, // Привязка заголовка кнопки к локализуемой строке схемы.
caption:{ bindTo:"Resources.Strings.ClientSearchButtonCaption"}, // Привязка метода-обработчика нажатия кнопки.
click:{ bindTo:"OnClientSearchButtonClick"}, // Настройка расположения кнопки на странице. "layout":{"column":5,"row":10,"colSpan":1} } } ] }; });
По крайней мере компилируется без ошибок.
Заранее благодарен
P.S. Я не задал entitySchemaName потому что не знаю какое значение нужно, в моём случае, для его задавать.
Евгений, если Вы унаследовались от карточки контакт, то логично указывать в entityschemaname "Контакт". Или как вариант указывать объект, который унаследует контакт.
Если Вы не уверены в работоспособности кода, то можно осуществлять отладку. Информация есть на SDK (http://academy.terrasoft.ru/documents/?product=SDK&ver=7.6.0).
Здравствуйте. В SDK есть статья "Пример реализации добавления кнопки на страницу редактирования". В ней описывается добавление кнопки на замещающую страницу. А можно точно таким же образом добавить кнопку на страницу, которая просто наследуется? Например, на страницу, которую я просто наследую от страницы "Схема отображения карточки контакта"? Ответьте, пожалуйста.
Спасибо. А скажите ещё, пожалуйста, следующее. Правила добавления поля на страницу тоже идентичны добавлению кнопки? Т.е. я имею ввиду, что можно добавить как поле замещающего объекта на замещающую страницу, так и поле какого либо базового объекта (например справочника Contact) на унаследованную страницу? Ответьте, пожалуйста.
Евгений:
1) Вы не сможете добавить поле, если оно добавлено в одном из подчиненных пакетов, а в Вашем пакете его нет.
2) Поле добавляется из последнего доступного в иерархии пакета.
3) Объект - это таблица в БД. Она одна. Если Вы заместили объект "Контакт", добавив несколько полей, то это всего лишь добавление новых колонок в таблицу dbo.contact, а не создание новой таблицы.
Правила добавления одинаковые, что для замещающих, что для унаследованных, что для новых страниц.
Скажите, пожалуйста, что пишется в секции mixins в файле исходного текста на Java Script страницы, если для создания страницы в конфигурации выбирается: Добавить/Расширенные/Схема модели представления карточки ?
Каких-то обязательных требований к содержимому блока mixins нет. В этот блок необходимо подключать классы, которые содержат некий общий функционал, если Вам необходимо использовать этот функционал в своём модуле. При этом метод миксина вызывается в контексте модуля, из которого он был вызван. Если Вам дополнительный функционал не нужен, можно вообще не заполнять или убрать этот блок.
Примером миксина может служить класс Terrasoft.GridUtilities, который используется и в базовом разделе, и в базовой детали.
В версиях BPMonline 7.2 и 7.5 есть библиотечный модуль на Java Script, который называется jQuery. Не может ли кто сказать - изменилось ли определение этого модуля в версии BPMonline 7.5 относительно версии 7.2 ? Дело в том что я взял готовый модуль на Java Script (в зависимостях которого был объявлен только jQuery) в версии 7.2 и перенёс его в приложение, которое делаю в версии 7.5. При сохранении перенесённого модуля в 7.5. появляется сообщение: "Похоже, исполняемый на этой странице сценарий занят или не отвечает. Вы можете остановить его сейчас, открыть сценарий в отладчике или позволить сценарию продолжить свою работу." В окне ошибок первым появляется следующее сообщение "Function declarations should not be placed in blocks. Use the function expression or move the statement to the top of the other function." Ниже привожу код на который "жалуется" система:
Система жалуется на объявление функции внутри оператора if ($.fn.inputmask === undefined) . Что здесь сделано неправильно? Из-за чего возникает данная ошибка. Ведь этот код работал в BPMonline 7.2, а в 7.5 не хочет!
P.S. В окне структуры указал в депенденсах jQuery. В свойствах всё прописал как положено (посмотрел как это было сделано в 7.2).
С версии 7.2 до версии 7.5 изменилась структура создания замещающего клиентского модуля. Вы можете посмотреть на новую схему в любой странице редактирования в 7.5. Например, можете посмотреть код ActivityPageV2.
В двух словах, базовый код замещающей клиентской схемы пишется так:
image2014-9-29_13-9-31.png (прикреплен)
image2014-9-29_13-11-1.png (прикреплен)
Методы пишутся в объекте methods, который собирается по иерархии.
Я вообще зелёный новичок в Java Script. Получается, что в версии 7.5 определять функцию внутри блока оператора if(){} нельзя? Скажите мне русским языком. По крайней мере, в ActivityPageV2 нет определения функций внутри блоков оператора if(){}. И вообще, ActivityPageV2 создана как простой модуль или как схема модели представления карточки ? Потому что свой модуль я создавал как простой модуль, т.е. зашёл на вкладку "Конфигурация", там выбрал нужный мне пакет и выполнил Добавить/Расширенные/Модуль. Покажите, пожалуйста, как мне нужно переписать код в моём случае, что бы он работал?
Доброго времени суток! Хочу стать кандидатом на вакансию JavaScript Developer в вашей компании.
Не могли бы привести пару примеров тестовых заданий, которые выдаются на собеседовании, если есть такая возможность?
Заранее благодарен!
Очень рады Вашей заинтересованности в позиции JavaScript Developer.
Конкурс на вакансию проходит в несколько этапов, где оцениваются Ваши базовые и професиональные компетенции. Мы ожидаем, что наш кандидат сможет:
1. Реализовать интеграцию системы bpm'online через встроенные в платформу сервисы.
2. Реализовать шаблон MVVM для JavaScript без использования готовых библиотек.
3. Выполнить задачи на анализ иерархических данных используя один из языков C#/JavaScript/SQL.
4. Также, Вам могут предложить решить задания на проверку навыков функциональной декомпозиции сложных задач.
Буду рада обсудить все детали вакансии. Мой Skype: galyna_kuleshova
В статье Асинхронные запросы в bpm’online 5.X был приведен пример отправки Get/Post запросов со страницы с использование языка JavaScript. В этой статье хотелось бы рассказать про подводные камни, которые встретились при реализации и как их можно обойти.
Предположим, имеется некий абонент интернет провайдера, у которого есть такие поля, как баланс, MAC-адрес, IP-адрес, состояние, список последних сессий абонента, получение доступных для смены тарифов, получение текущего тарифа абонента. При открытии карточки необходимо получать обновленную информацию от WCF сервиса, отображать её на странице и сохранять в базе данных.
При наличии сложной логики на странице, а именно:
применение нескольких асинхронных запросов;
обновление значений в контроллах на странице;
обновление значений столбцов в DataSource.ActiveRow;
обновление записей в базе с помощью класса Update (для того, чтобы при получении обновленной информации от сервиса, например, баланса, сразу записывать его значение в базу, и при последующем открытии карточки, даже если пользователь закрыл страницу не сохранив запись нажав "Отмена", пользователь увидит последние обновленные сведения, полученные от биллинговой системы, до того момента, пока от сервиса не придет новая, обновленная информация о балансе, в противном случае, при отсутствии доступа к данному сервису (пропало интернет соединение), будет отображаться последняя загруженная информация о балансе).
Столь сложная логика на странице может стать причиной ошибок на странице, как, например, ошибка "Сбой при загрузке состояния отображения. Дерево элементов управления, в которое загружается это состояние отображения, должно соответствовать дереву элементов управления, использованному для сохранения состояния отображения при предыдущем запросе. Например, при динамическом добавлении элементов управления те элементы управления, которые были добавлены при обратной передаче, должны по типу и положению соответствовать элементам управления, добавленным при исходном запросе." (скриншот окна с ошибкой ниже).
Данная ошибка возникает при переходе на деталь "Активности", и другие детали, в которые загружается информация, связанная с данной записью. Причем ошибка возникает только во время выполнения асинхронных запросов к сервису, если быть точнее, при получении информации от сервиса, выполняется серверная логика, во время которой и возникает ошибка.
Чтобы избежать данной ошибки, необходимо запретить пользователю переходить на детали, которые вызывают ошибку. Сделать это можно следующим образом.
В БП страницы на событие PageLoadComplete необходимо добавить элемент "Задание сценарий", который добавляет на страницу следующий JavaScript код (данный скрипт должен выполняться перед добавлением скрипта создания самого запроса, т.е. объекта XMLHttpRequest, как было описано в статье):
// Функция, позволяющая скрыть/отобразить все детали, следующие за деталью // "Активности", включая саму эту деталь function changeVisibleOfTabs(isVisible){ for(var i =0; i PageContainer_DataTabPanel.items.items.length; i++){ if(PageContainer_DataTabPanel.items.items[i].caption=='Активности'){ for(var j = i; j PageContainer_DataTabPanel.items.items.length; j++){
PageContainer_DataTabPanel.items.items[j].tabHeader.setVisible(isVisible); } break; } } }
// скрываем детали перед выполнением запросов
changeVisibleOfTabs(false);
// создаем таймер, который каждые 500мс проверяет, завершились ли все запросы, // после того, как все запросы завершены, создаем таймер на 2000мс, // чтобы отработала вся логика на странице, после чего отображаем скрытые детали var timerCheckIsDone = setInterval(function(){ if((requestUpdateBalance != undefined && requestUpdateBalance !=null&& requestUpdateBalance.readyState==4)&& (requestUpdateMacAndSerialNumber != undefined && requestUpdateMacAndSerialNumber !=null&& requestUpdateMacAndSerialNumber.readyState==4)&& (requestUpdateAbonentState != undefined && requestUpdateAbonentState !=null&& requestUpdateAbonentState.readyState==4)&& (requestGetSessionDetalisation != undefined && requestGetSessionDetalisation !=null&& requestGetSessionDetalisation.readyState==4)&& (requestGetAvaliableTariffs != undefined && requestGetAvaliableTariffs !=null&& requestGetAvaliableTariffs.readyState==4)&& (requestGetCurrentTariff != undefined && requestGetCurrentTariff !=null&& requestGetCurrentTariff.readyState==4)){
clearInterval(timerCheckIsDone); var timerChangeVisibleOfTabs = setTimeout(function(){
changeVisibleOfTabs(true);// отображаем детали },2000); } },500);
Важно! После выполнения данного скрипта, необходимо создать объекты запросов, как было показано в статье. Причем объекты запросов должны ссылаться на глобальные переменные, которые мы объявляли в самом начале, т.е. необходимо писать вместо
var request = new XMLHttpRequest();
вот так:
requestUpdateBalance = new XMLHttpRequest();
Иначе доступ к данным переменным будет невозможен из функции, где выполняется проверка завершения запросов.
Есть ситуации, когда нужно, чтобы при открытии карточки редактирования, в поля карточки подгружалась информация, которую нужно выводить в актуальном (обновленном) состоянии. К примеру, когда клиент звонит в тех поддержку, сотрудник техподдержки открывает карточку клиента в bpm'online и должен видеть текущий баланс данного клиента. Предположим, есть WCF сервис, работающий на некотором хостинге, созданный для интеграции с биллинговой системой, с методом получения баланса абонента GetBalance, ответ от которого приходит в виде строки в формате JSON, который мы можем обработать и вывести в нужном формате на страницу редактирования.
Если выполнять запрос из бизнес процесса карточки редактирования (на PageLoadComplete, к примеру), то при выполнении запроса возникает зависание карточки редактирования, и она не отвиснет пока либо не придет ответ, либо пока запрос не будет завершен по таймауту (если сервер долго не отвечает).
Чтобы выполнить запрос асинхронно, нужно добавить на страницу редактирования JavaScript код, который будет обращаться к сервису, получать ответ от него и выводить результат в контролы страницы. Чтобы отправлять запрос сразу после загрузки страницы, нужно добавить элемент бизнес процесса «Задание-сценарий» на событие «PageLoadComplete», либо если нужно отправлять запрос по нажатию на кнопку, то на событие нажатия на неё.
При выполнении данного кода Java Script кода на странице, мы получим ошибку в консоли браузера:
XMLHttpRequest cannot load http://someserveradress/SomeWCFService.svc/GetBalance. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8080' is therefore not allowed access.
Ошибка говорит о том, что запрещено обращаться к другому домену (попытка выполнить кросс-доменный запрос). Данное ограничение введено из соображений безопасности, но его можно обойти используя технологию CORS.
Подробную информацию об этой технологии можно посмотреть тут:
1) https://ru.wikipedia.org/wiki/Cross-origin_resource_sharing
2) http://enable-cors.org/
3) http://habrahabr.ru/post/120917/
Для того, чтобы разрешить кросс-доменные запросу, нужно включить поддержку на сервере, к которому приходит запрос, в моём случае это WCF служба. Для включения поддержки CORS у WCF сервиса, нужно выполнить действия, описанные тут: http://enable-cors.org/server_wcf.html.
Информацию по включению поддержки CORS для других платформ/серверов можно найти тут: http://enable-cors.org/server.html.
После этого, запрос должен выполняться асинхронно, не вызывая зависание карточки, благодаря чему можно просматривать/редактировать карточку в момент выполнения запроса.
Добрый день! Хочу поделиться опытом работы с JS в проектах на bpm’online 5. Статья будет полезна тем, кто не знает с какой стороны подойти к этому вопросу и с чего начать. Умение работать с JS применительно к bpm’online открывает богатые возможности настройки функциональности. В статье будет рассмотрено:
как добавлять js-скрипты на страницы bpm’online
как подписываться на события "onclick", "onkeydown" и пр.
как генерировать сигналы для страницы
показан пример использования jQuery
использование js-библиотек
Основы
Добавление JS скрипта на страницу выполняется с помощью метода:
Page.AddScript(string script)
Добавим на «страницу карточки задачи» кнопку и напишем код обработки:
Page.AddScript("alert('Hello!')");
В результате нажатия на кнопку произойдёт следующее:
Чтобы упростить себе жизнь и не мучиться с экранированием символов, текст JS-скрипта в исходном виде можно записать в параметр бизнес-процесса.
А затем добавить скрипт, передавая в качестве текста скрипта параметр JS_FirstScript:
Page.AddScript(JS_FirstScript);
Немного модифицируем этот способ: в параметр JS_FirstScript запишем:
alert('%message%');
Добавим в Usings пространство имен System.Text.RegularExpressions
В коде пишем:
После нажатия на нашу красную кнопку, на страницу добавятся обработчики нажатия кнопок «Стрелка влево» и «Стрелка вправо». Нажимая на стрелки, получаем:
Само собой, если добавить этот скрипт в "Init", то обработчики появятся уже после открытия страницы.
Пример №2
Добавим обработку клика по изображению. Дизайнер bpm'online не позволяет добавить обработчик события «click» на элемент «Область изображения», но мы можем сделать это с помощью JS. Добавим картинку на страницу:
Мы будем искать html-элемент этой картинки по id, поэтому посмотрим на него:
Для того, чтобы не изобретать велосипеды, у нас есть возможность использовать JQuery в своем коде. Причём, JQuery уже добавлен в ресурсы страницы. На момент написания статьи, обычно это jQuery v1.7.1
Приведу пример анимации с помощью jQuery.
Добавим в процесс параметр «scriptAnimation». Пишем его значение:
В результате, при нажатии на изображение, оно будет сдвигаться влево на 100 пикселей и постепенно исчезать. После чего начнётся обратная анимация.
Изменив id элемента в параметре «scriptAnimation», можно подвигать, например, поле ввода автора активности:
Добавление библиотек JS на страницу
Что делать, если нам нужно подключить какой-то js-код, который просто неприлично в нормальном обществе засовывать в параметр процесса? Рассмотрим на примере добавления маски ввода к текстовому полю.
Добавим на страницу текстовое поле, назовём его MaskedTextEdit
Все круто, только не понял, почему для обращения к TextEdit'у с клиента Вы используете свойтсво "ClientID", а для картинки смотрите ее Id в HTML-коде.
Думаю, что оптимальнее везде использовать ClientID.
Добрый день, Андрей!
На то это и примеры, чтобы показать все способы получения идентификатора. Например, понадобилось вдруг нам подвигать какое-нибудь поле, то тут ClientID нам не поможет:
Получив ClientID = PageContainer_HouseCategoryEdit мы будем двигать только текст контрола, в то время как "прямоугольник" контрола будет стоять на месте. Чтобы двигать прямоугольник, нам нужно посмотреть его Id в html:
т.е. нам нужен id div'а, а именно "ext-gen1052", или вообще "ext-gen1070", чтобы подвигать поле вместе с меткой.
Евгений, в таком случае это будет довольно небезопасно, так как после внесения изменений в дизайн страницы автогенерируемый Id уже может быть не тот_) Думаю, если нужно двигать весь контрол, то его можно поместить в контейнер и двигать контейнер. Хотя, я не пробовал, могу ошибаться.
Столкнулся с проблемой: добавил исходный код "MyTools", язык указал JavaScript. В коде написал функцию "MyFunction". В процессе, где нужно выполнение моей функции, пишу
Page.AddScript(script);
Что поместить в переменную script, чтобы вызвать MyFunction?
На сколько я понял, в переменной myStringJavaScriptFunction тело самой javascript-функции, а это не совсем то. Как раз таки, чтобы не плодить одни и те же функции по всей конфигурации, я создал в конфигурации исходный код, и хочу обращаться к нему примерно таким образом
тоже не подошел, так как у объекта Terrasoft нет объекта Common или Configuration. Это можно увидеть в консоли.
Возможно, нужно его как-то регистрировать?
где script - строка с методом JS, добавляет данный JS код на страницу в клиенте.
Соответственно, если вы добавите таким же образом JS код вызова какого либо метода, то он запустится.
По поводу консоли - cs файлы (классы и методы) они на сервере, в консоли браузера (клиентский код) Вы их и не увидите.
Обращаться можно через Terrasoft.Configuration.MySourceScheme.
добавил исходный код "MyTools", язык указал JavaScript. В коде написал функцию "MyFunction".
. После я указал, что способ
"Олейник Дмитрий" написал:
Page.AddScript(script);
где script - строка с методом JS, добавляет данный JS код на страницу в клиенте.
мне не подходит, так как мне придется везде, где нужен вызов моей функции, тупо делать копи-паст тела самой функции. Чтобы избавиться от перегрузки кода, я вынес ее (функцию) в отдельную схему, у которой указал язык JavaScript, а не C#.
То что классы и методы *.cs файлов в консоли я не увижу, это понятно. Задача и состоит, в том, чтобы перенести JavaScript код из моей схемы в клиентский код, так как функции, которые он исполняет, должны работать на клиентской стороне, а не на стороне сервера. Потому я приводил пример с
Page - это текущая клиентская страница (т.е. процесс страниц системы).
Элемент "Скрипт" выполняется на сервере, там никакой клиентской логики нет... По идее, Вам необходимо создавать страницу (или использовать текущие) и уже в контексте их выполнять какой то клиентский код.
А можно уточнить Вашу задачу?
Дмитрий, задачу я описывал в обращении 0160719. Нужно автоматически сгенерировать документ после создания документа в рамках БП. То есть сначала элемент "Страница редактирования", потом "Задание-сценарий", вызывающий метод ReportUtilities.generateReport() для генерации документа, затем открытие карточки e-mail для отправки этого документа.
Дмитрий, то есть есть нужно ещё и создать класс ReportUtilities?
Дело в том, что я думал, что он стандартный, мне нужно было сгенерировать печатную форму после сохранения записи...
Нет, смотрите, если в конфигурации в какой либо Source код схеме уже есть нужная Вам функция - разумеется, дублировать её не нужно.
Просто вызывайте её:
Посмотрел код схемы WordReportUtilities, которая генерит отчеты. Все просто - необходимо создать объект этого класса, воспользовавшись конструктором, затем вызвать метод GenerateReport с двумя параметрами - айди шаблона, и айди записи, для которой нужно построить отчет.