HTML, Excel, Word, SEOОсновы JavaScript ⇒ Формы

ОСНОВЫ JavaScript

Учебник JavaScript
·Знакомство с JS. Переменные, операторы, операции
·Функции
·Модель HTML документа
·Иерархия документов в бразуере
·Формы
·Окна и фреймы
·Ссылки, заголовок, статус
·События
·События клавиатуры и мыши
·События. Таймер
·Стили. Управление стилями
·Слои и блоки. Управление видимостью
·Объекты JS
·Внешние объекты
·Внутренние объекты
·Массивы
·Регулярные выражения
·Математика в JS
·Пример простого калькулятора
·Дата и время
·Cookies и хранение состояния
·Немного об AJAX
·Работа с WebMoney

 

Формы



Доступ к формам и элементам

Изменение значений и параметров элементов

Две предыдущие главы почти не содержали примеров. Поэтому вы, скорее всего, уже не можете дождаться новых приемов и скриптов, которые можно опробовать в деле. Могу вас обрадовать – эта, а также две следующие главы будут сосредоточены в основном на коде. Эти главы, если можно так выразиться, будут практическим подтверждением той информации, которую вы уже получили.  

Начнем с тех элементов страницы, которые являются основой всех взаимодействий пользователя с веб-сайтом, а именно с форм. 

В первую очередь, построим HTML-код, на основе которого будут выполняться все скрипты-примеры. Условимся, что скрипт для работы будет находиться во внешнем файле – впрочем, взглянув на структуру HTML-документа, вы и сами это увидите. 

Наш код будет включать все общеупотребимые элементы форм – кроме кнопок-картинок. 

Я предлагаю использовать следующий код (он довольно большой, к сожалению): 

Но, к счастью, все примеры будут работать только с этим кодом – так что приведенный выше HTML вам вообще не нужно будет менять. 

Здесь нужно сделать несколько комментариев по поводу этого кода.  

Строчка

<input type="button" value="Process Code" onClick="process();" /> 

может привести в некоторое замешательство атрибутом onClick. Не вдаваясь в подробности (для этих подробностей будет отведена специальная глава), можно сказать, что этот атрибут заставит выполняться функцию process() при нажатии на кнопку.

Все результаты работы мы будем создавать в div-е с ID равным  result. То есть – будем их динамически формировать при помощи уже описанных ранее методов.

Конечно, вы можете спросить, зачем вызывать функцию process(), куда мы поместим все операции по работе с формой, по нажатию кнопки, а не сразу. Но для этого есть веская причина – если вызвать функцию сразу в загружаемом скрипте, она может выполниться еще до того, как сформируется страница, и, таким образом, вызовет ошибку (по причине отсутствия формы, с которой функция работает).

Доступ к формам и элементам

Первым боевым заданием, на основе которого можно будет рассмотреть способы доступа к формам и элементам формы, будет построение списка всех этих форм и элементов. После выполнения скрипта хотелось бы видеть список (ненумерованный) всех форм страницы со вложенными элементами. Для каждого элемента должен указываться тип, имя и значение (если это группа элементов – то показываться выбранный элемент). 

На первый взгляд, работа, как говорится, неподъемная, но могу вас заверить – в результате работы код будет не очень большим. К сожалению, некоторые из операций вы еще не встречали – в основном, это будут операции со массивами, но они простые и понятные (и к тому же – я буду их пояснять в процессе создания кода). 

Для начала, стоит описать общее решение задачи. Звучать оно будет примерно так: 

«Получить список всех форм и элементов с атрибутами; сформировать HTML-список из внутреннего представления». 

При создании кода мы будем использовать «нисходящее программирование», то есть – сначала реализовывать общие части решения, и детализировать и расширять их в процессе разработки. 

Как вы видите, описание задачи с легкостью преобразуется в код, который эту задачу решает. Здесь, по принципам нисходящего программирования, решение будет использовать еще ненаписанные функции – для простоты, считаем что они уже есть. 

Вот код: 

function process() {
        // Главная функция.
        var structure = get_forms_elements();
        create_list(structure);
} 

Этот код работать не будет – для его запуска необходимо написать функции get_forms_elements() и create_list().

Но теперь задача разбита на две задачи поменьше – и каждую из них решить проще. 

Строчка, содержащая две косые черты «//» -- это так называемый комментарий. Весь текст, находящийся после символов комментарий до конца строки не воспринимается интерпретатором JavaScript, и может содержать что угодно. Чаще всего такие комментарии используются для пояснения кода, описания входящих параметров и так далее.

Есть и еще один тип комментариев – текст, находящийся между «/*» и «*/».

Этот комментарий может занимать несколько строк, главное – чтобы внутри комментария не было символов «*/» (потому что эти символы показывают конец комментария и вызовут ошибку). И не забывайте, что весь текст в коде JavaScript желательно писать в кодировке UTF-8

Итак, приступаем к решению новых задач. Первая из них – это получение списка элементов формы. 

Здесь мы поступим таким же образом – разобъем задачу на задачи поменьше. 

Например, так: 

function get_forms_elements() { 
        var forms = document.forms;
        var elements = [];
        for (var i = 0; i < forms.length; i++ ) {
                elements[i] = get_elements_from_form(forms[i]);
        }
        return elements;
}        

Здесь вводится новая «несуществующая» функция – get_elements_from_form(), которая получает все элементы из переданной ей формы.

Весь остальной код, кроме этой функции, вполне работоспособен и уже решает некоторую задачу, а именно – обход форм. 

Рассмотрим код построчно: 

var forms = document.forms;

Как вы можете понять, эта строка присваивает переменной forms содержимое переменной documen.forms. Ее практический смысл – к списку форм из объекта document можно будет обращаться по короткому имени (так как обе переменные содержат ссылку на один и тот же массив). Такое сокращение длины имени – достаточно частое действие, особенно если исходная переменная содержит четыре-пять ссылок на внутреннюю структуру.

В дальнейшем, комментироваться будут только незнакомые вам конструкции, так что не расслабляйтесь. 

Строка объявления цикла  

for (var i = 0; i < forms.length; i++ ) { 

содержит еще не описанное мной выражение – forms.length

Если я еще не упоминал об этом (или если я упоминал, но давно и вы забыли), расскажу о доступе к элементам массивов и объектов. 

Для того чтобы получить доступ к элементу массива, используется оператор «выбор по индексу». Это обычные квадратные скобки, такие же как и в определении массива. 

Например, такая запись 

var a = b[2];

занесет в переменную a содержимое второго элемента массива. 

Запись же  

a = b[0];

занесет в a нулевой элемент этого же массива. 

Да, в программировании на языке JavaScript, как и во многих других, элементы массива нумеруются с нулевого. 

Теперь об объектах. С ними все интереснее – во-первых, для доступа к свойствам объекта можно использовать точку, указывая после нее название свойства. 

Например, вот так: 

var forms = document.forms 

Думаю, такая запись вам уже встречалась неоднократно. Теперь вы точно знаете, что именно она означает. 

Но, кроме этой записи, можно также использовать обращение, аналогичное обращению к массиву. Например, предыдущую операцию можно переписать так: 

var forms = document['forms'] 

И она будет делать то же самое. 

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

И – небольшое дополнение по поводу массивов. Любой массив тоже является объектом, и кроме собственно элементов содержит несколько специальных значений и методов. 

Наиболее используемым является свойство «length», то есть – размер массива.

Поэтому в цикле, объявленном как 

for (var i = 0; i < forms.length; i++ ) { 

переменная i будет изменяться от нулевого индекса массива до последнего индекса (который равен length – 1) включительно.

Обычно именно таким образом обрабатывают все элементы массива. 

Строчка  

elements[i] = get_elements_from_form(forms[i]); 

не требует особых комментариев, учитывая вышенаписанное – здесь в элемент массива elements заносится результат работы функции   get_elements_from_form(), которой каждый раз передается значение элемента массива forms.

В целом, вся функция попросту вызывает get_elements_from_form() для каждой формы и возвращает массив результатов.

Теперь настало время написать функцию  get_elements_from_form().

Эта функция будет одним из ключевых элементов скрипта, и ее задача – получить все элементы с атрибутами.  

Для того чтобы получить атрибуты, нужно знать следующее: каждая форма содержит список элементов, каждый из которых в свою очередь является объектом и содержит свойства -- атрибуты, значения и так далее. Эти объекты создаются браузером автоматически после загрузки HTML-документа. 

Самыми используемыми атрибутами элементов являются имя, ID и значение. Доступ к ним выполняется при помощи свойств name, id и value соответственно.

Для наших целей этих свойств вполне достаточно, хотя нужно упомянуть, что эти свойства – не единственные, которые есть у элементов форм. 

В коде функции, который я приведу ниже, будет показано, каким образом можно получить доступ к этим свойствам. 

Как вы видите, эта функция получилась достаточно объемной, и сейчас вы поймете почему. 

Все дело в radiobuttons. Как вы знаете, группа radio-кнопок в HTML-форме обладает интересным свойством --  у всех радиокнопок одной группы одинаковое имя (не ID). Это, во-первых, делает их группой, а во-вторых, значением этой группы является значение выбранного элемента.

С чекбоксами происходит похожая вещь – значение возвращается только если чекбокс отмечен. 

Именно поэтому простым считыванием свойства value дело не заканчивается – приходится также проверять свойство checked кнопки, и уже на основании этого свойства выбирать, какое же значение будет у элемента.

Интерес в приведенном коде представляют следующие строки: 

current_el = {name: temp_el.name, type: 'checkbox', value: temp_el.value}; 

Во всех подобных строках формируется новый объект, свойства которого задаются не литеральными выражениями, а значением переменных. 

Так, в приведенной строке свойству name будет назначено значение свойства name переменной temp_el

elements.push(current_el); 

Эта строка добавляет элемент в конец массива. Кроме метода push() массив имеет еще несколько методов, которые оперируют с данными массива. Этим методам будет посвящен отдельный раздел.

for (var rg in radio_groups) { 

Это объявление «цикла по всем ключам». 

Такое объявление используется для того, чтобы перебрать все ключи какого-либо объекта. Согласитесь, если в случае когда индексы были числами, было достаточно перебрать все числа от 0 до максимального индекса, в случае когда индексы строковые (то есть – это ключи) делать такой перебор неэффективно – да и как перебрать все строки? 

Именно поэтому в языке JavaScript введена такая конструкция. 

Внутри тела цикла переменная rg (в нашем случае, вообще там будет любая переменная) последовательно принимает значения всех ключей (за небольшими исключениями, но это в данном случае несущественно) объекта. И эту переменную можно использовать для доступа к свойству объекта.

Фактически, у нас уже может быть выполнена первая часть общей функции process(). Для проверки, правильно ли все работает, стоит каким-либо образом проверить данные, которые эта часть возвращает (то есть – содержимое переменной structure после выполнения функции  get_forms_elements() ).  

Для этого можно, например, вставить вместо вызова еще не написанной функции create_list() следующие строки:

str = structure[0][0]; 
alert (str.name + ' ' + str.value + ' ' + str.type); 

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

Если все работает, можно переходить к написанию функции-генератора списка. 

Список, который должен получиться в результате, будем создавать при помощи DOM-функций. 

Лично я написал бы такой код: 

Как вы видите, я ввожу дополнительную функцию ce для того, чтобы не писать постоянно document.createElement().

Весь остальной код фактически объяснен в комментариях внутри самого кода – все выражения, которые вы здесь видите, уже вам знакомы или встречались раньше. 

Кроме того, эта функция показывает те примеры работы с DOM-деревом, которые были описаны раньше, но не имели примеров. 

Теперь нужно все функции собрать в один большой файл test.js (не забудьте убрать тестовый код, который вы использовали для проверки работоспособности функции get_forms_elements() и поставить на место вызов create_list()).

Изменение значений и параметров элементов

Здесь все с точностью до наоборот. Если в предыдущем коде мы брали значения из объектов – элементов форм, то в новом коде мы будем наоборот, заносить туда значения. 

Никаких особых премудростей не будет – разве что такие «специальные штуки» как селект-боксы со списками значений... Собственно, именно этот случай мы и будем рассматривать. 

Задача, которую нужно будет решить, формулируется так: добавить содержимое текстового поля  к первому списку, если отмечен левый чекбокс, и ко второму списку, если отмечен правый чекбокс. После добавления чекбоксы и поле ввода нужно очистить.

Возьмем за основу уже существующий HTML-код со всеми полями. В этом коде есть и чекбоксы, которые мы сможем проверять, и выпадающие списки. 

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

Итак,  вот шаблон кода:

function process() { 
        // Главная функция.
        var to_add = get_text();
        if (is_checked('check_id_a')) {
                insert_value(to_add, 'select_id_from');
        }
        if (is_checked('check_id_c')) {
                insert_value(to_add, 'select_id_to');
        }
        clear_text_and_checkboxes();
} 

Думаю, этот код даже не нуждается в пояснениях. 

Код для функций получения значений тоже достаточно прост: 

function get_text() { 
        var el = document.getElementById('text_id');
        return el.value;
} 
 
function is_checked(what) { 
        // Не забыть проверить, является ли элемент чекбоксом
        el = document.getElementById(what);
        if (el && el.type == 'checkbox') {
                return el.checked;
        }
} 

Но, при этом, так как функция is_checked() получает ID элемента извне – она предварительно проверяет, существует ли вообще элемент с таким ID, и является ли он чекбоксом. И только если проверки прошли, она возвращает состояние чекбокса, отмечен он или нет.

С добавлением элемента к выпадающему списку все в принципе тоже не так уж и сложно. 

Это добавление можно делать как при помощи appendChild(), так и при помощи более раннего метода  add(). В этом примере я буду использовать второй способ.

Код получится примерно таким: 

function insert_value(what, into) { 
        var el = document.getElementById(into);
        if (!el || el.type != 'select-one') {
                return false;
        }
        // до этой строки скрипт доходит только если указанный элемент -- выпадающий список
        var new_option = document.createElement('option');
        new_option.text = what;
        new_option.value = 'option_'+what;
        el.add(new_option, null); // добавляем элемент в конец списка
        // этот элемент будет автоматически выбран
        el.selectedIndex = el.length -1;
        return true;
} 

Здесь, как вы понимаете, тоже идет проверка на тип элемента. Следует запомнить, что для выпадающих списков (которые задаются при помощи тега select) тип будет не select, а select-one для одиночных списков и select-multiple для списков с множественным выделением. 

Функция add() списка требует два аргумента – первый это новый элемент (его нужно предварительно создать), а второй – это индекс элемента, перед которым нужно вставить этот элемент. К счастью, можно указать вместо этого параметра null, и тогда элемент будет добавлен в конец списка.

После добавления мы устанавливаем выбранным последний элемент – у списка есть параметр length, который равен числу элементов (почти как в массиве, только сами элементы списка доступны при помощи дополнительного свойства списка – options)

Функция очистки еще проще: 

function clear_text_and_checkboxes() { 
        document.getElementById('text_id').value='';
        document.getElementById('check_id_a').checked=false;
        document.getElementById('check_id_c').checked=false;
} 

Здесь используется то свойство JavaScript, что необязательно записывать результат работы функции в переменную, чтобы потом обратиться к свойству этого результата. Можно выполнить обращение сразу после вызова (так как здесь – результат функции getElementById() это объект, у него есть свойство value, и этому свойству можно присвоить значение – и все в одной строке).

Конечно, работа с формами не ограничивается только описанными примерами. У элементов форм можно менять их тип (например, можно чекбокс сделать полем пароля – простой заменой параметра type), или запретить поле (установить атрибут disabled этого поля), и так далее. Но все эти вещи делаются практически так же как и уже описанные. 

Теперь, как обычно во всех практических главах – задание.  

Вам предстоит на основе все того же HTML-кода и примеров из главы создать код, который поместит все элементы из первого списка во второй, а из второго – в первый. 

Операция remove() для списков существует, получает один параметр – индекс элемента.



В начало страницы



В начало страницы