В этой статье разберём методы jQuery для чтения, добавления, изменения и удаления DOM свойств. На практике подробно остановимся на рассмотрении таких свойств как disabled, checked и selected.

Что такое DOM-свойства элементов?

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

Другими словами, свойства элементов – это то, что находится в DOM, а атрибуты - это то, что находится в HTML. Так как в JavaScript мы работаем со страницей через DOM, то в большинстве случаев более корректно взаимодействовать именно с DOM-свойствами, а использовать HTML-атрибуты только тогда, когда мы осознанно хотим что-то получить или изменить в HTML.

HTML-атрибуты disabled, checked, selected и т.п.

Значения атрибутов (disabled, checked, selected, hidden, readonly и т.п.) отличиаются от соответствующим им DOM-свойств. При этом значение атрибута - это всегда строка, а DOM-свойства - нет. Разные DOM-свойства могут иметь разные типы данных. Например, DOM-свойства disabled, checked, selected и тому подобные имеют логический тип.

Как же тогда они согласуются? Этот процесс описан в стандарте. В ооответсвии с ним, значение этих DOM-свойств (disabled, checked и т.п.) равно true, когда такой атрибут присутсвует у тега и при этом не важно какое он имеет значение. В противном случае значения таких DOM-свойств равно false.

Методы jQuery для управления DOM-свойствами

В jQuery имеется два метода для управления DOM-свойствами элементов.

Первый метод - это prop.

Метод prop

Метод prop предназначен для выполнения различных операций над DOM-свойствами элементов.

Первая операция - это чтение значения DOM-свойства.

Синтаксис метода prop для получения значения DOM-свойства:

.prop( propertyName )
// propertyName - имя DOM-свойства, значение которого нужно получить

Пример, в котором рассмотрим принцип получения значения DOM-свойств с помощью метода prop:

<p id="introtext" class="intro">...</p>

<script>
// получим элемент
var intro = $('#introtext');
// выведем в консоль значение DOM-свойства id
console.log(intro.prop('id')); // "introtext"
// выведем в консоль значение DOM-свойства className
// при этом jQuery позволяет обращаться к этому DOM-свойству как по имени "class", так и по имени "className"
console.log(intro.prop('class')); // "intro"
console.log(intro.prop('className')); // "intro"
</script>

Но DOM-свойства для элементов создаются не только в соответствии с теми атрибутами, которые есть у каждого из них в HTML. Для каждого элемента в соответствии с его встроенным классом создаётся целый набор стандартных для него DOM-свойств. Например, для элемента input (его класс HTMLInputElement) создаётся один набор DOM-свойств, а для элемента a (его класс HTMLAnchorElement) создаётся немного другой, но стандартный уже для него набор DOM-свойств.

Пример, в котором изменим значения DOM-свойств элемента:

<input type="email" class="form-email" id="email" aria-describedby="emailHelp" placeholder="Введите email">
<a class="btn btn-warning" id="link" href="#" role="button">Сслыка</a>

<script>
// получим элементы
var email = $('#email');
var link = $('#link');

// выведем в консоль значение DOM-свойства type для элемента #email
console.log(email.prop('type')); // "email"
// выведем в консоль значение DOM-свойства href для элемента #link
console.log(link.prop('href')); // полный URL
// получим значение DOM-свойства checked для элемента #email (HTML-атрибут checked у данного элемента отсутствует)
console.log(email.prop('checked')); // false
// получим значение DOM-свойства autocomplete для элемента #email (HTML-атрибут autocomplete у данного элемента отсутствует)
console.log(email.prop('autocomplete')); // ""
// получим значение DOM-свойства tagName (имя тега), данное свойство есть у каждого элемента в DOM (в HTML ему не соответствует никакой HTML-атрибут)
console.log(email.prop('tagName')); // "INPUT"
console.log(link.prop('tagName')); // "A"

// при попытке получить значение DOM-свойства, которого нет у элемента в DOM, будет возвращено undefined (это можно использовать для проверки наличия определённого DOM-свойства у элемента)
console.log(link.prop('checked')); // undefined
</script>

Воторая операция - это изменение значения DOM-свойства.

Синтаксис метода prop для установления DOM-свойству нового знчаения:

.prop( propertyName, value )
// propertyName - имя DOM-свойства, значение которому нужно установить
// value - значение, которое нужно установить DOM-свойству
Кроме этого варианта jQuery предлагает ещё два:
// Вариант № 2 (предназначен для установки сразу нескольских DOM-свойств элементу)
.prop( properties )  
// properties - это объект, состоящий из набора пар свойство-значение:
// {
//   'имя_DOM-свойства': 'значение',
//   'имя_DOM-свойства': 'значение',
//   ... 
// }

// Вариант № 3 (предназначен для установки DOM-свойства такого значения которое вернёт функция)
.prop( propertyName, function )  
// propertyName - имя DOM-свойства, значение которому нужно установить
// function - функция, которая будет определять значение DOM-свойства (это значение будет тем, которая она вернёт в результате своего выполнения). 
// синтаксис функции:
// Function( Integer index, Anything oldPropertyValue ) => Anything
// на вход она получает:
//   index - индекс элемента в наборе
//   oldPropertyValue - текущее (старое) значение DOM-свойства
// внутри функции ключевое слово this указывает на текущий элемент набора

Пример, в котором изменим значения DOM-свойств элементов:

<input type="text" class="form-input" id="input-1" disabled>
<input type="text" class="form-input" id="input-2" disabled>

<script>
// получим элемент #input-1
var input1 = $('#input-1');

// Вариант №1
// изменим значение DOM-свойства type на file
input1.prop('type', 'file');
// изменим значение DOM-свойства disabled на false
input1.prop('disabled', false);

// Вариант №2
input1.prop({
  'type': 'file',
  'disabled': false
})
</script>

Пример, в котором установим заголовкам h2 и h3, находящихся в элементе .article, идентификаторы, если их у данных элементов нет:

<div class="article">
  <h2>...</h2>
  ...
  <h2>...</h2>
  ...
  <h3>...</h3>
  ...
</div>

<script>
var headers = $('.article').find('h2, h3');
headers.prop('id', function (index, oldPropertyValue){
  if (!oldPropertyValue) {
    return 'header-' + index;
  }
});
</script>

Удалить стандартное DOM-свойство у элемента нельзя. Но вы можете установить ему значение по умолчанию.

Пример, в котором установим для некоторого элемента, например button, значение DOM-свойства равным false.

<button id="btn" disabled>Кнопка</button>

Сейчас данный элемент в качестве значения DOM-свойства disabled имеет значение true, т.к. атрибут disabled присутствует у тега.

// значение DOM-свойства disabled
console.log($('#btn').prop('disabled')); // true
// значение HTML-атрибута disabled
console.log($('#btn').attr('disabled')); // ""

Теперь установим данному DOM-свойству значение false. Это изменение также повлияет на HTML код, данный атрибут будет убран у элемента. Это действие связано с тем, что браузер синхронизирует DOM и HTML код.

// установим DOM-свойству disabled значение false
console.log($('#btn').prop('disabled', false)); 
// получим значение HTML-атрибута disabled
console.log($('#btn').attr('disabled')); // undefined

Пример, в котором переведём кнопку submit в активное состояние (т.е. установим ей свойство disabled равное false) когда содержимое элемента input[name="search"] не будет равно пустой строке:

<form action="search.php">
  <input type="text" name="search">
  <input type="submit" value="Отправить">
</form>
  
<script>
// после загрузки страницы
$(function() {
  // установим кнопки submit DOM-свойство disabled со значением true (т.е. сделаем её не активной) 
  $('input[type="submit"]').prop('disabled', true);
  // при отпускании клавиши, проверим значение данного поля
  $('input[name="search"]').keyup(function() {
    // если значение не равно пустой строке
    if($(this).val() !== '') {
      // то сделаем кнопку активной (т.е. установим свойству disabled значение false)            
      $('input[type="submit"]').prop('disabled', false);
    }
  });
});
</script>    

Принцип работы с checked ничем не отличается от disabled.

Примеры работы с checked

1. Пример, в котором установим флажок checkbox, а затем снимем его у него через 5 секунд:

<!-- Чекбокс -->
<input type="checkbox" name="agree" id="agree">

<script>
  // переведем checked во включенное состояние (установим флажок)
  $('#agree').prop('checked', true);
  setTimeout(function () {
    // переведём checked в выключенное состояние (уберём флажок)
    $('#agree').prop('checked', false);
  }, 5000);
</script>

2. Пример, в котором будем перед отправкой формы проверять состояния checkbox #agree, и если он не установлен в true, то выводить некоторое сообщение и отменять отправку формы на сервер.

<form id="register" action="register.php" method="post" autocomplete="off">
  ...
  <input name="eula_accepted" id="eula_accepted" type="checkbox">
  <label for="eula_accepted">
    Нажимая на кнопку "Зарегистрироваться", я принимаю условия Пользовательского соглашения
  </label>
  <div id="error-eula" style="display:none">
    Для продолжения вы должны принять условия Пользовательского соглашения
  </div>
  <button type="submit">Зарегистрироваться</button>
</form>

<script>
// при отправке формы на сервер
$('#register').submit(function (e) {
  // если ли значение DOM-свойства checked равно false...
  if ($(this).find('#eula_accepted').prop('checked') === false) {
    // то отобразим сообщение о том, что вы должны принять условия пользовательского соглашения
    $('#error-eula').css('display', 'block');
    // отменим отправку форму на сервер
    e.preventDefault();
  } else {
    $('#error-eula').css('display', 'none');
  }
});
</script>

3. Пример, в котором выполним две операции, связанные с checked. Первое - это установим после загрузки страницы второму элементу radio состояние checked, равное true. Второе - это создадим обработчик для события change, который будет выводить в #log значение выбранного переключателя:

<!-- radio-элементы -->
<label>
  <input type="radio" checked="checked" name="web" value="HTML">
  HTML
</label>
<label>
  <input type="radio" name="web" value="CSS">
  CSS
</label>
<label>
  <input type="radio" name="web" value="JavaScript">
  JavaScript
</label>
<!-- #log -->
<div id="log"></div>

<script>
var web = $('input[name="web"]');
// установим второму элементу в наборе (с индексом 1) значение true для DOM-свойства checked 
web.eq(1).prop('checked', true);
// обработчик события при изменении выбранного checkbox 
web.change(function () {
  // получим значение элемента с состоянием checked
  var value = $('[name="web"]:checked').val();
  // вывести это значение в #log
  $('#log').text(value + ' is checked');
});
</script>

Пример работы с selected

Пример, в котором выполним несколько действий. Первое - это установим состояние selected второму option. Второе - это создадим обработчик для события change, который будет выводить в #log выбранный пункт.

<select id="list">
  <option>Пункт 1</option>
  <option>Пункт 2</option>
  <option>Пункт 3</option>
</select>
<div id="log"></div>

<script>
  // установим второму option значение DOM-свойству selected равное true
  $('#list option:nth-child(2)').prop('selected', true);
  // обработчик события change, который будет выводить в #log выбранный пункт
  $('#list').change(function () {
      $('#log').text($('#list').prop('value') + ' - selected');
  })
</script>

Пользовательские DOM-свойства

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

По сути, DOM элементы (узлы) – это обычные объекты JavaScript. Следовательно, к ним, как и к любым другим объектам можно добавлять свои свойства.

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

Рассмотрим добавление собственного DOM-свойства к элементам на следующем примере.

В этом примере добавим к элементам .counter пользовательское DOM-свойство count, которое будем использовать для хранения количество нажатий (click-ов):

<button class="counter">Нажми на меня</button>
<button class="counter">Нажми на меня</button>
<button class="counter">Нажми на меня</button>

<script>
var 
  counters = $('.counter'), // получим все кнопки
  defaultButtonText = 'Нажми на меня'; // текст кнопки по умолчанию
// добавим ко всем кнопкам DOM-свойство count со значением 0.
counters.prop('count', 0);
// добавим обработчик события click для каждой кнопки (при нажатии на кнопку будем увеличивать значение его DOM-свойства count на 1)
counters.click(function(){
  // сохраним текущее значение DOM свойства count в переменную count
  var count = $(this).prop('count');
  // увеличим значение переменной count на 1
  count++;
  // сохранить значение переменной count в пользовательское DOM-свойство count этого элемента
  $(this).prop('count',count);
  // изменим текст текущей кнопки
  $(this).text(defaultButtonText + ': ' + count);
});
</script>

Пользовательские DOM-свойства не отображаются в HTML коде и ни каким образом не сказываются отрисовку этого элемента на странице.

Удаление пользовательского DOM-свойства у элемента осуществляется с помощью метода removeProp.

Синтаксис метода removeProp:

.removeProp( propertyName )
// propertyName (тип: Строка) - свойство, которое нужно удалить

Данный метод предназначен исключительно для удаления собственных DOM-свойств. Удалить стандартные (встроенные) DOM-свойства у элементов нельзя, вы можете им просто установить значение по умолчанию.

Пример, в котором будем добавлять и удалять у элемента #paragraph пользовательское DOM-свойство при нажатии соответственно на ту или иную кнопку:

<p id="paragraph"></p>
<button id="add-custom-property">Добавить DOM-свойство myProp к элементу #paragraph</button>
<button id="remove-custom-property">Удалить DOM-свойство myProp у элемента #paragraph</button>
  
<script>
// при нажатию на кнопку с #add-custom-property
$('#add-сustom-property').click(function(){
  // добавим к элементу #paragraph свойство myProp
  $('#paragraph').prop('myProp', 'Этот текст является значением DOM-свойства myProp');
  // выведим в качестве контента элементв #paragraph значение свойства myProp
  $('#myParagraph').text($('#myParagraph').prop('myProp'));
});
// при нажатию на кнопку с #remove-custom-property
$('#remove-custom-property').click(function(){
  // удалим у элемента #paragraph свойство myProp
  $('#paragraph').removeProp('myProp');
  // вывести сообщение о том, что свойство myProp не существует
  if ($('body').prop('myProp') === undefined ) {
    $('#paragraph').text('У элемента нет DOM-свойства myProp!');
  }
});
</script>    

Управление состоянием checked, disabled, selected через HTML-атрибуты

Изменять состояние checked, disabled, selected более предпочтительно через соответствующее DOM-свойство.

Но, тем не менее можно выполнять это и через HTML-атрибуты.

Например, чтобы перевести кнопку в неактивное состояние (disabled), ей нужно просто добавить HTML атрибут disabled.

<button id="btn">Кнопка</button>

<script>
// добавим атрибут disabled
$('#btn').attr('disabled', '');
</script>    

Для выполнения обратного действия, перевода элемента в активное состояние у него нужно удалить этот атрибут:

// удалим атрибут disabled
$('#btn').removeAttr('disabled');

Для управления состоянием checked, readonly необходимо выполнять аналогичные действия.

В приведённом выше примере мы добавляли и удаляли атрибут disabled у элемента. При этом браузер при изменении HTML кода элемента синхронизировал его с DOM, т.е. при добавлении HTML-атрибута disabled устанавливал соответствующему DOM-свойству в данном случае disabled значение true, а при удалении этого HTML-атрибута – устанавливал false.

Браузер также выполняет синхронизацию наоборот, т.е. при изменении DOM изменяет HTML код. Для DOM-свойств с логическим типом это работает так, с другими по-другому. Например, с id, class и style синхронизация происходит точь в точь, а например, с value синхронизация туда и обратно не работает.

Статья, которая может быть вам также интересной:

Работа с атрибутами HTML-элементов в jQuery с помощью методов attr и removeAttr.