флажок типа ввода с метками, запускающими события дважды

#javascript #jquery #html #css

#javascript #jquery #HTML #css

Вопрос:

Я пытаюсь динамически создавать круглые флажки с отметкой, которые добавляются к id="demo" одному нажатию двух кнопок, вызывающих get(data) метод.

Проблема заключается в том, что при одновременном вызове двух кнопок флажок не получает галочку и вызывает вызов getdata(idD '_chckBox') метода дважды или более, как показано в console.log.

Тем не менее, я использую e.preventDefault(); e.stopPropagation(); .

В чем здесь проблема, getdata(idD '_chckBox') вызывается дважды или более, а roundcheckbox не проверяется?

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

каков наилучший и простой способ привязки onclick и onscroll метода в динамических htmls, которые находятся в цикле for, чтобы объект можно было передавать в качестве параметра в вызываемом методе onclick.

index.html

    

     var data0 = [{
            "title": "a"
          },
          {
            "title": "b"
          },
          {
            "title": "c"
          },
          {
            "title": "d"
          },
        ];
        var data1 = [{
            "title": "ads"
          },
          {
            "title": "bd"
          },
          {
            "title": "fc"
          },
          {
            "title": "dg"
          },
        ];
    
     var html = "<div id='parent'   '   'onscroll="loadMoreContent(event)" ></div>";
     $(html ).appendTo('body');
        $(document).on('click', '#btn11', () => {
          get(data0, 'parent');
        })
        $(document).on('click', '#btn00', () => {
          get(data1,'parent');
        })
    
function loadMoreContent(event){
 // gettting server data (data01 ) on ajax call
var data01 = [{
            "title": "aaa"
          },
          {
            "title": "sdw3b"
          },
          {
            "title": "c433"
          },
          {
            "title": "34d"
          },
        ];
get(data01 , idToAppend)
}
        function get(data, idToAppend) {
    
          var html = '';
          html  = '<div class="col-12 parentdiv">';
          $.each(data, function(key, msgItem) {
            var idD = msgItem.title   key;
            html  = '<div class="flLeftBlock"  style="width: 30px;margin-top: 36px;">';
            html  = '<div class="roundCheckboxWidget"  id="'   idD   '_roundCheckboxWidget">';
            html  = '<input   id="'   idD   '_chckBox" class="" type="checkbox" tid="" title="discard">';
            html  = '<label id="'   idD   '_chckBox_label" for="'   msgItem.title   '" ></label> ';
            html  = "amp;nbsp;"   msgItem.title;
            html  = '</div>';
            html  = '</div>';
            html  = '';
          });
          html  = '</div>';
          $('#'  idToAppend).append(html);
    
          $.each(data, function(index, element) {
            var idD = element.title   index;
            const self = this;
            $(document).on('click', '#'   idD   '_chckBox_label', (e) => {
              if (e.target.tagName === "LABEL") {
                e.preventDefault();
                e.stopPropagation();
                console.log('#'   idD   '_chckBox_label');
                getdata(idD   '_chckBox');
              }
            });
          });
        }
    
        function getdata(id) {
          console.log(id);
          $("#"   id).prop("checked", !$("#"   id).prop("checked"));
          return true;
        }  
 .roundCheckboxWidget {
  position: relative;
}

.roundCheckboxWidget label {
  background-color: #ffffff;
  border: 1px solid rgb(196, 196, 209);
  border-radius: 50%;
  cursor: pointer;
  height: 22px;
  left: 0;
  position: absolute;
  top: 0;
  width: 22px;
}

.roundCheckboxWidget label:after {
  border: 2px solid #fff;
  border-top: none;
  border-right: none;
  content: "";
  height: 6px;
  left: 4px;
  opacity: 0;
  position: absolute;
  top: 6px;
  transform: rotate(-45deg);
  width: 12px;
}

.roundCheckboxWidget input[type="checkbox"] {
  visibility: hidden;
}

.roundCheckboxWidget input[type="checkbox"]:checked label {
  /* background-color: #6168e7 !important;
      border-color: 1px solid #6168e7 !important; */
}

.roundCheckboxWidget input[type="checkbox"]:checked label:after {
  opacity: 1;
}

.roundCheckboxWidget input[type="checkbox"]:checked label {
  background-color: #ff5b6a;
  border-color: #ff5b6a !important;
}  
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Alternate click on two buttons without refreshing causing getdata() method call twice. </p>

<button id="btn11" onclick="get()">Try It</button>
<button id="btn00" onclick="get()">Try It2</button>
<div id="demo"></div>  

Комментарии:

1. Вы вызываете getData при каждом нажатии, поэтому два нажатия будут вызываться дважды.

2. почему один щелчок по кнопке запускает события дважды. при нажатии alternate .. флажок также не устанавливается при одновременном нажатии кнопок?

3. Не уверен, что я понимаю. Ваши шаги для воспроизведения, скажем, нажмите на две кнопки. Я вижу, что get (data) вызывается по одному разу для каждого.

4. getdata(idD ‘_chckBox’) вызывается дважды или более, как упоминалось выше.

5. Извините, я сначала не уловил этого, я только что создал ответ, который указывает на ошибку .

Ответ №1:

Здесь есть несколько ошибок.

  1. Вы используете некоторые, id которые не уникальны. Была предпринята попытка сделать их уникальными, но вы использовали массив key , который является статическим. Таким образом, при каждом нажатии кнопки создаются повторяющиеся идентификаторы. Вам нужен счетчик.
  2. Для определения делегированного обработчика событий используется .each() цикл… Что является неправильным пониманием делегирования.
  3. Вы используете функцию для переключения checkbox состояния, когда for= атрибут на label может сделать это без единой строки кода.
  4. loadMoreContent() Функция неясна… Я предположил, что вы хотите «бесконечную прокрутку»… Поэтому вам нужно проверить, достигнут ли нижний край страницы, чтобы вызвать Ajax-запрос… В противном случае вы будете запускать тонны запросов при каждой прокрутке… вверх и вниз!

Итак, вот как это сделать:
   (См. Комментарий в коде)

 // checkbox title arrays
var data0 = [{ "title": "a" }, { "title": "b" }, { "title": "c" }, { "title": "d" }];
var data1 = [{ "title": "ads" }, { "title": "bd" }, { "title": "fc" }, { "title": "dg" }];

// Appends th "parent" div on load.
var html = "<div id='parent'></div>";
$(html).appendTo('body');

// Button handlers
$(document).on('click', '#btn11', () => {
  get(data0,'parent');
})
$(document).on('click', '#btn00', () => {
  get(data1,'parent');
})

// Simulated Ajax request... I assume.
function loadMoreContent(idToAppend){
  // gettting server data (data01 ) on ajax call
  var data01 = [{ "title": "aaa" }, { "title": "sdw3b" }, { "title": "c433" }, { "title": "34d" } ];
  get(data01 , idToAppend)
}

// Main function. It needs a counter to create UNIQUE ids.
var checkbox_counter = 0;
function get(data, idToAppend) {

  var html = '';
  html  = '<div class="col-12 parentdiv">';
  $.each(data, function(key, msgItem) {
    html  = '<div class="flLeftBlock" style="width: 30px;margin-top: 36px;">';
    html  = '<div class="roundCheckboxWidget">';
    html  = '<input id="checkbox_' checkbox_counter '" type="checkbox" tid="" title="discard">';
    html  = '<label for="checkbox_' checkbox_counter '"></label> ';
    html  = "amp;nbsp;"   msgItem.title;
    html  = '</div>';
    html  = '</div>';
    html  = '';
    
    // Increment the checkbox counter
    checkbox_counter  ;
  });
  html  = '</div>';
  $('#'  idToAppend).append(html);
}

// Just to console log the id of the checkbox...
$(document).on('click', 'label', function(){
  var checkbox_id = $(this).prev("[type='checkbox']").attr("id");
  console.log(checkbox_id);
});

// On scroll handler, check if the bottom of the page is reached to load some more...
$(document).on('scroll', function(){
  var scrolled = Math.ceil($(window).scrollTop());
  var viewport_height = $(window).outerHeight();
  var window_full_height = $(document).outerHeight();
  //console.log(scrolled  " "  viewport_height  " "  window_full_height);
  
  if(scrolled   viewport_height == window_full_height){
    console.log("reached the bottom... Loading some more!");
    
    // Call the Ajax request
    loadMoreContent("parent");
  }
});  
 .roundCheckboxWidget {
  position: relative;
}

.roundCheckboxWidget label {
  background-color: #ffffff;
  border: 1px solid rgb(196, 196, 209);
  border-radius: 50%;
  cursor: pointer;
  height: 22px;
  left: 0;
  position: absolute;
  top: 0;
  width: 22px;
}

.roundCheckboxWidget label:after {
  border: 2px solid #fff;
  border-top: none;
  border-right: none;
  content: "";
  height: 6px;
  left: 4px;
  opacity: 0;
  position: absolute;
  top: 6px;
  transform: rotate(-45deg);
  width: 12px;
}

.roundCheckboxWidget input[type="checkbox"] {
  visibility: hidden;
}

.roundCheckboxWidget input[type="checkbox"]:checked label {
  /* background-color: #6168e7 !important;
  border-color: 1px solid #6168e7 !important; */
}

.roundCheckboxWidget input[type="checkbox"]:checked label:after {
  opacity: 1;
}

.roundCheckboxWidget input[type="checkbox"]:checked label {
  background-color: #ff5b6a;
  border-color: #ff5b6a !important;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Alternate click on two buttons without refreshing causing getdata() method call twice. </p>

<button id="btn11" onclick="get()">Try It</button>
<button id="btn00" onclick="get()">Try It2</button>
<div id="demo"></div>  

CodePen

Ответ №2:

С кодом связаны две проблемы:

  • Вы устанавливаете, onclick="get()" а также добавляете click событие с помощью jQuery, чтобы оно запускалось дважды. удалить onclick ="get()"
  • Вторая проблема заключается в том, что при каждом get() вызове он будет добавлять новых click прослушивателей к флажкам. Чтобы предотвратить это, используйте логическое значение в вашем массиве, примените click событие только один раз

 var data0 = [{
    "title": "a"
  },
  {
    "title": "b"
  },
  {
    "title": "c"
  },
  {
    "title": "d"
  },
  false
];
var data1 = [{
    "title": "ads"
  },
  {
    "title": "bd"
  },
  {
    "title": "fc"
  },
  {
    "title": "dg"
  },
  false
];
$(document).on('click', '#btn11', () => {
  get(data0);
})
$(document).on('click', '#btn00', () => {
  get(data1);
})

function get(data) {
  var html = '';
  html  = '<div class="col-12 parentdiv"';
  $.each(data, function(key, msgItem) {
    var idD = msgItem.title   key;
    html  = '<div class="flLeftBlock"  style="width: 30px;margin-top: 36px;">';
    html  = '<div class="roundCheckboxWidget"  id="'   idD   '_roundCheckboxWidget">';
    html  = '<input   id="'   idD   '_chckBox" class="" type="checkbox" tid="" title="discard">';
    html  = '<label id="'   idD   '_chckBox_label" for="'   msgItem.title   '" ></label> ';
    html  = "amp;nbsp;"   msgItem.title;
    html  = '</div>';
    html  = '</div>';
    html  = '';
  });
  html  = '</div>';
  $('#demo').html(html);
  if(data[data.length - 1]) return false;
  
  $.each(data, function(index, element) {
    var idD = element.title   index;
    const self = this;
    if(index === data.length - 1) return false;
    $(document).on('click', '#'   idD   '_chckBox_label', (e) => {
      if (e.target.tagName === "LABEL") {
        e.preventDefault();
        e.stopPropagation();
        //console.log('#'   idD   '_chckBox_label');
        getdata(idD   '_chckBox');
      }
    });
    
  });
  data[data.length -1] = true;
}

function getdata(id) {
  //console.log(id);
  $("#"   id).prop("checked", !$("#"   id).prop("checked"));
  return true;
}  
 .roundCheckboxWidget {
  position: relative;
}

.roundCheckboxWidget label {
  background-color: #ffffff;
  border: 1px solid rgb(196, 196, 209);
  border-radius: 50%;
  cursor: pointer;
  height: 22px;
  left: 0;
  position: absolute;
  top: 0;
  width: 22px;
}

.roundCheckboxWidget label:after {
  border: 2px solid #fff;
  border-top: none;
  border-right: none;
  content: "";
  height: 6px;
  left: 4px;
  opacity: 0;
  position: absolute;
  top: 6px;
  transform: rotate(-45deg);
  width: 12px;
}

.roundCheckboxWidget input[type="checkbox"] {
  visibility: hidden;
}

.roundCheckboxWidget input[type="checkbox"]:checked label {
  /* background-color: #6168e7 !important;
      border-color: 1px solid #6168e7 !important; */
}

.roundCheckboxWidget input[type="checkbox"]:checked label:after {
  opacity: 1;
}

.roundCheckboxWidget input[type="checkbox"]:checked label {
  background-color: #ff5b6a;
  border-color: #ff5b6a !important;
}  
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<p>Alternate click on two buttons without refreshing causing getdata() method call twice. </p>

<button id="btn11">Try It</button>
<button id="btn00">Try It2</button>
<div id="demo"></div>  

Комментарии:

1. data1 и data0 являются динамическими, и мы не можем установить false в качестве последнего элемента, поскольку метод get (data0) будет вызываться n раз с разными данными. Не могли бы вы, пожалуйста, помочь с каким-нибудь общим решением этой проблемы.

Ответ №3:

TL; DR

Отключите обработчики событий перед привязкой нового. Используйте этот код:

$(document).off('click', '#' idD '_chckBox_label').on('click', '#' idD '_chckBox_label', (e) => {

Длинный ответ

Вы не можете использовать e.preventDefault(); e.stopPropagation(); для остановки различных вызовов функций. Вот в чем дело,

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

Что вам здесь нужно, так это,

«удалите существующий обработчик щелчков перед добавлением нового».

Эта строка:

$(document).on('click', '#' idD '_chckBox_label', (e) => { добавляет обработчик событий к метке. Но когда вы снова нажимаете на кнопку, это запускается снова и добавляет другой обработчик событий.

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

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

$(document).off('click', '#' idD '_chckBox_label').on('click', '#' idD '_chckBox_label', (e) => {

Этот код сообщает, что отключите любой предыдущий обработчик щелчков и добавьте новый.

Бонус:

Если у вас есть именованные функции, вы можете удалить определенные обработчики событий, например:

$(document).off(<event_type>, <el_selector>, <event_handler>).on(<event_type>, <el_selector>, <event_handler>);

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

PS: При копировании было несколько опечаток в коде, но я думаю, что запуск кода здесь не стоит на повестке дня 🙂

Ответ №4:

Здесь у вас есть 2 прослушивателя событий щелчка:

 $(document).on('click', '#btn11', () => {
  get(data0);
})
$(document).on('click', '#btn00', () => {
  get(data1);
})
  

Ваша get() функция завершает два $.each() цикла, второй из которых добавляет сюда еще один прослушиватель событий:

 $(document).on('click', '#'   idD   '_chckBox_label', (e) => {
  if (e.target.tagName === "LABEL") {
    e.preventDefault();
    e.stopPropagation();
    console.log('#'   idD   '_chckBox_label');
    getdata(idD   '_chckBox');
  }
});
  

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