|
ФормыИзменение значений и параметров элементов Две предыдущие главы почти не содержали примеров. Поэтому вы, скорее всего, уже не можете дождаться новых приемов и скриптов, которые можно опробовать в деле. Могу вас обрадовать – эта, а также две следующие главы будут сосредоточены в основном на коде. Эти главы, если можно так выразиться, будут практическим подтверждением той информации, которую вы уже получили. Начнем с тех элементов страницы, которые являются основой всех взаимодействий пользователя с веб-сайтом, а именно с форм. В первую очередь, построим HTML-код, на основе которого будут выполняться все скрипты-примеры. Условимся, что скрипт для работы будет находиться во внешнем файле – впрочем, взглянув на структуру HTML-документа, вы и сами это увидите. Наш код будет включать все общеупотребимые элементы форм – кроме кнопок-картинок. Я предлагаю использовать следующий код (он довольно большой, к сожалению): <html> <head> <script type="text/javascript" src="test.js"></script> </head> <body> <form name="test_form_name" id="test_form_id" method="get" action="?"> <input type="hidden" name="hidden_name" id="hidden_id" value="hidden" /><br/> <input type="text" name="text_name" id="text_id" value="text" /><br/> <input type="password" name="password_name" id="password_id" value="password" /><br/> <input type="radio" name="radio_group_1" id="radio_id_1" value="radio_1" /> <input type="radio" name="radio_group_1" id="radio_id_2" value="radio_2" /> <input type="radio" name="radio_group_1" id="radio_id_3" value="radio_3" /><br/> <input type="radio" name="radio_group_2" id="radio_id_a" value="radio_a" /> <input type="radio" name="radio_group_2" id="radio_id_b" value="radio_b" /> <input type="radio" name="radio_group_2" id="radio_id_c" value="radio_c" checked="checked" /><br/> <input type="checkbox" name="check_a" id="check_id_a" value="check_1" checked="checked" /> <input type="checkbox" name="check_b" id="check_id_b" value="check_2" /> <input type="checkbox" name="check_c" id="check_id_c" value="check_3" checked="checked" /><br/> <select name="select_name_from" id="select_id_from"> <option value="option_1">1</value> <option value="option_2" selected="selected">2</value> <option value="option_3">3</value> </select><br/> <select name="select_name_to" id="select_id_to"> <option value="option_4">4</value> <option value="option_5">5</value> <option value="option_6">6</value> </select><br/> <textarea name="textarea_name" id="textarea_id" cols="20" rows="5">Textarea</textarea><br/> <input type="submit" name="submit_name" id="submit_id" value="submit" /> <input type="reset" name="reset_name" id="reset_id" value="reset" /> </form> <input type="button" value="Process Code" onClick="process();" /> <div id="result"></div> </body> </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 соответственно. Для наших целей этих свойств вполне достаточно, хотя нужно упомянуть, что эти свойства – не единственные, которые есть у элементов форм. В коде функции, который я приведу ниже, будет показано, каким образом можно получить доступ к этим свойствам. function get_elements_from_form(form) { var elements = []; var current_el; var radio_groups = {}; // Эта переменная служит для учета групп радиокнопок for (var i = 0; i < form.length; i++) { var temp_el = form[i]; switch(temp_el.type) { case "radio" : if (temp_el.checked) { radio_groups[temp_el.name] = '[filled]'; // помечаем группу current_el = {name: temp_el.name, type: 'radio', value: temp_el.value}; } else { if (!radio_groups[temp_el.name]) { // если группа еще не встречалась radio_groups[temp_el.name] = '[no elelements checked]'; } continue; } break; case 'checkbox' : if (temp_el.checked) { current_el = {name: temp_el.name, type: 'checkbox', value: temp_el.value}; } else { current_el = {name: temp_el.name, type: 'checkbox', value: '[not checked]'}; } break; default: current_el = {name: temp_el.name, type:temp_el.type, value: temp_el.value}; break; } elements.push(current_el); } // Отдельная обработка всех radio groups for (var rg in radio_groups) { if (radio_groups[rg] != '[filled]') { //добавляем группу, в которой нет выбранных кнопок elements.push({name: rg, type: 'radio', value: radio_groups[rg]}); } } return elements; } Как вы видите, эта функция получилась достаточно объемной, и сейчас вы поймете почему. Все дело в 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-функций. Лично я написал бы такой код: function ce(el) { return document.createElement(el); } function create_list(structure) { var host_el = document.getElementById('result'); host_el.innerHTML = ''; // Создаем основной элемент списка UL var el = ce('ul'); var ul_top = host_el.appendChild(el); for (var i=0; i<structure.length; i++) { // Проходимся по всем формам. // И для каждой формы создаем вложенные элементы LI и UL el = ce('li'); var li_top = ul_top.appendChild(el); el = ce('ul'); var ul_per_form = li_top.appendChild(el); for (var j = 0; j < structure[i].length; j++) { // Проходимся по всем элементам // Для каждого элемента создаем свой внутренний LI el = ce('li'); var inner_li = ul_per_form.appendChild(el); // проходимся по всем элементам var form_el = structure[i][j]; inner_li.innerHTML = 'Название: ' + form_el.name + '; Тип: ' + form_el.type + '; Значение: ' + form_el.value; } } } Как вы видите, я ввожу дополнительную функцию 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() для списков существует, получает один параметр – индекс элемента. |
|
Спасибо, что заглянули на сайт. Надеюсь, Вам понравилось. Заходите еще. Здесь всегда рады вам :) |
© 2008 |
E-mail: |