1

Lets say I have two hidden form field inputs:

<input id="val1" name="val1" value="0"/>
<input id="val2" name="val2" value="0"/>

Lets say I have a warning DIV with a message that I want to display if both of these inputs have a value of "1"

<div id="myWarningDiv" style="display: none;" class="clswhatever">
    You have done something wrong comrade!
</div>

Now suppose there are many ways to trigger a change one or both of these hidden field values. What I don't want to do is change code on each of these triggers to check if both of these values are "1". Is there a way I can just add a custom event that would just listen for this to happen, without using setInterval or anything clugy like that?

This is a simple example. What I am really looking for is NOT a way to attach an event to a single DOM element, but to create a custom condition that might span mutiple DOM objects, but when triggered would call an event handler function. Heres some pseudo code:

public Boolean onBothTrue() {
   if (document.getElementById("val1").value == "1" && document.getElementById("val2").value == "1") {
       return true;
   }
   else {
       return false;
   }
}
document.addEventListener('onBothTrue',myEventHandler);
function myEventHandler() {
    var elem = document.getElementById("myWarningDiv");
    elem.style.display = "block";
} 
David P
  • 2,027
  • 3
  • 15
  • 27
  • Can you display your attempts of doing this? – NewToJS Mar 03 '15 at 16:12
  • While I have decent experience in javascript, I don't have a lot in custom events, and so I don't know where to start. – David P Mar 03 '15 at 16:16
  • HI EVERYBODY! Thanks for your input. I am thinking now I would like to use CustomEvent and attach it to the form. Also thinking it should be dispatched on form change instead of Window.SetInterval. Thinking I can use a setter function anytime code would update the value abd also fire the custom event. This solution is taking a little bit from everybody. Does this sound right? If so, can somebody post a comprehensive answer so I know who to reward the bounty to? I am not sure how to split a bounty. – David P Mar 10 '15 at 13:00
  • I added another example which should do the trick. – SGD Mar 10 '15 at 19:18

5 Answers5

2

I'd do something like this:

var input1 = document.getElementById('val1');
var input2 = document.getElementById('val2');
var div = document.getElementById('myWarningDiv');

input1.addEventListener('change', check);

input2.addEventListener('change', check);

function check() {
    if (parseInt(input1.value, 10) === 1 && parseInt(input2.value, 10) === 1) {
        div.style.display = 'block';
    } else {
        div.style.display = 'none';
    }
}

EDIT

A form will receive change events from its children, in this case I would attach a change event listener to the parent form and perform the check when any input change, eg:

var form = document.getElementById('form1');
var inputs = form.getElementsByTagName('input');

form.addEventListener('change', check);

function check(event) {
    var element = event.target;
    //convert nodeList to Array
    var inputArray = Array.prototype.slice.call(inputs);
    var conditionMet = true;

    // check all inputs checked
    inputArray.forEach(function (el, index) {
        if (!el.checked) {
            conditionMet = false;   
        }
    });

    // OR 

    // check all inputs with a class "required" are checked
    inputArray.forEach(function (el, index) {
        if (el.className.indexOf('required') !== -1) {
            if(!el.checked) {
                conditionMet = false;
            }
        }
    });

    if (conditionMet) {
        showWarningDiv();
    }
}

function showWarningDiv() {
    // show div
    console.log('show warning');
}

See Fiddle

Joe Fitter
  • 1,309
  • 7
  • 11
  • I was hoping I could add a listener to the BODY or FORM. In my example I could definitely use your example, but my example was extremely simplistic. What if it were more complex (eg - I had 10 inputs and if any 3 of them had values that were <5)? I would have to add listeners to all 10 inputs correct? BTW - if the value of the hidden field is changed by code, will the onchange event be fired? – David P Mar 03 '15 at 16:22
  • 1
    Maybe your question lacks in detail or is too board to answer? People will answer the best they can and this fits the question asked. If you want to expand the question then maybe you should think about your question before posting it? Give a real example or display your attempts and maybe people will have something worth working with. – NewToJS Mar 03 '15 at 16:33
  • I have added some pseudo code to my question to make it more clear as to what I am after. – David P Mar 03 '15 at 17:03
  • In regards to your edited answer - Would the form change event be triggered if one of the input's values was changed by code, and not by user input? Or would I need to setup a setter as Prathik Rajendran suggested? – David P Mar 10 '15 at 12:46
  • No, change events in JS don't fire when elements are programatically changed. If you are going down a jQuery route then $.trigger will suffice, if you are wanting to stick to vanilla JS then you will need to look at createEvent, init the event, and dispatch the event on the element. A good example can be seen in this answer. http://stackoverflow.com/a/25083394/4571952 – Joe Fitter Mar 10 '15 at 12:57
2

The answers provided give good examples of who to do this with or without jQuery. To answer your question about the custom events, you can register it but it as you wrote but it will not fire (because how would it know when). so the only way to do this would be something like:

window.setInterval(function(){
    if (parseInt(input1.value, 10) === 1 && parseInt(input2.value, 10) === 1) {
        // Create the event
        var event = new CustomEvent("bothTrue", { "detail": "Both elements are true which indicates an error" });

        // Dispatch/Trigger/Fire the event
        document.dispatchEvent(event);
    }
}, 500);

There are other posts here which discuss the event handling in native JS (i.e. How to trigger event in JavaScript?)

Update using custom event & change handler:

var input1 = document.getElementById('val1');
var input2 = document.getElementById('val2');
var warningDiv = document.getElementById('myWarningDiv');

function customCondition() {
    if (parseInt(input1.value, 10) === 1 && parseInt(input2.value, 10) === 1) {
        // Create the event
        var event = new CustomEvent("bothTrue", { "detail": "Both elements are true which indicates an error" });
        // Dispatch/Trigger/Fire the event
       document.dispatchEvent(event);
}

input1.addEventListener('change', customCondition);
input2.addEventListener('change', customCondition);

document.addEventListener('bothTrue', function(e){
    warningDiv.style.display = 'block';
});
Community
  • 1
  • 1
SGD
  • 1,676
  • 14
  • 18
  • So there's no way to tell the document just to listen for a certain condition to occur without using a setInterval? – David P Mar 09 '15 at 12:33
  • No, the listener is just what is executed after the event has been fired. What is missing however is the the ability to pass a condition or something like that, so the only really meaningful workaround is using `setInterval` with a not overly complex condition and a reasonable interval set. That is how most frameworks providing such functionality do it as well AFAIK. – SGD Mar 09 '15 at 13:32
  • Too bad. Has this ever been proposed as a new standard? I really like the concept of event driven architecture, but it seems like the whole idea of Custom Events in javascript is a bit of a red herring if you can't tell the browser to raise them without doing a setInterval (basically a timer). – David P Mar 09 '15 at 14:18
  • If I don't hear anything better, I will award you the +50 later today. – David P Mar 09 '15 at 14:19
1

Using jQuery

$("#val1,#val2").change(function() {
 var other = ($(this).get(0).id==="val1")?$("#val2"):$("#val1");
 if($(this).val() == 1 && $(other).val() == 1) {
   $("#myWarningDiv").show();
 } else {
   $("#myWarningDiv").hide();
 }
});

Here is a fiddle for it

https://jsfiddle.net/sx0mg8k1/

Setter to make sure that the change event is triggered every time the value is changed.

$.fn.setVal = function(val) {
    $(this).val(val);
    $(this).trigger('change');
}

Anytime you want to change the value, you would use $("#val1").setVal(0);

Prathik Rajendran M
  • 1,152
  • 8
  • 21
  • If another javascript function changed the value of #val1 or #val2 (as opposed to user input), would your function work? – David P Mar 09 '15 at 12:36
  • User input would trigger a change but I am not sure whether a code input would. You could write a custom setter to be sure that it would trigger a change event. Updated the answer with a jQuery setter which would trigger a change event. – Prathik Rajendran M Mar 09 '15 at 14:25
1

I'll take the same example, using JQuery this is possible by appending a css class to each element, basically inputs .

<input id="val1" name="val1" class="listen"value="0"/>  
<input id="val2" name="val2" class="listen" value="0"/>

JQuery

$(".listen").each(function() {
   $(this).on('change', function(){
   var val=$(this).val();
   alert(val);
   });
});
Abdelghani AINOUSS
  • 190
  • 1
  • 1
  • 11
  • 1
    I've found your solution (using classes) to be the most elegant. However, it still uses the built in 'change' event for the elements which belong to this class. I was hoping to build my own custom event that only triggered when my certain set of conditions were true. If what I was after is not possible please let me know. – David P Mar 09 '15 at 12:27
  • Here is an example how to build your own custom events, [How to Create Custom Events in JavaScript to Program with HTML](http://www.dummies.com/how-to/content/how-to-create-custom-events-in-javascript-to-progr.html) – Abdelghani AINOUSS Mar 10 '15 at 12:09
0

Try

var input = $("input"), message = $("#myWarningDiv"), arr = [], n = 1;
input.each(function(i, el) {
  return $(el).on("input", function(e) {
    arr[i] = Number($(this).val());
    var res = arr.length === input.length ? arr.every(function(value) {
      return value === n
    }) : false;
    return res ? message.show() : message.hide()
  })
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<input id="val1" name="val1" value="0"/>
<input id="val2" name="val2" value="0"/>
<!-- Lets say I have a warning DIV with a message that I want to display 
     if both of these inputs have a value of "1" -->

<div id="myWarningDiv" style="display: none;" class="clswhatever">
    You have done something wrong comrade!
</div>
guest271314
  • 1
  • 15
  • 104
  • 177