Пост

Хочу универсально! Часть 1

Начинающий разработчик проходит путь от простой задачки к созданию своего механизма


Жил-был начинающий разработчик Вася. И было у него три «пунктика»:

  • Писать по стандартам
  • Делать универсально
  • Перепроверять, что все соответствует п.1 и п.2

И в зависимости от расположения звёзд на небе, у Василия активизировались те или иные пункты. Например.

Есть на форме обработки таблица с колонками. Разработчик столкнулся с, на первый взгляд, примитивной задачей — сделать кнопку, которая будет открывать значение в текущей колонке. Пользователь становится курсором на валюту «Руб.» и нажимает кнопку. Карточка валюты «руб.» открывается. Пользователь становится на другую ячейку и нажимает на кнопку — открывается значение из этой ячейки.

И вот программист Вася, вдохновившись тем, что сможет моментально решить задачу, добавляет команду.

- А вдруг пользователь нажмёт кнопку в тот момент, когда в таблице вообще не будет строк?

И прилежный программист сразу же (как учили) в процедуре делает стандартную проверку.

1
2
3
4
5
ТаблицаФормы = Элементы.Валюты;

Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
    Возврат;
КонецЕсли;

- Ну вот! Уже лучше. Начинаем эксперименты

И вот Василий берётся за определение текущей колонки. А так как наш разработчик любит сначала всё проверять, то выводит её сообщением.

1
2
ТекущаяКолонка = ТаблицаФормы.ТекущийЭлемент;
Сообщить("Имя текущего поля: " + ТекущаяКолонка.Имя);

Открывает свой любимый тонкий клиент и проверяет: Обработка

- Но ведь сама колонка в таблице называется «Валюта», а не «ВалютыВалюта».

Взмахнув мышкой, Василий открывает редактор формы и видит, что на самом деле происходит.

«Валюты» - это имя таблицы, в которой хранятся данные. «Валюта» - имя колонки этой таблицы. А «ВалютыВалюта» - это имя поля на форме. Оно не хранит данные, а лишь выводит их. На самом деле данные хранятся в строке таблицы «Валюты» в колонке «Валюта».

Обработка

Так происходит, когда имя поля было сгенерировано автоматически. Например, разработчик вынес его «вручную» на форму обработки. Имя автоматически присвоелось по формуле:

имя таблицы + имя колонки

- И как же мне определить реальное имя колонки у текущего элемента?

Чему зачастую учат программистов в этих ваших интернетах? Прежде чем создавать свой велосипед, нужно поискать чужие. Естественно, в интернете.

Недолго думая гугля, Вася находит несколько примеров.

- А где-то я уже это видел…

Флэшбеки вспышками имен методов и переменных пролетают в сознании разработчика 1С и, погрузившись в океан жёлтых воспоминаний, он хватает за хвост имя обработки, в которой видел нечто подобное.

- Точно, я уже такое видел!

И действительно, в одной из завалявшихся в конфигурации обработок есть это:

1
ТаблицаФормы.ТекущиеДанные[Сред(ТаблицаФормы.ТекущийЭлемент.Имя, СтрДлина(ТаблицаФормы.Имя) + 1)] 

Всё просто. Автор этого кода полагает, что имена элементов в его инструменте всегда будут строиться по приведенной ранее формуле: имя таблицы + имя колонки. И вроде бы ничего страшного, ведь так чаще всего и бывает, но:

- Я хочу универсальное решение!

Звёзды сошлись. Сегодня Василий решается на серьёзный поступок — не денег ради, но во имя высокой цели, сделать кнопку не «как можно быстрее», а «как можно круче». Естественно, степень крутости определяется им самим.

Нужно решение, которое можно будет скопировать в другой инструмент, не заботясь о том, чтобы имена элементов соответствовали какому-то там шаблону.

Порывшись в гугле синтаксис помощнике, Василий находит свойство у поля: ПутьКДанным

ПолеФормы (FormField) ПутьКДанным (DataPath) Использование: Чтение и запись. Описание: Тип: Строка. Содержит путь к реквизиту, с которым связан объект. Доступность: Сервер, мобильное приложение(сервер).

И вроде бы вот оно решение, однако есть загвоздка — свойство доступно только на сервере.

Можно, конечно, написать серверную функцию, которая будет возвращать путь к данным формы:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
&НаКлиенте
Процедура ОткрытьЗначениеЯчейки(Команда)
	
	ТаблицаФормы = Элементы.Валюты;
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ТекущаяКолонка = ТаблицаФормы.ТекущийЭлемент;
	Сообщить("Имя текущего поля: " + ТекущаяКолонка.Имя);
	Сообщить("Путь к данным текущего поля: " + ПутьКДаннымЭлементаФормы(ТекущаяКолонка.Имя));
	
КонецПроцедуры


&НаСервере
Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента)
	
	ПутьКДаннымЭлемента = Неопределено;
	НайденныйЭлемент    = Элементы.Найти(ИмяЭлемента);
	Если НЕ НайденныйЭлемент = Неопределено Тогда
		ПутьКДаннымЭлемента = НайденныйЭлемент.ПутьКДанным;
	КонецЕсли;
	
	Возврат ПутьКДаннымЭлемента;
	
КонецФункции

Но…

Но…

Вспомнив, что каждое излишнее обращение к серверу — это зло, за которое его ругали в Великой Школе Одинэсников Имени Желтого Чайника, разработчик Вася решает попробовать не плодить серверные вызовы. Тем более с передачей всей формы.

Программист добавляет на форму обработки реквизит произвольного типа «ПутиКДаннымЭлементовФормы»

Обработка

А при создании формы заполняем эту структуру именами полей и адресами их значений, хранящихся в свойстве «ПутьКДанным»

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ПутиКДаннымЭлементовФормы = Новый Структура;
	
	Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл
		
		Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") 
			ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда
			
			ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным);
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

Теперь остаётся лишь сделать клиентский метод, который будет возвращать соответствующее значение свойства «ПутьКДанным»

1
2
3
4
5
6
7
8
&НаКлиенте
Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента)
	
	ПутьКДаннымЭлемента = Неопределено;
	ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента);
	Возврат ПутьКДаннымЭлемента;
	
КонецФункции

Разработчик оглядывает код и радуется проделанной работе. А заодно и проверяет насколько правильно всё работает:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ПутиКДаннымЭлементовФормы = Новый Структура;
	
	Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл
		
		Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") 
			ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда
			
			ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным);
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры

&НаКлиенте
Процедура ОткрытьЗначениеЯчейки(Команда)
	
	ТаблицаФормы = Элементы.Валюты;
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ТекущаяКолонка = ТаблицаФормы.ТекущийЭлемент;
	Сообщить("Имя текущего поля: " + ТекущаяКолонка.Имя);
	Сообщить("Путь к данным текущего поля: " + ПутьКДаннымЭлементаФормы(ТекущаяКолонка.Имя));
	
КонецПроцедуры

&НаКлиенте
Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента)
	
	ПутьКДаннымЭлемента = Неопределено;
	ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента);
	Возврат ПутьКДаннымЭлемента;
	
КонецФункции

Вернувшись в тонкий клиент, Василий смотрит на результат:

Скрин

Уже лучше. Теперь мы можем на клиенте узнать путь к данным формы. Для проверки, что всё на самом деле так, как планировалось, разработчик Вася переименовал элемент формы на «КолонкаСВалютой». Теперь путь к данным и имя элемента непохожи между собой, что поможет понять разницу. Вася любит всё перепроверять.

Ну вот. Всё хорошо. Но что теперь делать с этим? Нужно же определить имя колонки из полного пути к данным формы. Василий берёт самый прямой способ - расщепить полный путь на массив и взять его последний элемент:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ПутиКДаннымЭлементовФормы = Новый Структура;
	
	Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл
		
		Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") 
			ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда
			
			ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным);
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры


&НаКлиенте
Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента)
	
	ПутьКДаннымЭлемента = Неопределено;
	ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента);
	Возврат ПутьКДаннымЭлемента;
	
КонецФункции


&НаКлиенте
Процедура ОткрытьЗначениеЯчейки(Команда)
	
	ТаблицаФормы = Элементы.Валюты;
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ИмяПоляКолонки     = ТаблицаФормы.ТекущийЭлемент.Имя;                 //КолонкаСВалютой
	ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ИмяПоляКолонки);        //Валюты.Валюта
	
	СоставПутиКДанным  = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь);     //Валюты; Валюта
	ИмяКолонкиТаблицы  = СоставПутиКДанным[СоставПутиКДанным.ВГраница()]; //Валюта
	
	Сообщить("Имя колонки таблицы: " + ИмяКолонкиТаблицы);
	
КонецПроцедуры

- Сейчас проверим

Скрин

Осталось немного — просто взять значение из колонки и открыть его:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
	
	ПутиКДаннымЭлементовФормы = Новый Структура;
	
	Для Каждого ЭлементФормы Из ЭтаФорма.Элементы Цикл
		
		Если ТипЗнч(ЭлементФормы) = Тип("ПолеФормы") 
			ИЛИ ТипЗнч(ЭлементФормы) = Тип("ТаблицаФормы") Тогда
			
			ПутиКДаннымЭлементовФормы.Вставить(ЭлементФормы.Имя, ЭлементФормы.ПутьКДанным);
			
		КонецЕсли;
		
	КонецЦикла;
	
КонецПроцедуры


&НаКлиенте
Функция ПутьКДаннымЭлементаФормы(ИмяЭлемента)
	
	ПутьКДаннымЭлемента = Неопределено;
	ПутиКДаннымЭлементовФормы.Свойство(ИмяЭлемента, ПутьКДаннымЭлемента);
	Возврат ПутьКДаннымЭлемента;
	
КонецФункции


&НаКлиенте
Процедура ОткрытьЗначениеЯчейки(Команда)
	
	ТаблицаФормы = Элементы.Валюты;
	
	Если ТаблицаФормы.ТекущиеДанные = Неопределено Тогда
		Возврат;
	КонецЕсли;
	
	ИмяПоляКолонки     = ТаблицаФормы.ТекущийЭлемент.Имя;
	ПутьКДаннымКолонки = ПутьКДаннымЭлементаФормы(ИмяПоляКолонки);
	
	СоставПутиКДанным  = СтрРазделить(ПутьКДаннымКолонки, ".", Ложь);
	ИмяКолонкиТаблицы  = СоставПутиКДанным[СоставПутиКДанным.ВГраница()];
	
	ЗначениеЯчейки     = Неопределено;
	ТаблицаФормы.ТекущиеДанные.Свойство(ИмяКолонкиТаблицы, ЗначениеЯчейки);
	
	ПоказатьЗначение(Новый ОписаниеОповещения, ЗначениеЯчейки);
	
КонецПроцедуры

Замечательно! Инструмент заработал. И теперь уже значение будет открываться независимо от того, как называется наш элемент формы.

Василий уже прикинул в голове способы применения этого кода. Например, у нас есть табличная часть документа, которую нельзя редактировать. Наш разработчик ставит на таблицу ТолькоПросмотр, а так же подвязывает событие «Выбор», в котором открывает текущее значение.

И как только наш начинающий программист подумал об этом, в голову пришла мысль.

- Недостаточно удобно!

Да, этого мало. Василий хочет сделать ещё круче! Он решает переспать с этой мыслью, чтобы уже позже продолжить свой путь от простой задачи к универсальному механизму…

Авторский пост защищен лицензией CC BY 4.0 .