Javascript-форум (https://javascript.ru/forum/)
-   Events/DOM/Window (https://javascript.ru/forum/events/)
-   -   Не выдергивается первый символ из выражения getAttribute('href') (https://javascript.ru/forum/events/60922-ne-vydergivaetsya-pervyjj-simvol-iz-vyrazheniya-getattribute-%27href%27.html)

Heny 27.01.2016 14:27

Не выдергивается первый символ из выражения getAttribute('href')
 
Добрый вечер, гуру))) :)
Я новичок в этом языке, но старательно пытаюсь изучить.
Возникла проблема, и я ничего не могу найти, подскажите плиз.

Есть такая строчка:
document.querySelector(this.getAttribute('href')).classList.add('active');


Она находит элемент с href, и элементу, у которого такой же id добавляет класс 'active'.
Это работает, но я хочу немного изменить. Надо чтобы находился href, к значению этого href добавлялись символы 'sm', и уже элементам с id=sm+href добавлялся класс 'active'.
И все тут я села)))
Пишу:
document.querySelector('sm'+this.getAttribute('href')).classList.add('active');

И ничего не получается, вернее получается, что нет такого элемента 'sm#значениеhref', и это понятно. Получается мне надо удалить символ # из значения href. Пробовала через str, через регулярные выражения, но не получается. Подскажите, ткните носом, буду очень благодарна.

laimas 27.01.2016 15:08

'sm'+this.hash.substr(1)

Vlasenko Fedor 27.01.2016 16:46

alert('sm' + '#you_id'.slice(1));

Heny 28.01.2016 08:53

Спасибо большое.
А вот теперь вылезла ошибка:
Uncaught TypeError: Cannot read property 'classList' of null

:blink:

Можно я приложу весь свой малюсенький код? может подскажете откуда эта ошибка(
<script type="text/javascript">
	    var btn = document.querySelectorAll('.btn'),
		el = document.querySelectorAll('.el');
		   Array.prototype.forEach.call(btn, function(curr){
			   curr.addEventListener('click', function() {
				   
				   Array.prototype.forEach.call(el, function(curr){
					   curr.classList.remove('active');
				});
			document.querySelector('sm'+(this.getAttribute('href').slice(1))).classList.add('active');
        return false;        
    }, false);    
}); 
</script>

рони 28.01.2016 09:19

Heny,
как выглядит тег sm? может так '#cm'+... если это id

Heny 28.01.2016 09:29

Выглядит так:
Тут располагаются картинки со стилем el, у которого display: none;
<div id="sm1013" class="el"><img src="/konf3d/sm1013.png" /></div>
      <div id="sm1015" class="el"><img src="/konf3d/sm1015.png" /></div>
      <div id="sm1019" class="el"><img src="/konf3d/sm1019.png" /></div>

А тут располагаются типа кнопочки, при нажатии на которые к стилю el добавляется active, и display становится block:
<div class="panel2">
          <a class="btn" href="#1013"><img src="/konf3d/1013.png"></a>
          <a class="btn" href="#1015"><img src="/konf3d/1015.png"></a>
          <a class="btn"href="#1019"><img src="/konf3d/1019.png"></a>
        </div>


Смысл в том, что потом будет блок с приставкой 'sp' и другие, а кнопочки с href="" останутся теми же самыми

Heny 28.01.2016 09:34

Цитата:

Сообщение от рони (Сообщение 405267)
Heny,
как выглядит тег sm? может так '#cm'+... если это id

Спасибо, добрый человек!!!
Помогло так:
document.querySelector('#sm'+this.getAttribute('href').slice(1)).classList.add('active');

Надо же как просто оказалось!!!!

Heny 28.01.2016 09:45

И еще маленький глупенький вопросик. Как сделать так, чтобы при нажатии на
<a class="btn" href="#1013"><img src="/konf3d/1013.png"></a>
, страница не прокручивалась до самой ссылки-кнопки? Так как
<div id="sm1013" class="el"><img src="/konf3d/sm1013.png" /></div>

с которым происходят изменения находится выше

рони 28.01.2016 10:17

Heny,
отменить переход по ссылке
curr.addEventListener('click', function(event) {event.preventDefault();

laimas 28.01.2016 11:12

Цитата:

Сообщение от Heny
<a class="btn" href="#1015"><img src="/konf3d/1015.png"></a>

Ну так сразу и укажите якоря как href="#sm1015", тогда обратиться к id соответствующему будет проще document.querySelector(this.hash)

Heny 28.01.2016 13:06

Так и было задумано изначально. Там получается комната, у которой меняются цвета стен, так вот будет еще выбираться и материал стен, в таком случае у меня будут дивы с картинками sm... и sp..., а цвета у них одинаковые, вот поэтому мудрю, буду писать условие сейчас, что если выбран такой-то материал, то добавляем sm, если такой-то, то добавляем sp. Ну как-то так :dance:

laimas 28.01.2016 13:17

Цитата:

Сообщение от Heny
будет еще выбираться и материал стен, в таком случае у меня будут дивы с картинками sm... и sp...

Обращение же будет к разным объектам, а цвет и материал выбираются тоже разными ссылками, какие проблемы тогда использовать сразу ID?

Heny 28.01.2016 13:35

Вот в том то и дело, что цвет будет выбираться одними и теми же ссылками, а обращение к разным объектам

laimas 28.01.2016 14:14

Цитата:

Сообщение от Heny
Вот в том то и дело, что цвет будет выбираться одними и теми же ссылками, а обращение к разным объектам

Я разве против? Но далее речь то была о материале. А словами можно - что нужно "сотворить"?

Heny 01.02.2016 14:24

А сотворить нужно грубо говоря планировщик интерьера. У него можно оформить:
1. стены: имеют 3 возможных материала панелей, и в зависимости от выбора радиокнопок панелей, меняются картинки с панелями, на которые скрыты (display:none), а при нажатии на кнопочки с цветами (display:block);
2. полы: имеют 2 возможных варианта - линолеум и наливные, у которых так же разный набор цветов и соответствующих картинок.
А потом еще добавится потолок и оборудование.

Учитывая мое первое знакомство с javascript, то я уже голову всю сломала.
Со стенами у меня все заработало, а добавив пол, все перестало работать :(
Вот.
Можете подскажете, что не так делаю:
<script type="text/javascript">
	    var btn = document.querySelectorAll('.btn'),
		el = document.querySelectorAll('.el');
		   Array.prototype.forEach.call(btn, function(curr){
			   
			   curr.addEventListener('click', function(event) {
				   Array.prototype.forEach.call(el, function(curr){
				   curr.classList.remove('active');
				});	
				   if (document.getElementsByName('gender').checked = true) {
					  if(document.getElementById('sm').checked) {   		
	     	 	      document.querySelector('#sm'+this.getAttribute('href').slice(1)).classList.add('active');				  
					  } 
					  if ((document.getElementById('sp').checked) || (document.getElementById('spr').checked))  {
					  document.querySelector('#sp'+this.getAttribute('href').slice(1)).classList.add('active');
					  } 
					  };
					if (document.getElementsByName('gender2').checked = true) {
					  if (document.getElementById('linol').checked)  {
					  document.querySelector('#p'+this.getAttribute('href').slice(1)).classList.add('active');
					  }};					  
                	  return false;  
				}, false);    
			}); 
</script>


Добавились input radio с другим name (gender2) - это выбор пола. Так вот, первая часть со стенами работает, а с полом нет. Знаю, что вы сейчас надо мной будете смеяться ;) но все, я не могу никак и так и сяк пробовала.
А пример можно посмотреть на этой странице http://www.laminar.ru/test/

laimas 01.02.2016 15:22

Цитата:

Сообщение от Heny
грубо говоря планировщик интерьера

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

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

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

Heny 02.02.2016 06:16

Извини пожалуйста, за возможно глупые вопросы. А это можно сделать через запросы к базе mysql, в которой создать как раз эти таблицы, и php?

laimas 02.02.2016 07:09

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

Heny 02.02.2016 09:55

Глупый, потому что логику понимаю, а делать не очень представляю как :-E
ну ничего, буду учиться

Heny 03.02.2016 14:16

начала пробовать, вот сразу проблема)))
как удалить именно div блок при клике на ссылку
$( 'ссылка с id #steny' ).click(function () {
// При клике на steny "стены" мы должны удалить 
// все имеющиеся значения в все допустимые значения div c id #p, #pt, #ob

$( '#p, #pt, #ob' ).find( 'div:not(:first)' ) // Ищем все теги, не являющиеся тегом по умолчанию
.remove() // Удаляем эти теги
// Изменим значение свойства disabled объектов,
// так как мы работаем с ними через библиотеку jQuery
.end() // Возвращаемся к исходному объекту
.prop( 'disabled',true ); // Делаем неактивными
// Сохраним выбранное значение списка в переменную
var type_id = $( this ).val();
// Если выбрано значение по умолчанию, ничего не делаем
if (type_id == 0) { return; }
....

Не правильно же, disabled используется только в полях списков?

laimas 03.02.2016 15:03

Цитата:

Сообщение от Heny
как удалить именно div блок при клике на ссылку

Поясните "зачем удалить" и почему "по ссылке"? Если вы пробуете то, что "получать динамически из базы наборы", то могу уверить, что удаления чего-то по умолчанию в этом ну просто не должно быть. )

Heny 04.02.2016 09:08

а что должно? может есть какой-нибудь урок на эту тему? а то я как ежик в тумане, не иначе(

Вот я такой урок нашла, и по нему начала делать
http://www.lezhenkin.ru/examples/php/dynamic-select/

laimas 04.02.2016 11:09

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

Допустим, в базе хранятся некие панели, которые пользователь выбрал. Сервер вернул все что имеется, какие есть материалы текстур и какие текстуры.

<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
<style>
ul {
    padding: 0;
}

label {
    display: block;
} 

li {
    list-style: none;
    padding: 2px;
    margin-bottom: 1px;
    border: 1px solid #eee;
}

li, li * {
    cursor: pointer;
}

li:hover {
    border-color: #ccc;
    background-color: #eee;
}
</style> 
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script> 
$(function() {
    //объект из возвращенным сервером данных 
    var data = {
        'wood' : [['pine', 'Сосна', 250, '1.img'], ['oak', 'Дуб', 300, '2.img'], ['birch', 'Береза', 350, '3.img']],
        'rock' : [['granite', 'Гранит', 400, '4.img'], ['marble', 'Мрамор', 450, '5.img']]
    };
    
    $('#map input').change(function() {
        $('#result').empty();
        $('#texture').html(
            '<ul><li>' + $.map(data[this.value], function(e) {
                return '<label><img src="'+e[3]+'"> <input type="radio" name="texture" data-price="'+e[2]+'" value="'+e[0]+'" /> '+e[1]+'</label>';
            }).join('</li><li>') + '</li></ul>'
        ).on('change', 'input', function() {
            $('#result').text(this.getAttribute('data-price')+' руб.')
        })
    });
});
</script>     
</head> 

<body>
<form autocomplete="off">
<p>Материал</p>
<div id="map">
<label><input type="radio" name="map" value="wood" /> Дерево</label>
<label><input type="radio" name="map" value="rock" /> Камень</label>
</div>
<p>Текстура</p>
<div id="texture"></div>
</form>
<p>Выбор</p>
<div id="result"></div>
</body> 
</html>


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

Сам объект представляет простой набор данных, но если данные не только для калькулятора и не пассивного, но и определяют выбор пользователя, который и просчитывается, и будет в конечном итоге отправлен серверу, то элементы выбора: списки, кнопки, флажки и т.п. обязательно должны иметь имена, значения которых также должны быть переданы сервером (ключ => значение), так как они должны быть связаны с SQL таблицами.

Heny 04.02.2016 13:48

Спасибо огромное!!! Села разбираться :dance:

Heny 05.02.2016 11:10

Вот сижу разбираюсь, и вопрос за вопросом)))
Вот у меня такие значения массива steny к примеру:
'steny' : [['sm', 'Металл', 'sm1013', '1013.png', '1013.png'], ['sm', 'Металл', 'sm1015', '1015.png', '1015.png'], ['sp', 'Пластик', 'sp1013', '1013.png', '1013.png']],...
При таком выводе:
$('#steny').html(
            '<div class="panel1"><h3 class="widget-title">Материал стен</h3><div class="radio">' + $.map(data[this.value], function(e) {
                return '<input type="radio" name="steny" data-price="'+e[2]+'" value="'+e[0]+'" /><label> '+e[1]+'</label>';
            }).join('') + '</div>'

Он выводит все привсе элементы массива. А подскажите как можно сделать выборку из элементов и вывести по одному разу название для радиокнопки - "Металл" и "Пластик" из массивов (sm и sp) без повторений?
Чтобы потом уже при клике на эту радиокнопку со значением, выстраивать рядом кнопки с цветом....

laimas 05.02.2016 11:54

Wall - еще понятно, стена, но если steny да еще moi_dlya_rashetov.... ну это нечто :D

Не копируйте то, что я пишу, это пример к рассуждению, хотя UL->LI для представления будет удобен, но ведь необязательно как список, моно же как галерея изображений с выбором, да и выводить ее не обязательно так, тут большую роль будет играть структура данных, и для реального случая вряд ли такая будет. Если имя всех полей "steny" еще можно терпеть, но чтобы значение полей было "sm", "sp", это уже не годится. Расшифруйте для начала значение каждого из элементов массива:

'steny' - что это?
'sm', 'sp' - что это?
'Металл' - это понятно
'sm1013', 'sp1013' - что это?
'1013.png' - что это?
'1013.png' - почему дубль?

И разъяснить относительно базы, и если возможно структуру и связи данных, хотя есть предчувствие, что все в одну таблицу впихнуто, так?

Heny 05.02.2016 12:22

steny - это вот
var data = {
        'steny' : [['sm', 'Металл', 'sm1013', '1013.png', '1013.png'], ['sm', 'Металл', 'sm1015', '1015.png', '1015.png'], ['sp', 'Пластик', 'sp1013', '1013.png', '1013.png']],

при выводе потом используются так: <div id="steny"></div>

Ой ой, какой тут у меня кошмар))) Сейчас попробую объяснить.
Есть 3 вида стеновых панелей:
- металл
- пластик импортный
- пластик российский
У всех этих панелей одинаковый выбор цветов (1013,1015,1019... - это коды цветов). 1013.png - это картинка с цветом, sm1013.png - это картинка самих панелей определенного материала и цвета.
sm - стены металл; sp - стены пластик.
Так вот, я хочу, чтобы из объектов массива 'steny' : [['sm', 'Металл', 'sm1013', '1013.png', '1013.png'], ['sm', 'Металл', 'sm1015', '1015.png', '1015.png'], ['sp', 'Пластик', 'sp1013', '1013.png', '1013.png']] сначала выдернуть виды материаллов - для радиокнопок слева (их всего три получается, а элементов около 20), справа вывести цвета возможные (не важно как списком не списком, у меня просто ссылки были), а потом при нажатии на цвета, чтоб была выборка по массиву, чтоб совпал код цвета (например 1013) и материал (sp или sm) воооооот и открывалась соответствующая картинка (например sp1013.png)

Я понимаю, как глупо выглядят мои вопросы, но уж извините меня такую неуч :( Я вся уже замаялась

laimas 05.02.2016 16:04

Все не так. Начинается все с проектирования базы данных и если говорить даже только о стеновых панелях, то они есть: фасадные, для кухонь и ванных, металл, МДФ, ДВП, характеризуются по ширине, высоте, толщине, различных текстур, производитель, и т.д., и т.п., и конечно же имеют цену.

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


Таблица материалов, в которую всегда легко добавить новый, и каждая запись в ней не под "sm" и "sp", а под уникальным идентификатором который формируется автоматически средствами самой базы. И это число, по которому SQL сделает выборку, отфильтрует или отсортирует данные гораздо проворнее, нежели копаясь с "sm", "sp" и еще бог весь чем.

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

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

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

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

Выбор пользователя при этом будет возвращать значения полей формы как идентификаторы наборов и под именами/ключами, которые указывают на поле SQL таблицы, которым принадлежат эти идентификаторы. А это значит, что данные на клиенте должны представлять собой объект не с массивами (как в примере, что вы пытаетесь использовать), а с объектами, или в случае последовательного получения различных характеристик панелей, каждый ответ сервера, это объект на клиенте, из которого строится очередной список.

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

Если вам кажется, что это сложно и слишком громоздко, а проще "sm", "sp" и так мне удобнее ибо легче запомнить, то это заблуждение. Одно понятие "человеческий фактор" может превратить эту кажущуюся простоту в причину мучений.

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

Вот типа такого.

Heny 10.02.2016 08:25

Сижу ковыряю, ковыряю. И снова какая-то нелепая ошибка. Может ткнете носом?
<script type="text/javascript">
	    var btn = document.querySelectorAll('.btn'),
		el = document.querySelectorAll('.el');
		   Array.prototype.forEach.call(btn, function(curr){
			   curr.addEventListener('click', function() {				   
				   Array.prototype.forEach.call(el, function(curr){
					   curr.classList.remove('active');
				});
                 if (document.getElementById('1').onclick = true) { 
                     document.getElementById('steny').classList.add('active');
                     };
                 if (document.getElementById('2').onclick = true) {  
                     document.getElementById('pol').classList.add('active');
                     };
                     return false;        
    }, false);    
}); 
</script>

В html так:
<div class="variant">
       <div class="menu3d">
        <div class="inform">
          <ul> 
              <li id="1" class="btn"><a href="">Стены</a></li>
              <li id="2" class="btn"><a href="">Пол</a></li>
           </ul>
        </div>
       </div>
    <!--Конец Меню-->
    <!--Начало формы -->
      <div class="3d-panel">
      <!--Панель выбора стен-->
      <div id="steny" class="el active">      
      </div>
      <!-- Конец панели выбора стен-->
      <!--Панель выбора пола-->
      <div id="pol" class="el">      
      </div>
      <!-- Конец панели выбора пола-->
</div>

Изначально <div id="steny"> c class="el active", то есть с display=block.
При нажатии на ссылки "стены"/"пол" на секунду появляется панель с полом. А должно быть, чтобы при нажатии на "пол" - "стены" исчезали (удалялся класс active), а полу он добавлялся --> Кароче что-то не то творится(

laimas 10.02.2016 11:39

На форуме с завидным постоянством вопросы по раскрыть/свернуть панель/панели, и много готового. Посмотрите готовое решение, как это правильно делается, без явных указаний на идентификаторы объектов, иначе добавить еще одну панель - переписывать код. Да и id начинающиеся с цифры это вообще-то невалидно.

destus 10.02.2016 11:52

Heny,
объясните, что это за условие, которое на самом деле ни разу не условие
if (document.getElementById('1').onclick = true)


Часовой пояс GMT +3, время: 09:31.