¿Hay alguna manera de determinar si el evento de change de un elemento seleccionado fue realizado por el usuario o por código (manipulación dom)?
Tengo un temporizador que establece automáticamente algunos valores seleccionados en función de alguna condición y luego formatea el color seleccionado para indicar "éxito" (cuadro de selección verde).
Debido a que tengo el formulario configurado para activar una solicitud ajax cuando se activa el evento de cambio de selección, lo hace tanto para los cambios basados en el temporizador en las selecciones como para los cambios de selección basados en el usuario.
Solo me gustaría activar ese evento ajax cuando se trata de un cambio de selección basado en el usuario.
es posible?
EDITAR:
Cuando envío el valor de e.isTrusted , dice Undefined en el registro.
Aquí está mi código:
$(document).on('change', 'select', function (e) { e.preventDefault(); console.log(e.isTrusted); // This outputs "Undefined" if (e.isTrusted) { save_review(); console.log("Point status changed by user - Saved"); } else { console.log("Point status changed programmatically - Not Saved"); } });Logré resolver esto en base a una solución que encontré buscando en Google y con la ayuda de las respuestas proporcionadas por la comunidad anteriores.
Cuando se activa el evento basado en el temporizador, ahora le paso un valor booleano (auto_selected):
$("#pt" + value + " option:nth-child(2)").attr('selected', true).trigger('change', [true]);En mi detector de eventos, puedo verificar el valor de ese parámetro:
$(document).on('change', 'select', function (e, auto_selected) { e.preventDefault(); console.log("Auto-selected: " + auto_selected); if (typeof auto_selected == 'undefined' || !auto_selected) { save_review(); console.log("Point status changed by user - Saved"); } else { console.log("Point status changed programmatically - Not Saved"); } });Hay una propiedad llamada isTrusted en el objeto de evento que puede usar para verificar si el evento se desencadena por acción del usuario o por secuencia de comandos.
eso es verdadero cuando el evento fue generado por una acción del usuario y falso cuando el evento fue creado o modificado por un script o enviado a través de EventTarget.dispatchEvent()
if (e.isTrusted) { /* The event is trusted */ } else { /* The event is not trusted */ } si usa jQuery, está dentro de event.originalEvent
if (e.originalEvent && e.originalEvent.isTrusted) { /* The event is trusted */ } else { /* The event is not trusted */ } Si usa select2 , escuche el evento select2:select y event.params.originalEvent.originalEvent (dos eventos originalEvent aquí, parece una mala implementación dentro de la biblioteca)
$('#your-selector').on('select2:select', function(e) { if(e?.params?.originalEvent?.originalEvent) { // user action } else { // programatically trigger } });Revisé un poco la documentación de select2 porque no estaba muy contento con la solución inicial en mi respuesta. Y en realidad proporcionan una solución para eso usando eventos con espacio de nombres.
Limitación del alcance del evento de cambio :
Es común que otros componentes escuchen el evento de
changeo que se adjunten controladores de eventos personalizados que pueden tener efectos secundarios. Para limitar el alcance para notificar solo a Select2 del cambio, use el espacio de nombres de eventos.select2
Me pregunto por qué no sugieren ese como predeterminado en la documentación. Sigo pensando que su forma sugerida (usando la versión sin espacio de nombres) para sincronizar el elemento de select nativo con la representación HTML de select2 es extraña. Porque, ¿por qué el comportamiento predeterminado de cambiar un elemento de entrada mediante programación debería desencadenar un evento de change ?
Entonces, si usa $("select option:nth-child(2)").attr('selected', true).trigger('change.select2'); no activará el evento de change .
$('select').select2(); function commonTaskOnChange() { console.log('commonTask') } $(document).on('change', 'select', function (e) { console.log('selection changed by user') // in case you want to perform some common task for timer and change event commonTaskOnChange(); }) setTimeout(() => { console.log('timer will change selection') // trigger the namespaced change event $("select option:nth-child(2)").attr('selected', true).trigger('change.select2'); // you could still perform some action that the change event has in common by calling a function here commonTaskOnChange(); }, 1000) <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <link href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css" rel="stylesheet" /> <script src="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/js/select2.min.js"></script> <select> <option>1</option> <option>2</option> <option>3</option> </select>