29

I have two variables:

var trafficLightIsGreen = false; 
var someoneIsRunningTheLight = false;

I would like to trigger an event when the two variables agree with my conditions:

if(trafficLightIsGreen && !someoneIsRunningTheLight){
    go(); 
}

Assuming that those two booleans can change in any moment, how can I trigger my go() method when they change according to the my conditions?

Byron Sommardahl
  • 12,103
  • 14
  • 68
  • 126

7 Answers7

36

There is no event which is raised when a given value is changed in Javascript. What you can do is provide a set of functions that wrap the specific values and generate events when they are called to modify the values.

function Create(callback) {
  var isGreen = false;
  var isRunning = false;
  return { 
    getIsGreen   : function()  { return isGreen; },
    setIsGreen   : function(p) { isGreen = p; callback(isGreen, isRunning); },
    getIsRunning : function()  { return isRunning; },
    setIsRunning : function(p) { isRunning = p; callback(isGreen, isRunning); }
  };
}

Now you could call this function and link the callback to execute go():

var traffic = Create(function(isGreen, isRunning) {
  if (isGreen && !isRunning) {
    go();
  }
});

traffic.setIsGreen(true);
JaredPar
  • 673,544
  • 139
  • 1,186
  • 1,421
2

The most reliable way is to use setters like that:

var trafficLightIsGreen = false; 
var someoneIsRunningTheLight = false;

var setTrafficLightIsGreen = function(val){
    trafficLightIsGreen = val;
    if (trafficLightIsGreen and !someoneIsRunningTheLight){
        go(); 
    };
};
var setSomeoneIsRunningTheLight = function(val){
    trafficLightIsGreen = val;
    if (trafficLightIsGreen and !someoneIsRunningTheLight){
        go(); 
    };
};

and then instead of assigning a value to a variable, you just invoke the setter:

setTrafficLightIsGreen(true);
Tadeck
  • 117,059
  • 25
  • 140
  • 191
2
//ex:
/*
var x1 = {currentStatus:undefined};
your need is x1.currentStatus value is change trigger event ?
below the code is use try it.
*/
function statusChange(){
    console.log("x1.currentStatus_value_is_changed"+x1.eventCurrentStatus);
};

var x1 = {
    eventCurrentStatus:undefined,
    get currentStatus(){
        return this.eventCurrentStatus;
    },
    set currentStatus(val){
        this.eventCurrentStatus=val;
    }
};
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="create"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
x1.currentStatus="edit"
console.log("eventCurrentStatus = "+ x1.eventCurrentStatus);
console.log("currentStatus = "+ x1.currentStatus);
Avatar
  • 29
  • 2
0

There is no way to do it without polling with setInterval/Timeout.

If you can support Firefox only, you can use https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/watch

Which will tell you when a property of an object changes.

Your best solution is probably making them part of an object and adding getters, setters that you can send out notifications yourself, as JaredPar showed in his answer

Juan Mendes
  • 80,964
  • 26
  • 138
  • 189
0
function should_i_go_now() {
    if(trafficLightIsGreen && !someoneIsRunningTheLight) {
        go();
    } else {
        setTimeout(function(){
            should_i_go_now();
        },30);
    }
}
setTimeout(function(){
    should_i_go_now();
},30);
Haseeb Ibrar
  • 337
  • 4
  • 18
MyStream
  • 2,485
  • 1
  • 14
  • 32
0

You could always have the variables be part of an object and then use a special function to modify the contents of it. or access them via window.

The following code can be used to fire custom events when values have been changed as long as you use the format changeIndex(myVars, 'variable', 5); as compared to variable = 5;

Example:

function changeIndex(obj, prop, value, orgProp) {
    if(typeof prop == 'string') { // Check to see if the prop is a string (first run)
        return changeIndex(obj, prop.split('.'), value, prop);
    } else if (prop.length === 1 && value !== undefined &&
               typeof obj[prop[0]] === typeof value) {
        // Check to see if the value of the passed argument matches the type of the current value
        // Send custom event that the value has changed
        var event = new CustomEvent('valueChanged', {'detail': {
                                                          prop : orgProp,
                                                          oldValue : obj[prop[0]],
                                                          newValue : value
                                                       }
                                                     });
        window.dispatchEvent(event); // Send the custom event to the window
        return obj[prop[0]] = value; // Set the value
    } else if(value === undefined || typeof obj[prop[0]] !== typeof value) {
        return;
    } else {
        // Recurse through the prop to get the correct property to change
        return changeIndex(obj[prop[0]], prop.slice(1), value);
    }
};
window.addEventListener('valueChanged', function(e) {
    console.log("The value has changed for: " + e.detail.prop);
});
var myVars = {};
myVars.trafficLightIsGreen = false;
myVars.someoneIsRunningTheLight = false;
myVars.driverName = "John";

changeIndex(myVars, 'driverName', "Paul"); // The value has changed for: driverName
changeIndex(myVars, 'trafficLightIsGreen', true); // The value has changed for: traggicIsGreen
changeIndex(myVars, 'trafficLightIsGreen', 'false'); // Error. Doesn't set any value

var carname = "Pontiac";
var carNumber = 4;
changeIndex(window, 'carname', "Honda"); // The value has changed for: carname
changeIndex(window, 'carNumber', 4); // The value has changed for: carNumber

If you always wanted to pull from the window object you can modify changeIndex to always set obj to be window.

Steven10172
  • 1,993
  • 4
  • 20
  • 35
0

If you were willing to have about a 1 millisecond delay between checks, you could place

window.setInterval()

on it, for example this won't crash your browser:

window.setInterval(function() {
    if (trafficLightIsGreen && !someoneIsRunningTheLight) {
        go();
    }
}, 1);
Awesomeness01
  • 2,013
  • 1
  • 15
  • 14