Жил-был начинающий разработчик Вася. И было у него три «пунктика»:
-
Писать по стандартам
-
Делать универсально
-
Перепроверять, что все соответствует п.1 и п.2
И в зависимости от расположения звёзд на небе, у Василия активизировались те или иные пункты. Например.
Есть на форме обработки таблица с колонками. Разработчик столкнулся с, на первый взгляд, примитивной задачей — сделать кнопку, которая будет открывать значение в текущей колонке. Пользователь становится курсором на валюту «Руб.» и нажимает кнопку. Карточка валюты «руб.» открывается. Пользователь становится на другую ячейку и нажимает на кнопку — открывается значение из этой ячейки.
И вот программист Вася, вдохновившись тем, что сможет моментально решить задачу, добавляет команду.
— А вдруг пользователь нажмёт кнопку в тот момент, когда в таблице вообще не будет строк?
И прилежный программист сразу же (как учили) в процедуре делает стандартную проверку.
ТаблицаФормы = Элементы.Валюты; Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда Возврат; КонецЕсли;
— Ну вот! Уже лучше. Начинаем эксперименты
И вот Василий берётся за определение текущей колонки. А так как наш разработчик любит сначала всё проверять, то выводит её сообщением.
ТекущаяКолонка = ТаблицаФормы.ТекущийЭлемент; Сообщить("Имя текущего поля: " + ТекущаяКолонка.Имя);
Открывает свой любимый тонкий клиент и проверяет:
— Но ведь сама колонка в таблице называется «Валюта», а не «ВалютыВалюта».
Взмахнув мышкой, Василий открывает редактор формы и видит, что на самом деле происходит.
«Валюты» — это имя таблицы, в которой хранятся данные.
«Валюта» — имя колонки этой таблицы.
А «ВалютыВалюта» — это имя поля на форме. Оно не хранит данные, а лишь выводит их. На самом деле данные хранятся в строке таблицы «Валюты» в колонке «Валюта».
Так происходит, когда имя поля было сгенерировано автоматически. Например, разработчик вынес его «вручную» на форму обработки. Имя автоматически присвоелось по формуле:
имя таблицы + имя колонки.
— И как же мне определить реальное имя колонки у текущего элемента?
Чему зачастую учат программистов в этих ваших интернетах? Прежде чем создавать свой велосипед, нужно поискать чужие. Естественно, в интернете.
Недолго думая гугля, Вася находит несколько примеров.
— А где-то я уже это видел…
Флэшбеки вспышками имен методов и переменных пролетают в сознании разработчика 1С и, погрузившись в океан жёлтых воспоминаний, он хватает за хвост имя обработки, в которой видел нечто подобное.
— Точно, я уже такое видел!
И действительно, в одной из завалявшихся в конфигурации обработок есть это:
ТаблицаФормы.ТекущиеДанные[Сред(ТаблицаФормы.ТекущийЭлемент.Имя, СтрДлина(ТаблицаФормы.Имя) + 1)]
Всё просто. Автор этого кода полагает, что имена элементов в его инструменте всегда будут строиться по приведенной ранее формуле: имя таблицы + имя колонки. И вроде бы ничего страшного, ведь так чаще всего и бывает, но:
— Я хочу универсальное решение!
Звёзды сошлись. Сегодня Василий решается на серьёзный поступок — не денег ради, но во имя высокой цели, сделать кнопку не «как можно быстрее», а «как можно круче». Естественно, степень крутости определяется им самим.
Нужно решение, которое можно будет скопировать в другой инструмент, не заботясь о том, чтобы имена элементов соответствовали какому-то там шаблону.
Порывшись в гугле синтаксис помощнике, Василий находит свойство у поля: ПутьКДанным
ПолеФормы (FormField)
ПутьКДанным (DataPath)
Использование:
Чтение и запись.
Описание:
Тип: Строка.
Содержит путь к реквизиту, с которым связан объект.
Доступность:
Сервер, мобильное приложение(сервер).
И вроде бы вот оно решение, однако:
Доступность:
Сервер, мобильное приложение(сервер).
Есть загвоздка — свойство доступно только на сервере.
Можно, конечно, написать серверную функцию, которая будет возвращать путь к данным формы:
&НаКлиенте Процедура ОткрытьЗначениеЯчейки(Команда) ТаблицаФормы = Элементы.Валюты; Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда Возврат; КонецЕсли; ТекущаяКолонка = ТаблицаФормы.ТекущийЭлемент; Сообщить("Имя текущего поля: " + ТекущаяКолонка.Имя); Сообщить("Путь к данным текущего поля: " + ПутьКДаннымЭлементаФормы(ТекущаяКолонка.Имя)); КонецПроцедуры &НаСервере Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента) ПутьКДаннымЭлемента = Неопределено; НайденныйЭлемент = Элементы.Найти(ИмяЭлемента); Если НЕ НайденныйЭлемент = Неопределено Тогда ПутьКДаннымЭлемента = НайденныйЭлемент.ПутьКДанным; КонецЕсли; Возврат ПутьКДаннымЭлемента; КонецФункции
Но…
— Так не пойдёт!
Вспомнив, что каждое излишнее обращение к серверу — это зло, за которое его ругали в Великой Школе Одинэсников Имени Желтого Чайника, разработчик Вася решает попробовать не плодить серверные вызовы. Тем более с передачей всей формы.
Программист добавляет на форму обработки реквизит произвольного типа «ПутиКДаннымЭлементовФормы»
А при создании формы заполняем эту структуру именами полей и адресами их значений, хранящихся в свойстве «ПутьКДанным»
&НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) ПутиКДаннымЭлементовФормы = Новый Структура; Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным); КонецЕсли; КонецЦикла; КонецПроцедуры
Теперь остаётся лишь сделать клиентский метод, который будет возвращать соответствующее значение свойства «ПутьКДанным»
&НаКлиенте Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента) ПутьКДаннымЭлемента = Неопределено; ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента); Возврат ПутьКДаннымЭлемента; КонецФункции
Разработчик оглядывает код и радуется проделанной работе. А заодно и проверяет насколько правильно всё работает:
&НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) ПутиКДаннымЭлементовФормы = Новый Структура; Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным); КонецЕсли; КонецЦикла; КонецПроцедуры &НаКлиенте Процедура ОткрытьЗначениеЯчейки(Команда) ТаблицаФормы = Элементы.Валюты; Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда Возврат; КонецЕсли; ТекущаяКолонка = ТаблицаФормы.ТекущийЭлемент; Сообщить("Имя текущего поля: " + ТекущаяКолонка.Имя); Сообщить("Путь к данным текущего поля: " + ПутьКДаннымЭлементаФормы(ТекущаяКолонка.Имя)); КонецПроцедуры &НаКлиенте Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента) ПутьКДаннымЭлемента = Неопределено; ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента); Возврат ПутьКДаннымЭлемента; КонецФункции
Вернувшись в тонкий клиент, Василий смотрит на результат:
Уже лучше. Теперь мы можем на клиенте узнать путь к данным формы. Для проверки, что всё на самом деле так, как планировалось, разработчик Вася переименовал элемент формы на «КолонкаСВалютой». Теперь путь к данным и имя элемента непохожи между собой, что поможет понять разницу. Вася любит всё перепроверять.
Ну вот. Всё хорошо. Но что теперь делать с этим? Нужно же определить имя колонки из полного пути к данным формы. Василий берёт самый прямой способ — расщепить полный путь на массив и взять его последний элемент:
&НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) ПутиКДаннымЭлементовФормы = Новый Структура; Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным); КонецЕсли; КонецЦикла; КонецПроцедуры &НаКлиенте Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента) ПутьКДаннымЭлемента = Неопределено; ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента); Возврат ПутьКДаннымЭлемента; КонецФункции &НаКлиенте Процедура ОткрытьЗначениеЯчейки(Команда) ТаблицаФормы = Элементы.Валюты; Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда Возврат; КонецЕсли; ИмяПоляКолонки = ТаблицаФормы.ТекущийЭлемент.Имя; //КолонкаСВалютой ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ИмяПоляКолонки); //Валюты.Валюта СоставПутиКДанным = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь); //Валюты; Валюта ИмяКолонкиТаблицы = СоставПутиКДанным[СоставПутиКДанным.ВГраница()]; //Валюта Сообщить("Имя колонки таблицы: " + ИмяКолонкиТаблицы); КонецПроцедуры
— Сейчас проверим
Осталось немного — просто взять значение из колонки и открыть его:
&НаСервере Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка) ПутиКДаннымЭлементовФормы = Новый Структура; Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным); КонецЕсли; КонецЦикла; КонецПроцедуры &НаКлиенте Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента) ПутьКДаннымЭлемента = Неопределено; ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента); Возврат ПутьКДаннымЭлемента; КонецФункции &НаКлиенте Процедура ОткрытьЗначениеЯчейки(Команда) ТаблицаФормы = Элементы.Валюты; Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда Возврат; КонецЕсли; ИмяПоляКолонки = ТаблицаФормы.ТекущийЭлемент.Имя; ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ИмяПоляКолонки); СоставПутиКДанным = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь); ИмяКолонкиТаблицы = СоставПутиКДанным[СоставПутиКДанным.ВГраница()]; ЗначениеЯчейки = Неопределено; ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТаблицы, ЗначениеЯчейки); ПоказатьЗначение(Новый ОписаниеОповещения, ЗначениеЯчейки); КонецПроцедуры
Замечательно! Инструмент заработал. И теперь уже значение будет открываться независимо от того, как называется наш элемент формы.
Василий уже прикинул в голове способы применения этого кода. Например, у нас есть табличная часть документа, которую нельзя редактировать. Наш разработчик ставит на таблицу ТолькоПросмотр, а так же подвязывает событие «Выбор», в котором открывает текущее значение.
И как только наш начинающий программист подумал об этом, в голову пришла мысль.
— Недостаточно удобно!
Да, этого мало. Василий хочет сделать ещё круче! Он решает переспать с этой мыслью, чтобы уже позже продолжить свой путь от простой задачи к универсальному механизму…
Понравилась статья?
Дамы и господа 1Сники. Не будьте равнодушными. Каждая ваша "звёздочка" порадует и автора и программиста Васю. Ведь это показатель того, что кому-то текст зашёл, а значит и время было потрачено не зря.
Ну а после переходите к другим работам.
"Меньше копипаста!", или как Вася универсальную процедуру писал
Сортируем ДанныеФормыДерево на клиенте
Не провоцируйте СКД, или пример "как не надо"
классно написано!)Жду дальше историй про Васю!)
Нам плюсиков не жалко, они бесплатные :)) Так что пиши ещё :))
Написано классно, стиль повествования понравился… Но , никогда так не буду делать, потому что структура колонок в реквизите формы — это уже костыль.
1. при открытии значения все равно будет обращение к серверу, если это конечно не примитивный тип данных. Так почему просто не обращаться на сервере к ПутьКДанным. Другой вопрос действительно не хочется тянуть на сервер всю форму, но для этого можно поискать обходные пути.
2. универсальность может и появилась. Но не очень… а что будет если программист Петя, у которого нету времени вникать в суть процедур Васи захочет программно добавить колонки, не задумываясь что за переменная ПутиКДаннымЭлементовФормы? Он будет думать над своей логикой, и только потом обнаружит что эта «кнопка» уже не совсем работает…
А можете мне рассказать суть статьи? Это подход к решению задачи, или описание маленькой задачи?
Извините за критику, надеюсь она будет конструктивной.
1 Если первое: То как то не расскрыто. Не вижу разбора паттерна , да и самого паттерна подхода к решению задачи.
2 Если про саму задачу: решение — так себе… Вроде и работает. Но… писал уже выше.
Пока — статья для статьи.. Что тоже имеет место быть.
(0) как-то все сложно…
(0) вот видео
(5) Ну и ? Добавлю колонку со своим именем… Как данные потом найдешь? В статье это как раз и написано. Вот лишь бы написать не почитавши.
(6) еще и с видео заморочились )))… Там в обработке две строчки. можно же было просто сюда код написать!
(5) ну так стоит изменить имя элемента и всё сломается. В этом и вся суть
(8) :)))))))))))))))) да уж… вы правы
(9) имя какого элемента вы хотите поменять?
(3) 1. обращение минимальное. Это не тоже самое, что в добавок ещё и форму всю перекидывать ради одной строчки
2. ага, выглядит как костылик. Но я вот помню сталкивался с подобной ситуацией… И что-то подобное только и получилось сделать. Как-то вариантов других не нашли (
(11) любого. Если элемент будет называться как угодно, не соответствуя шаблону «Список» + ИмяКолонки, то всё сломается.
(13) Название табличной части «Список» можно выделить в переменную
&НаКлиенте
Процедура СообщитьИмяЭлемента(Команда)
ИмяТЧ = «Список»;
ТекЭлемент = ЭтаФорма.Элементы[ИмяТЧ ].ТекущийЭлемент;
Сообщить(СтрЗаменить(ТекЭлемент.Имя, «ИмяТЧ «, «»));
КонецПроцедуры
(13) Имя табличной части сможете сами вытащить ? и в переменную передавать и далее в процедуру.
(14) с таким подходом лучше уж как в статье:
ТаблицаФормы.ТекущиеДанные[Сред(ТаблицаФормы.ТекущийЭлемент.Имя, СтрДлина(ТаблицаФормы.Имя) + 1)]
но это не меняет сути, что имена элементов должны быть строго стандартизированы.
(14) а если элемент будет называться не «СписокВалюта», а «ВалютаУчета» ?
Или нужно вынести два элемента, привязанного к одной колонке.
ваш подход работает только с самыми примитивными ситуациями. А тут описывается «универсальное мега супер решение»
По мне так все таки нормальный вариант Получать ПутьКданным на сервере, и там получать сразу данные… Если не нравится идея передавать всю форму на сервер, используйте НаСервереБезконтекста, куда в параметрах передавать ТаблицуФормы и Данныеформыколлекция
(18) нельзя сделать при помощи &НаСервереБезконтекста
Если у Вас выйдет, поделитесь, пожалуйста — это заметно упростит код.
(19) Да , прошу прощения, Элементы формы не передаются в параметрах на сервер…
Но тут пришла и другая мысль… А зачем боятся вызова этого сервера в контексте этой задачи? Ведь важно что бы не было частых вызовов, а тут тоолько один , по нажатию кнопки… А если предполагается частый контекстный вызов, то наверное нужно использовать другие события ТаблицыФормы
(16)
(17) я не вижу супер-решения.
Коллеги, все равно считаю , что данный метод получения значения ячейки таблицы формы или же имени колонки таблицы — костыльный… Не рекомендуйте особенно новичкам так делать! Пользуйтесь по стандарту — на стороне сервера получаете путькданным. Просто , понятно, читабельно , легко! Ваш код всегда будут читать другие, зачем усложнять сложное.
Конечно , все в зависимости от поставленной задачи.
(20) Если говорить об универсальности, хотелось бы найти такое решение, которое подошло бы, например, для этой задачи:Открывашка ячеек таблиц . То есть всё должно быть на клиенте. Менять код формы мы не можем, всё что у нас есть — это текущий элемент и
ДанныеФормыСтруктураДанныеФормыЭлементКоллекции (ТекущиеДанные).Автор! Вы забыли указать, что Василий это кот 🙂
Не совсем понял задачу. ТекущаяСтрока и НайтиПоИдентификатору() в обработке выбора без использования элементов формы религией запрещены?
(12) Все таки интересно, пример или хотя бы суть такой ситуации, в которой без костылика не обойдешься?
Могу только предоположить , когда данные на форме объемные, и любая отправка формы на сервер вызывает задержку?
Вот не лень же людям ерундой заниматься — текущие проблемы, которые по ходу дела решаются, расписывать в виде статей про всяких вась…
А вообще, с возрастом и опытом приходит понимание тонкой грани между решением «по месту», кастомизацией, продиктованной сроками, стоимостью, сложностью, перспективами развития и эксплуатации системы, и универсализацией. И вместо сферических универсалов в вакууме гораздо чаще востребованы и удобны оказываются узкоспециализированные решения. Не говоря уже о том, что универсализация на уровне разработчика частенько «выпихивает» проблему настоящей собственно автоматизации процесса на следующий уровень — уровень админа, продвинутого юзера — того, кто настраивает этот супер-пупер-универсал и рулит им. Универсалам нужна подробная справка, и всё равно не читают; универсалов тупо опасаются; универсалы редко «угадывают» настоящие направления работы и оказываются бесполезны…
(26) А причем тут обработка выбора.. Автор хочет по кнопке получить текущую колонку и текущую строку, а потом по этим данным найти и открыть значение.
(30)Ну ок, по кнопке, не по обработке выбора. Разницы нет. В любом случае правильнее работать не с элементами формы а с реквизитом типа ДанныеФормыКоллекция.
(29)
Я же правильно Вас понял, что учитывая тонкую грань бесполезны бывают лишь в некоторых случаях, а не всегда.
Ведь много идёт по пути универсальности. Например, платформа 1С. Уже есть готовые объекты и действительно надо знать как ими пользоваться. И всякие универсальные вещи ускоряют работу. Например, автомобильные детали используются в различных брендах и надо знать их качество, надежность, крепления, параметры.
(32) Разумеется. Нигде нет смысла бросаться в крайности и возводить в абсолюты. Программирование или нет, тут не суть.
Что за критика ? Универсальное ради универсального. Просто читать — бальзам на душу. Разобран конкретный пример, все с этим столкнутся. Васе зачёт и молочка.
Для чего вообще делать кнопку и все это? Я правильно понимаю, что задача программиста в данном случае открывать значение из ячейки в таблице? Но из-за того, что установлено свойство «ТолькоПросмотр» = Истина в самой ячейке таблицы не работает кнопка «Открыть»? А почему нельзя убрать «ТолькоПросмотр», тогда естесственное открытие ведь станет работать. Потому что тогда пользователь сможет менять значение в колонке, а это плохо? На мой взгляд решение есть проще.
Имеем:
0. Таблица значений на форме, нужно открывать любое значение из колнки стандартной «лупой», но не иметь возможности менять элемент.
1. У всех ссылочных полей таблицы ставим свойство «Редактирование текста» = Ложь.
2. У тех же полей создаем событие «Начало выбора», в котором ставим «СтандартнаяОбработка» = Ложь.
3. У тех же полей создаем событие «Очистка, в котором ставим «СтандартнаяОбработка» = Ложь.
4. «Только просмотр» не ставим.
Все. Теперь любое ссылочное значение из таблицы можно открыть без доп. кнопок и кучи кода, простой кнопкой «открыть» из ячейки. А также поменять или очистить значение тоже никак не получится.