Ванильный Javascript: как использовать клонированный узел DOM несколько раз?

Я создаю очень простую корзину.

Он имеет зависимые выпадающие меню и кнопку "Add more products", которая добавит еще один ряд таких же выпадающих меню.

Есть 2 выпадающих меню. 2-е меню должно оставаться disabled до тех пор, пока не будет выбрана опция в 1-м меню. Ввод количества должен быть disabled, пока не будет выбрана опция во 2-м меню. Добавлено количество Add more products включено

Я использую cloneNode(), чтобы добавить код для новой строки.

Поскольку это работает только один раз, я создаю клон каждый раз, когда нажимается кнопка "Add more products", которая вызывает new_products();

Я использую последнюю добавленную строку для создания новой Clone

Новая строка добавляется, но проблема во втором меню, а ввод количества в этой строке уже равен enabled.

Пожалуйста, попробуйте дать решение на ванильном (чистом) JavaScript.

РЕДАКТИРОВАТЬ 1: я прошел половину пути.

Перед добавлением клона я попытался получить доступ к этим элементам и изменить значение атрибута disabled.

In function new_products() :

var order = document.getElementById('order_now');
var product = document.getElementsByClassName('product');
var clone = product[no_of_products-1].cloneNode(true);
clone.getElementsByClassName('second_select')[0].disabled=true;
clone.getElementsByClassName('add_btn')[0].disabled=true;

Но это работало только для второго выпадающего меню.

Это не работает для контроля количества input.

Фрагмент кода:

var productsByCategory = {
  A: ["Select sub-product", "CNC 1", "CNC 2", "CNC 3", "CNC 4"],
  B: ["Select sub-product", "LASER 1", "LASER 2", "LASER 3", "LASER 4"],
  C: ["Select sub-product", "RUBBER 1", "RUBBER 2", "RUBBER 3", "RUBBER 4", "RUBBER 5"],
  D: ["Select sub-product", "PRECISION 1", "PRECISION 2", "PRECISION 3"]
}
var valuesByCategory = {
  A: ["", "A1", "A2", "A3", "A4"],
  B: ["", "B1", "B2", "B3", "B4"],
  C: ["", "C1", "C2", "C3", "C4", "C5"],
  D: ["", "D1", "D2", "D3"]
}

var no_of_products = 1;

function dropdown() {
  var select = document.getElementsByClassName('first_select');
  var selected = select[no_of_products - 1].value;
  var target = document.getElementsByClassName('second_select');
  var targetLength = target[no_of_products - 1].length
  /*console.log("Length"+target.length);*/
  for (var i = targetLength; i >= 0; i--) {
    /*console.log(i);*/
    target[no_of_products - 1].remove(i);
  }
  if (selected == 0) {
    var option = document.createElement("option");
    option.text = "Select Product first";
    option.value = "";
    target[no_of_products - 1].add(option);
    target[no_of_products - 1].disabled = true;
  }
  if (selected == 1) {

    for (var i in productsByCategory['A']) {
      var option = document.createElement("option"); //If this is outside the lopp then only last option gets included.
      option.text = productsByCategory['A'][i];
      option.value = valuesByCategory['A'][i];
      target[no_of_products - 1].add(option);
      target[no_of_products - 1].disabled = false;
    }

  } else if (selected == 2) {
    for (var i in productsByCategory['B']) {
      var option = document.createElement("option");
      option.text = productsByCategory['B'][i];
      option.value = valuesByCategory['B'][i];
      target[no_of_products - 1].add(option);
      target[no_of_products - 1].disabled = false;
    }
  } else if (selected == 3) {
    for (var i in productsByCategory['C']) {
      var option = document.createElement("option");
      option.text = productsByCategory['C'][i];
      option.value = valuesByCategory['C'][i];
      target[no_of_products - 1].add(option);
      target[no_of_products - 1].disabled = false;
    }
  } else {
    for (var i in productsByCategory['D']) {
      var option = document.createElement("option");
      option.text = productsByCategory['D'][i];
      option.value = valuesByCategory['D'][i];
      target[no_of_products - 1].add(option);
      target[no_of_products - 1].disabled = false;
    }
  }
}

function dropdown2() {
  var select = document.getElementsByClassName('second_select');
  var selected = select[no_of_products - 1].value;
  /*console.log(selected);*/
  var submit = document.getElementsByClassName('s_btn');
  submit[no_of_products - 1].disabled = false;
  var add = document.getElementById('add_button');
  add.disabled = false;
}

function new_products() {
  var order = document.getElementById('order_now');
  var product = document.getElementsByClassName('product');
  var clone = product[no_of_products - 1].cloneNode(true);
  clone.getElementsByClassName('second_select')[0].disabled = true;
  clone.getElementsByClassName('add_btn')[0].disabled = true;
  var add = document.getElementById('add_button');

  product[no_of_products - 1].removeChild(add);

  /*console.log(clone);*/

  order.appendChild(clone);

  no_of_products += 1;
}
body {
  height: 100vh;
  margin: 0px;
  overflow-y: auto;
  font-family: 'Roboto';
}

#clear {
  clear: both;
}

.content {
  display: flex;
  background-color: white;
  height: auto;
  margin-top: 0px;
  font-family: 'Roboto';
  z-index: -1;
  min-height: 88%;
}

.link-contents {
  position: relative;
  display: block;
  float: left;
  left: 0px;
  width: 100%;
}

.option-links {
  display: block;
  font-size: 30px;
  cursor: pointer;
}

#op1 {
  background-color: #cccccc;
}

select,
button,
input {
  position: relative;
  top: 5em;
  display: block;
  width: 12em;
  height: 2em;
}

button {
  width: 8em;
}

.first_select {
  position: relative;
  float: left;
  left: 10%;
}

.second_select {
  position: relative;
  float: left;
  left: 20%;
}

.s_btn {
  position: relative;
  float: left;
  left: 30%;
}

.add_btn {
  float: left;
  top: 6em;
  width: 10em;
  left: 5em;
}

.footer {
  display: block;
  max-height: 4%;
}

.option-contents {
  display: none;
}

#order_now {
  display: block;
}
<!DOCTYPE html>
<html>

<head>
  <link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>
  <link rel="stylesheet" type="text/css" href="profile.css">
  <title></title>
</head>

<body>

  <div class="content">
    <div class="link-contents">
      <div class="option-contents" id="order_now">
        <div class="product">
          <select class="first_select" onchange="dropdown();">
            <option value="0">Select</option>
            <option value="1">CNS</option>
            <option value="2">Laser Cut</option>
            <option value="3">Rubber roller</option>
            <option value="4">Fixture</option>
          </select>

          <select class="second_select" onchange="dropdown2();" disabled>
            <option>Select Product first</option>
          </select>
          <input class="s_btn" type="number" min='1' value="1" disabled />
          <br/>
          <button class="add_btn" id="add_button" onclick="new_products();" disabled>Add more products</button>
          <div id="clear"></div>
        </div>
      </div>
    </div>

    <div id="clear"></div>

  </div>

  <div class="footer">
    A big thank you to all of you.
  </div>



</body>
<script type="text/javascript" src="profile.js"></script>

</html>


person Abhay    schedule 09.09.2018    source источник
comment
Как я понял, вновь созданные элементы клона должны иметь: второй элемент select отключен, элемент input отключен и button отключен? Я прав ?   -  person ths    schedule 09.09.2018
comment
@ths да, сэр, вы все правильно поняли.   -  person Abhay    schedule 09.09.2018
comment
Но у вас будут те же ID на странице, что не рекомендуется. Опора на имена классов более точна, поэтому, например, следует удалить добавление button ID, должно остаться только имя класса.   -  person ths    schedule 09.09.2018
comment
@ths В JavaScript я использовал class-names для доступа к 1-му и 2-му выбору. Я использовал ID для доступа к кнопке «Добавить больше продуктов» только потому, что перед клонированием я удалил предыдущую кнопку с помощью removeChild(). Только после его удаления я добавляю клонированный код.   -  person Abhay    schedule 09.09.2018
comment
Но клонированные элементы будут иметь одинаковые ID, даже если вы не использовали их ID в своем коде. Атрибут ID должен быть уникальным на веб-странице.   -  person ths    schedule 09.09.2018
comment
@ths хорошо, сэр, я понял. Я удалю это. Также это решит мою проблему?   -  person Abhay    schedule 09.09.2018
comment
Это не имеет никакого влияния на вашу настоящую проблему. Но как только вы захотите прикрепить прослушиватели событий, например, на основе атрибута ID, то только первый элемент с указанным ID получит тот самый четный слушатель.   -  person ths    schedule 09.09.2018
comment
Добро пожаловать ! о вашей проблеме, попробуйте создать глобальную переменную, которая содержит клон первого .product div, а затем добавьте его, когда захотите.   -  person ths    schedule 09.09.2018
comment
@ths, сэр, я сначала сделал то же самое. Но это работает только один раз. Я искал в Интернете, и везде указано, что такой клон работает только один раз. Таким образом, для многократного добавления необходимо создать несколько клонов.   -  person Abhay    schedule 09.09.2018
comment
Я знаю, что это сработает только один раз, это связано с вашей логикой в ​​​​вашем коде. Попробуйте решить проблему самостоятельно, я тоже буду над этим работать, я могу опубликовать ответ, как только смогу.   -  person ths    schedule 09.09.2018
comment
@ths, сэр, я на полпути. Теперь 2-й выпадающий список получает disabled . Пожалуйста, проверьте РЕДАКТИРОВАТЬ выше фрагмент кода.   -  person Abhay    schedule 09.09.2018
comment
Я работаю над этим, сейчас я отправлю ответ.   -  person ths    schedule 09.09.2018
comment
Я добавил ответ, проверьте его!   -  person ths    schedule 09.09.2018


Ответы (2)


К сожалению, у вас много ошибок в коде. Из-за этого опишу только важные ошибки:

  1. Атрибут id элемента должен быть уникальным на всей HTML-странице. Если вы клонируете какой-то элемент и у него есть атрибут id, вам нужно создать новый id. А так как вы хотите убрать с кнопки атрибут id, я сделал это за вас.
  2. Не используйте element.disable для отключения элемента. Его поддерживает большинство браузеров, но он не является стандартным. Если вы видите документацию для Element и для Node, то вы увидите, что у них нет этого свойства. Некоторые браузеры не поддерживают это. Используйте для этого случая Element.setAttribute() и Element.removeAttribute().
  3. Кнопка для добавления следующей товарной строки не должна находиться в товарной строке.
  4. Не используйте свойство CSS float: left, если оно вам не нужно. В вашем случае вам это не нужно, потому что у вас есть inline-block элементов. Я также изменил много вашего кода CSS.
  5. Не повторяйте свой код снова и снова — это очень плохой стиль программирования. Читайте статью по последней ссылке. Из-за этого я сократил ваш код — написал несколько функций с параметрами.
  6. Обычно лучше использовать метод addEventListener вместо встроенных прослушивателей событий, но в вашем случае это спорно, и из-за этого я не использую addEventListener — чтобы вы могли лучше понять мой код. Но я добавляю в ваши функции один параметр — обратите внимание.

Я написал новый код, чтобы у вас не было ошибок. Наслаждайся этим!

Полное решение

var productsByCategory =
{
    A: ["Select sub-product", "CNC 1", "CNC 2", "CNC 3", "CNC 4"],
    B: ["Select sub-product", "LASER 1", "LASER 2", "LASER 3", "LASER 4"],
    C: ["Select sub-product", "RUBBER 1", "RUBBER 2", "RUBBER 3", "RUBBER 4", "RUBBER 5"],
    D: ["Select sub-product", "PRECISION 1", "PRECISION 2", "PRECISION 3"]
};

var valuesByCategory =
{
    A: ["", "A1", "A2", "A3", "A4"],
    B: ["", "B1", "B2", "B3", "B4"],
    C: ["", "C1", "C2", "C3", "C4", "C5"],
    D: ["", "D1", "D2", "D3"]
};

//var no_of_products = 1; //WE DO NOT NEED IT

function selectHelper(category, targetObj)
{
    for(var i in productsByCategory[category])
    {
        var option = document.createElement("option");

        option.text = productsByCategory[category][i];
        option.value = valuesByCategory[category][i];

        targetObj.add(option);
    }
    
    setEnabled(targetObj);
}

function dropdown(obj)
{
    var selected = obj.value,
        //second select:
        target = obj.nextElementSibling;

    for(var i = target.length; i--; )
        target.remove(i);

    if(selected == 0)
    {
        var option = document.createElement("option");
        option.text = "Select Product first";
        option.value = "";

        target.add(option);
        setDisabled(target);
        //set disabled input field:
        setDisabled(target.nextElementSibling)
    }
    else
    {
        if(selected == 1)
            selectHelper('A', target);
        else if(selected == 2)
            selectHelper('B', target);
        else if(selected == 3)
            selectHelper('C', target);
        else
            selectHelper('D', target)
    }
}

function dropdown2(obj)
{
    setEnabled(obj.nextElementSibling);

    setEnabled(document.getElementsByClassName('add_btn')[0]);
}

function new_products()
{
    var allProducts = document.getElementsByClassName('product');
        lastProduct = allProducts[allProducts.length - 1],
        clone = lastProduct.cloneNode(true);

    setDisabled(clone.getElementsByClassName('second_select')[0]);
    //set disabled input field:
    setDisabled(clone.getElementsByClassName('s_btn')[0]);
    setDisabled(document.getElementsByClassName('add_btn')[0]);

    //may be "insertBefore" is weird, but we do here insert new product after the last product:
    document.getElementById('order_now').insertBefore(clone, lastProduct.nextSibling);
}

function setDisabled(obj)
{
    obj.setAttribute("disabled", "disabled");
}

function setEnabled(obj)
{
    obj.removeAttribute("disabled");
}
body
{
    height: 100vh;
    margin: 0px;
    overflow-y: auto;
    font-family: 'Roboto';
}

.content
{
    background-color: white;
    height: auto;
    margin-top: 0px;
    z-index: -1;
    min-height: 88%;
}

.link-contents
{
    position: relative;
    left: 0px;
    width: 100%;
}

.option-links
{
    display: block;
    font-size: 30px;
    cursor: pointer;
}

#op1 {background-color: #cccccc}

select, button, input
{
    position: relative;
    top: 5em;
    width: 12em;
    height: 2em;
}

button {width: 8em}

.first_select
{
    position: relative;
    left: 10%;
}

.second_select
{
    position: relative;
    left: 20%;
}

.s_btn
{
    position: relative;
    left: 30%;
}

.add_btn
{
    top: 6em;
    width: 10em;
}

.footer
{
    display: block;
    max-height: 4%;
}

.option-contents {display: none}
#order_now {display: block}
<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet'>
<link rel="stylesheet" type="text/css" href="profile.css">

<div class="content">
    <div class="link-contents">
        <div class="option-contents" id="order_now">
            <div class="product">
                <select class="first_select" onchange="dropdown(this)">
                    <option value="0">Select</option>
                    <option value="1">CNS</option>
                    <option value="2">Laser Cut</option>
                    <option value="3">Rubber roller</option>
                    <option value="4">Fixture</option>
                </select>

                <select class="second_select" onchange="dropdown2(this)" disabled>
                    <option>Select Product first</option>
                </select>

                <input class="s_btn" type="number" min='1' value="1" disabled />
            </div>
            <center><button class="add_btn" onclick="new_products()" disabled>Add more products</button></center>
        </div>
    </div>
</div>
<div class="footer">A big thank you to all of you.</div>

person Bharata    schedule 09.09.2018

Чтобы добавлять клон div.product каждый раз, когда нажимается «Добавить больше продуктов» button.add_btn, вам нужно создать глобальную переменную, содержащую клон div.product, который появляется при загрузке страницы (я имею в виду div.product, у которого есть select.second_select, input.s_btn и button.add_btn, которые изначально отключены), затем при нажатии на button.add_btn мы создадим новый элемент div, присвоим ему класс product, затем добавим этот div к div#order_now, затем мы будем использовать атрибут innerHTML клонированного элемента и назначьте его вновь созданному div.

Некоторые замечания и рекомендации

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

  • #P4# <блочная цитата> #P5# #P6#
  • #P7# <блочная цитата> #P8#
  • В моем ответе некоторые переменные из вашего кода больше не будут использоваться как переменная no_of_products, а некоторые другие (надеюсь, вы их сами заметите).

  • Я удалил все лишние атрибуты IDs, в частности button, input и selects, из элементов div.product, потому что ID должен быть уникальным на странице. Кроме того, я удалил все встроенные обработчики событий, так как мы будем использовать метод addEventListener.

  • #P11# <блочная цитата> #P12#
  • #P13# <блочная цитата> #P14#

С учетом всего сказанного, вот работающий фрагмент для иллюстрации:

var productsByCategory = {
    A: ["Select sub-product", "CNC 1", "CNC 2", "CNC 3", "CNC 4"],
    B: ["Select sub-product", "LASER 1", "LASER 2", "LASER 3", "LASER 4"],
    C: ["Select sub-product", "RUBBER 1", "RUBBER 2", "RUBBER 3", "RUBBER 4", "RUBBER 5"],
    D: ["Select sub-product", "PRECISION 1", "PRECISION 2", "PRECISION 3"]
  },
  valuesByCategory = {
    A: ["", "A1", "A2", "A3", "A4"],
    B: ["", "B1", "B2", "B3", "B4"],
    C: ["", "C1", "C2", "C3", "C4", "C5"],
    D: ["", "D1", "D2", "D3"]
  },
  /**
   * create a clone element using 'querySelector' method 
   * which DOESN'T return a 'live node' (it returns a 'static node'), thus gain performance.
   **/
  clone = document.querySelector('.product').cloneNode(true);
/**
 * add event listeners to the body rather than the specific elements
 * thus the dynamically created elements are also supported and catchable by the events.
 * using some checking to get the desired handler function to be called.
 * using the 'call' method, we specify to which element in the handler functions the 'this' keyword refers to. 
 **/
document.addEventListener('change', function(e) {
  (e.target instanceof HTMLSelectElement && ((e.target.classList.contains('first_select') && dropdown.call(e.target)) || (e.target.classList.contains('second_select') && dropdown2.call(e.target))));
  /**
   * the above code is the same as the next but it's faster.

    if (e.target instanceof HTMLSelectElement && e.target.classList.contains('first_select')) {
      dropdown.call(e.target)
    } else if (e.target instanceof HTMLSelectElement && e.target.classList.contains('second_select')) {
      dropdown2.call(e.target)
    }
    
  **/
});
document.addEventListener('click', function(e) {

  (e.target instanceof HTMLButtonElement && e.target.classList.contains('add_btn') && new_products.call(e.target));
  /**
  * the above code is the same as the next but it's faster.
  
    if(e.target instanceof HTMLButtonElement && e.target.classList.contains('add_btn')) {
      new_products.call(e.target);
    }
    
  **/
  
})

/**
* from now on, the handler function use the 'this' keyword to reference the desired element, even the dynamically created ones are supporyted.
* So, 'this' === the argument that passed to the 'call' method.
**/

function dropdown() {

  var selected = this.value;
  var target = this.parentNode.getElementsByClassName('second_select')[0];
  var targetLength = target.length;
  for (var i = targetLength; i >= 0; i--) {
    target.remove(i);
  }
  if (selected == 0) {
    var option = document.createElement("option");
    option.text = "Select Product first";
    option.value = "";
    target.add(option);
    /**
    * you missed to disable the 'button' and the 'input' if the selected value is '0'. 
    **/
    this.parentNode.querySelector('.s_btn').disabled = true;
    this.parentNode.querySelector('.add_btn').disabled = true;
    target.disabled = true;
  } else if (selected == 1) {

    for (var i in productsByCategory['A']) {
      var option = document.createElement("option");
      option.text = productsByCategory['A'][i];
      option.value = valuesByCategory['A'][i];
      target.add(option);
      target.disabled = false;
    }

  } else if (selected == 2) {
    for (var i in productsByCategory['B']) {
      var option = document.createElement("option");
      option.text = productsByCategory['B'][i];
      option.value = valuesByCategory['B'][i];
      target.add(option);
      target.disabled = false;
    }
  } else if (selected == 3) {
    for (var i in productsByCategory['C']) {
      var option = document.createElement("option");
      option.text = productsByCategory['C'][i];
      option.value = valuesByCategory['C'][i];
      target.add(option);
      target.disabled = false;
    }
  } else {
    for (var i in productsByCategory['D']) {
      var option = document.createElement("option");
      option.text = productsByCategory['D'][i];
      option.value = valuesByCategory['D'][i];
      target.add(option);
      target.disabled = false;
    }
  }
}

function dropdown2() {
  this.parentNode.getElementsByClassName('s_btn')[0].disabled = false;
  this.parentNode.getElementsByClassName('add_btn')[0].disabled = false;
}

function new_products() {
  var order = document.getElementById('order_now'),
  /**
  * create a 'div' element which will hold the cloned element's 'innerHTML'.
  **/
      product = document.createElement('div');
  /**
  * give that 'div' element the 'product' class.
  **/
  product.className = 'product';
  /**
  * append that 'div' to the 'div#order_now' element.
  * it's now the last child of the 'div#order_now' element.
  **/
  order.appendChild(product);
  /**
  * assign the cloned element's 'innerHTML' to the newly created 'div' using the 'lastChild' attribute.
  * with that we eliminate the possibility of directly appending the cloned element to 'div#order_now' to run only once.
  **/
  order.lastChild.innerHTML = clone.innerHTML;
  this.parentNode.removeChild(this)
}
body {
  height: 100vh;
  margin: 0px;
  overflow-y: auto;
  font-family: 'Roboto';
}

#clear {
  clear: both;
}

.content {
  display: flex;
  background-color: white;
  height: auto;
  margin-top: 0px;
  font-family: 'Roboto';
  z-index: -1;
  min-height: 88%;
}

.link-contents {
  position: relative;
  display: block;
  float: left;
  left: 0px;
  width: 100%;
}

.option-links {
  display: block;
  font-size: 30px;
  cursor: pointer;
}

#op1 {
  background-color: #cccccc;
}

select,
button,
input {
  position: relative;
  top: 5em;
  display: block;
  width: 12em;
  height: 2em;
}

button {
  width: 8em;
}

.first_select {
  position: relative;
  float: left;
  left: 10%;
}

.second_select {
  position: relative;
  float: left;
  left: 20%;
}

.s_btn {
  position: relative;
  float: left;
  left: 30%;
}

.add_btn {
  float: left;
  top: 6em;
  width: 10em;
  left: 5em;
}

.footer {
  display: block;
  max-height: 4%;
}

.option-contents {
  display: none;
}

#order_now {
  display: block;
}

select,
input {
  display: block !important;
}
<div class="content">
  <div class="link-contents">
    <div class="option-contents" id="order_now">
      <div class="product">
        <select class="first_select">
          <option value="0">Select</option>
          <option value="1">CNS</option>
          <option value="2">Laser Cut</option>
          <option value="3">Rubber roller</option>
          <option value="4">Fixture</option>
        </select>

        <select class="second_select" disabled>
          <option>Select Product first</option>
        </select>
        <input class="s_btn" type="number" min='1' value="1" disabled />
        <br/>
        <button type="button" class="add_btn" disabled>Add more products</button>
        <div id="clear"></div>
      </div>
    </div>
  </div>
  <div id="clear"></div>

Этот пост Stackoverflow может помочь вам узнайте больше о live nodes и static nodes.

Надеюсь, я подтолкнул вас дальше.

person ths    schedule 09.09.2018
comment
Спасибо, сэр, за подробное объяснение. Но есть небольшая ошибка. Попробуйте следующее: после добавления 2-й строки попробуйте изменить параметр 2-го раскрывающегося меню 1-й строки. Выдает эту ошибку --›› Uncaught TypeError: Невозможно установить свойство «отключено» неопределенного - person Abhay; 09.09.2018
comment
@Bharata Мы молодцы, братан! Я использовал свой телефон, когда писал ответ, конечно, нет консоли для проверки. Я думаю, что ваш ответ гораздо более понятен для ОП, так как мой использует продвинутое программирование, хотя я пытался комментировать каждую строку и давать ссылки на документы для каждого из используемых мной расширенных методов/операторов. - person ths; 10.09.2018
comment
Если вы написали это с помощью телефона, то вы как супермен! ;-) Это очень сложно! Прохладно! Хорошая работа! Но не тратьте время на ответы по телефону, потому что с ПК это намного быстрее! ;-) - person Bharata; 10.09.2018
comment
@Bharata, к сожалению, у меня нет компьютера, иногда я одалживаю его у своих братьев на некоторое время. - person ths; 10.09.2018
comment
@ths Я очень ценю твой ответ. Но в случае, если какой-либо другой человек последует за вопросом, проверенный ответ может помочь ему получить наиболее безошибочный ответ, поэтому ему придется изменить проверенный ответ. - person Abhay; 10.09.2018
comment
@ user8810517 мы молодцы, братан. Вам следует принять тот ответ, который вы видите более точным для вас. Я здесь для любой помощи. - person ths; 11.09.2018