Background function javascript - javascript

I work with javascript. Let's suppose I have the following function in my app:
function verify(cats) {
if ( cats > 20 ) {
// do something
}
}
Supposing i have a button to add cats, I may use that function after every cat adding.
However, i don't like this method.
I want that this function be in the background and is executed automatically when the condition states true
Is there some way to do so ?

Use a setter, that runs on every assignment. Before:
var obj = {};
obj.cats = 10;
obj.cats += 30;
verify(obj.cats); // we don't want to call this each time.
After:
var obj = {
_cats : 0, // private
get cats() { return this._cats; },
set cats(num) {
verify(num); // any verification here
this._cats = num;
}
};
Later, you can do:
obj.cats += 10; // will run verification
obj.cats = 15; // same
Alternatively, you can use a proxy, but those aren't really widely supported by JS engines yet.

How about setInterval()
$(function() {
setInterval(
function verify(cats) {
if ( cats > 20 ) {
// do something
}
}
, 10);
})

Related

Passing values from an object inside a function

I have been working all day trying to pass the value of "returnData.salary" inside the "readData" function to
the object inside the "calculateTax" function which is suppose to take the salary value and calculate state and federal taxes. I am stumped, I can't find anything on the internet which provides a good example for me to work with. The examples are either way to simple or super complex. Any help would be appreciated.
I apologize in advance if I did not submit this question in the correct format. This is my first time asking for help on stackoverflow.
function readForm() {
var returnData = {};
returnData.name = $("#name").val();
returnData.lastName = $("#lastName").val();
returnData.age = $("#age").val();
returnData.gender = $("[name=gender]:checked").val();
returnData.salary = $("#salary").val();
returnData.isManager = $("#isManager").val();
returnData.myTextArea = $("#myTextArea").val();
$("#name2").text(returnData.name);
$("#lastName2").text(returnData.lastName);
$("#age2").text(returnData.age);
$("#gender2").text(returnData.gender);
$("#salary2").text(returnData.salary);
$("#myTextArea2").text(returnData.myTextArea);
if ($(isManager).is(':checked')) {
$("#isManager2").text("Yes");
}
else {
$("#isManager2").text("No");
}
//$("#employeeForm")[0].reset();
} //end of readForm function
function calculateTax() {
console.log("Button Works");
var calculateTax = {
state: function(num) {
num *= 0.09;
return num;
}
, federal: function(num) {
if (num > 10000) {
num *= 0.2;
return num;
}
else {
num * 0.1;
return num;
}
}
, exempt: true
};
}
//Invoke readForm function when the submit button is clicked.
$(document).ready(function () {
$("#btnSubmit").on("click", readForm);
$("#btnCalculate").on("click", calculateTax);
})
</script>
Well, simply put; you can't. Not like this anyway. Or, at least not pass the value to the function directly.
You are using global functions right now, which are not inside a class. If it was inside a class, you could instantiate the class and save it to this (which would be the class' instance). However, I'm assuming classes are a bit over complicated in this case. What you could do, is set variables globally so all functions can use them, like this;
//declare the global variable so it exists for every function
var returnData = {};
function readForm() {
//We do NOT redeclare the "var" again. It's global now.
returnData = {}; //Reset the global variable when this function is called
returnData.name = $("#name").val();
returnData.lastName = $("#lastName").val();
returnData.age = $("#age").val();
returnData.gender = $("[name=gender]:checked").val();
returnData.salary = $("#salary").val();
returnData.isManager = $("#isManager").val();
returnData.myTextArea = $("#myTextArea").val();
//Rest of your function
}
function calculateTax(){
console.log(returnData) //works here
}
Note that you do overwrite global variables, so it's best to reset them on every function call. You might get old data stuck in there, otherwise.

How to declare instance of a class within a instance of class?

I am making a simple hmtl/js game. I'd like to have all the data of the Game in DataofGame. It is like tennis, it is simpler than tennis: there is only set and match. changeinSet is called on click.
But I think i have a problem with private variable so it doesn't work.
Uncaught TypeError: Cannot read property 'WordsoftheGame' of undefined
//Added
document.getElementById('playboutton').addEventListener('click', newGame);
function newGame() {
var DataofGame = new newGameData();
}
// New game
function newGameData() {
this.pointTeam1 = 0;
this.pointTeam2 = 0;
this.WordsoftheGame = ShuffleListe();
this.ASet = new aSet();
}
//How the set is manage ********************
function aSet() {
var oneWord = DataofGame.ListeMot;
// display the word and delete it from the list
document.getElementById('jouer').innerHTML = oneWord[0];
DataofGame.WordsoftheGame.shift();
this.turn = true;
this.score = 0;
}
function changeinSet() {
DataofGame.ASet.score += 1;
//This is the other team's turn:
DataofGame.ASet.turn = !DataofGame.ASet.turn;
};
//shuffle liste
ListOfWords = ['Artiste', 'Appeler', 'Cheval', 'Choisir', 'Ciel', 'Croire', 'Dormir'];
function ShuffleListe() {
data = shuffle(ListOfWords);
return data;
}
function newGameData(){
this.pointTeam1=0;
this.pointTeam2=0;
this.WordsoftheGame= ShuffleListe();
this.ASet=new aSet();
}
//How the set is manage ********************
function aSet(){
var oneWord=DataofGame.ListeMot;
// display the word and delete it from the list
document.getElementById('jouer').innerHTML=oneWord[0];
DataofGame.WordsoftheGame.shift(); // << DataofGame not assigned yet
this.turn=true;
this.score=0;
}
Here when you're accessing DataofGame, it's not yet assigned because you're inside the constructor when calling aSet().
What you want to achieve is not completely clear, but if it's adding an ASet method to your object, you could write something like this:
function newGameData(){
this.pointTeam1=0;
this.pointTeam2=0;
this.WordsoftheGame= ShuffleListe();
this.ASet = function() {
// your code
};
}
NB your coding style for names is a bit messy, you should use uppercases consistently. The usage is to start constructor names with uppercases, the rest in lower cases.
You can let the function return an object with the data or just set the object.
function newGameData(){
return {
pointTeam1 : 0,
pointTeam2 : 0,
WordsoftheGame : ShuffleListe(),
ASet : new aSet()
}
}
But I would recommend to search for how to work with objects in javascript. Maybe this helps:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

Multiple Timers with setTimeInterval

I am facing a problem with setInterval being used in a loop.
I have a function subscribeFeed( ) which takes an array of urls as input.
It loops through the url array and subscribes each url to getFeedAutomatically() using a setInterval function.
so if three URL's are there in the array, then 3 setInterval's will be called.
The problem is
1)how to distinguish which setInterval is called for which URL.
2)it is causing Runtime exception in setInterval( i guess because of closure problem in javascript)
//constructor
function myfeed(){
this.feedArray = [];
}
myfeed.prototype.constructor= myfeed;
myfeed.prototype.subscribeFeed =function(feedUrl){
var i=0;
var url;
var count = 0;
var _this = this;
var feedInfo = {
url : [],
status : ""
};
var urlinfo = [];
feedUrl = (feedUrl instanceof Array) ? feedUrl : [feedUrl];
//notifyInterval = (notifyInterval instanceof Array) ? notifyInterval: [notifyInterval];
for (i = 0; i < feedUrl.length; i++) {
urlinfo[i] = {
url:'',
notifyInterval:5000,// Default Notify/Refresh interval for the feed
isenable:true, // true allows the feed to be fetched from the URL
timerID: null, //default ID is null
called : false,
position : 0,
getFeedAutomatically : function(url){
_this.getFeedUpdate(url);
},
};
urlinfo[i].url = feedUrl[i].URL;
//overide the default notify interval
if(feedUrl[i].NotifyInterval /*&& (feedUrl[i] !=undefined)*/){
urlinfo[i].notifyInterval = feedUrl[i].NotifyInterval;
}
// Trigger the Feed registered event with the info about URL and status
feedInfo.url[i] = feedUrl[i].URL;
//Set the interval to get the feed.
urlinfo[i].timerID = setInterval(function(){
urlinfo[i].getFeedAutomatically(urlinfo[i].url);
}, urlinfo[i].notifyInterval);
this.feedArray.push(urlinfo[i]);
}
}
// The getFeedUpate function will make an Ajax request and coninue
myfeed.prototype.getFeedUpdate = function( ){
}
I am posting the same on jsfiddle
http://jsfiddle.net/visibleinvisibly/S37Rj/
Thanking you in advance
After some prototyping i found a answer ,which has the answer,move the closure outside
function myclass(){
}
myclass.prototype.funone= function(){
var counter =0;
var timerID;
timerID = setInterval( function(){
alert(counter++);
},1000);
}
myclass.prototype.funtwo= function(){
var timerID2;
var counter2 =50;
timerID2 = setInterval( function(){
alert(counter2++);
},2000);
}
myclass.prototype.funthree = function( ){
var urlArray =["google.com","yahoo.com"];
var timeArray =[15000,6000];
var timerID ;
for(var i=0;i<2; i++){
var url = urlArray[i];
var timerinterval = timeArray[i];
timerID = this.register( url,timerinterval);
}
}
myclass.prototype.register = function(url,timerInterval){
var myUrl =url;
var myTimer = timerInterval;
var timerID = setInterval( function(){
alert(myUrl+"with"+ myTimer);
},myTimer);
}
var m = new myclass( );
m.funthree( );
http://jsfiddle.net/visibleinvisibly/Q4SBG/13/
The move the index binding from the setInterval and pass the url and time interval.
It works perfectly
You might want to have a look at this answer (under "The this variable" at the bottom) about what the this value means.
The error in your code may have something to do with using a counter in a loop and creating closures depending on the counter. The simplest way to create such closures is.
for(i=0;i<len;i++){
object.myCallback = (function(counter){
return function(){
doSomethingWith(counter);
}
}(i));
}
When creating closures on the fly like that you should be careful not dragging large or large amounts of variables into the closure scope. The link above and code below shows how to do this safely.
I've changed some of the code to make it simpler and not copy stuff that doesn't need to be copied, the setInterval is setTimeout so it only does it once but it's the same idea.
//constructor
function MyFeed(){
this.feedArray = [];
}
MyFeed.prototype.subscribeFeed =function(feedUrl){
var i=0,urlInfo=[];
feedUrl = (feedUrl instanceof Array) ? feedUrl : [feedUrl];
for (i = 0; i < feedUrl.length; i++) {
feedUrl[i].isEnable=true;
feedUrl[i].called=false;
feedUrl[i].position=0;//not sure what this is supposed to do
//Set the interval to get the feed.
feedUrl[i].timerID = setTimeout(this.closures//changed this to timeout
.getFeedUpdate(this)
,feedUrl[i].notifyInterval||100//changed default value
);
this.feedArray.push(feedUrl[i]);
}
};
// The getFeedUpate function will make an Ajax request and coninue
MyFeed.prototype.getFeedUpdate = function( index ){
console.log("in getFeedUpdate, this is now:",this);
console.log("my feed url object:",this.feedArray[index].url);
};
//limit closure scope, define closure creators here
MyFeed.prototype.closures={
//this.closures.getFeedUpdate(this)
// will return a closure that calls this.getFeedUpdate
// with correct parameters
getFeedUpdate:function(me){
var index = me.feedArray.length;
return function(){
me.getFeedUpdate(index);
};
}
};
//code to test adding single feed
var mf = new MyFeed();
mf.subscribeFeed({
url:"I am last",
notifyInterval:1000
});
//add another single feed
mf.subscribeFeed({
url:"first.com"
});
//and another
mf.subscribeFeed({
url:"second.com"
});
//and add some more feeds in an array of feeds
mf.subscribeFeed([
{
url:"third"
},
{
url:"fifth"
},
{
url:"no, I am last",
notifyInterval:1500
}
]);
Try FireFox with the FireBug plugin or Chrome and press F12 to see the console, when the log statements log something you can click on it to see the details of the logged item. Very helpful to log objects like this or simple values like index

How to store variables: Privileged method, static property

Instead of just saying:
var thing = timeConsumingMethod();
I have my variable hidden in a method like so:
function _thing() {
var thing = timeConsumingMethod() );
return thing;
}
It gets called a number of times. I'm concerned that I'm made things very inefficient. I assume it calls timeConsumingMethod every time (which is unneeded, it's always the same) I call "_thing()" to get my variable.
How do I manage these types of variables in simple efficient way? Is something like this a solution?:
function _thing() {
return _thing.thing
}
_thing.thing = timeConsumingMethod();
Basically, i want the protection of a function and to (ideally0 access my variable using _thing() or something similar, but I only want timeConsumingMethod to run once.
edit: tried this, doesn't work either:
function _thingy() {
var thing = timeConsumingMethod();
}
_thingy.test = function() {
return( _thingy.thing)
}
Why not just:
function SomethingTimeConsuming() { ... }
function LazyThing(sourceFunction) {
this.sourceFunction = sourceFunction;
this.value = null;
this.Value = function() {
if ( this.value == null) this.value = sourceFunction();
return this.value;
}
}
JSFiddle: http://jsfiddle.net/YSAjJ/
Output:
[14:20:20.079] Calling time-consuming function *(1 time)

document.write in function body

I have the following JavaScript function which receives coordinates and returns the nearest tube station:
function coord() {
var metro = new YMaps.Metro.Closest(new YMaps.GeoPoint(<?=getCoords($addr) ?>), { results : 1 } )
YMaps.Events.observe(metro, metro.Events.Load, function (metro) {
if (metro.length()) {
metro.setStyle("default#greenSmallPoint");
var firstStation = metro.get(0);
var tubest = (firstStation.text).split("метро ");
var tube = tubest[1];
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
} else {
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
}
});
}
The value which I need to output as a result of this function execution is the value of the "tube" variable (var tube = tubest[1];). Basically a simple document.write will work. Or a simple return value like:
var tubestation = coord();
However I'm not sure how to achieve this.
You can't have this function return the value, since you're using an observer pattern - which sets up an asynchronous logic to the code. Simply saying, at the time that your coord() function returns, the value is not there yet.
To deal with this, normally you would pass a callback function, then resume your computation there.
Declare your function as:
function coord(callback)
then, after you know the value you want, call the callback with the value:
callback.call(null, tube);
Do it after your if { ... } else { ... } so your callback gets called both on success and on failure (on failure it will pass undefined, you might want to correct it by declaring var tube = null before the if).
then, instead of:
tubestation = coord();
call it like this:
coord(function(tubestation) {
// continuation of your code here
});
You probably won't be able to use document.write since the time to use it would be long past, but you can set the value as the contents of an element that you already generated. You have jQuery in your tags, so it's quite easy:
coord(function(tubestation) {
$('#tube_station').text(tubestation);
});
assuming you have <div id="tube_station"/> somewhere in your HTML.
How about this simple add to that function?
function coord() {
var metro = new YMaps.Metro.Closest(new YMaps.GeoPoint(<?=getCoords($addr) ?>), { results : 1 } )
YMaps.Events.observe(metro, metro.Events.Load, function (metro) {
if (metro.length()) {
metro.setStyle("default#greenSmallPoint");
var firstStation = metro.get(0);
var tubest = (firstStation.text).split("метро ");
var tube = tubest[1];
$('div#myDivResult').html(tube)
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
} else {
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
}
});
}

Categories