callback function in loop to fire only once - javascript

I have a loop, iterating over an object that runs a function with a callback. The problem is I want the callback to only run after all the items have gone through the loop... not each and every time.
$scope.myArray = [];
Object.keys($scope.obj).forEach(function(key) {
var curNode = $scope.obj[key];
if ( curNode ) {
if ( x = 3 ) {
$scope.myArray.push(curNode);
myFunction({
//do something before the callback,
}, myCalback( myArray ) );
}
}
});
$scope.myCallback = function ( arry ) {
//do something ONCE with arry
}

There is also a bug x = 3
'=' is assignment '==' is equality without type comparison.
$scope.myArray = [];
Object.keys($scope.obj).forEach(function(key) {
var curNode = $scope.obj[key];
if ( curNode ) {
if ( x == 3 ) {
$scope.myArray.push(curNode);
myFunction({
//do something before the callback,
});
}
}
});
$scope.myCallback = function ( arry ) {
//do something ONCE with arry
}
$scope.myCalback( $scope.myArray ) ;

Edit:
This won't fire the callback unless there was a matched item and only fires after finished iterating:
$scope.myArray = [];
var run = false;
Object.keys($scope.obj).forEach(function(key) {
var curNode = $scope.obj[key];
if ( curNode ) {
if ( x == 3 ) {
$scope.myArray.push(curNode);
myFunction({
//do something before the callback,
}, function() {run = true} );
}
}
});
$scope.myCallback = function ( arry ) {
//do something ONCE with arry
}
if (run) $scope.myCallback($scope.myArray);

Related

Recursive hasOwnProperty for objects

I have an object as:
const object = {};
object.property1 = 54;
object.property1.property1 = 60;
now I would like to achieve something like this:
if(object.hasOwnProperty('property1')){
//do something
}
else if(object.hasOwnProperty('property1').hasOwnProperty('property1')){
//do something
}
else{
//do something
}
But it fails at the else if part.
why can't we use hasOwnProperty recursively? what is the workaround? I am stuck at this for many hours now.
I have tried to use:
if(object.property1.property1){
//do something
}
but this gives me undefined
So how to get around this situation? Please help!
I would use a recursive function
const object = {};
object.property1 = {};
object.property1.property2 = 60;
if (hasOwnPropertyRecursive(object, 'property2')) {
console.log('yes')
} else {
console.log('no')
}
function hasOwnPropertyRecursive(obj, prop) {
if (typeof obj !== 'object' || obj === null) return false
if (obj.hasOwnProperty(prop)) return true
return Object.getOwnPropertyNames(obj).some(key => hasOwnPropertyRecursive(obj[key], prop))
}
#MisterJojo I am trying to assigning a value
so you may do that this way...
const
objA = {}
, objB = { propX: 'b' }
, objC = { propX: { propX: 'c' } }
;
setLastProp( objA, 'propX', 'x_A' );
setLastProp( objB, 'propX', 'x_B' );
setLastProp( objC, 'propX', 'x_C' );
console.log( 'objA ->', JSON.stringify( objA ));
console.log( 'objB ->', JSON.stringify( objB ));
console.log( 'objC ->', JSON.stringify( objC ));
function setLastProp ( obj, propName, value )
{
let next = obj, prev = obj, count = 0;
while (next.hasOwnProperty(propName))
{
prev = next;
next = next[propName];
};
prev[propName] = value;
}

ng-show/ng-hide limit multiple calls

I am trying to limit the call of ng-hide/ng-show. Currently, what it does is it calls the getLicense function multiple times that will overloads the browser.
$scope.getLicense = function( value ) {
if( $sessionStorage.license === '' ) {
DashboardService.getLicense( ).then( function( data ) {
$scope.licenses = data;
var arr = [ ],
id = '';
for( var i in $scope.licenses ) {
arr.push( [ i ] );
}
$sessionStorage.license = arr;
} );
for( var cnt = 0; cnt < $sessionStorage.license.length; cnt++ ) {
if( $sessionStorage.license[ cnt ] == value ) {
console.log( 'true' );
return true;
break;
} else {
return false;
break;
}
}
} else {
for( var cnt = 0; cnt < $sessionStorage.license.length; cnt++ ) {
if( $sessionStorage.license[ cnt ] == value ) {
console.log('true');
return true;
break;
} else {
console.log('false');
return false;
break;
}
}
}
};
My HTML code looks like this:
<md-list-item class="md-caption" ng-class="{'active': $state.includes('security.webcontrol')}" translate="SIDEBAR.NAV.WEBCONTROL.TITLE" ng-hide="getLicense('web_control_da')">
Giving a function to ng-show / hide / if / etc is a very bad practice.
Each time $digest is called (very often) it check each watcher to see if it has changed. So it will have to execute your function to know if the result is different (or not).
Add a console.log('function executed') in your function getLicense and you will see how often it is called.
To avoid that (like Icycool explained) you have to replace that by a boolean in your scope. And only change the boolean when getLicense should be tested.
For example : If getLicense need to be calculated each time $sessionStorage.license change (for example) :
$scope.licence = getLicense();
$scope.watch("$sessionStorage.license", function (newValue, oldValue){
$scope.licence = getLicense();
});
And in your view/template : ng-hide="licence"
So it will execute your getLicense only when it does really matter.
You can assign it to a scope variable and have ng-hide point to that instead. Call check license on other occasions.

QUEUE and 'IF' 'ELSE' 'WHILE' statements from scratch and running functions

I'm making a game engine in javascript, and needed some way to code some actions.
The code is here:
<!DOCTYPE html> <html> <body> <script>
var engine={}, actions={}; engine.atomStack=new Array();
events = {
1: ["action1|5","action2|2;2","action1|2"],
2: ["action2|5;2","action2|2;2"],
3: ["action2|5;2","action1|2"] };
engine.runatomStack = function(){
while(engine.atomStack.length > 0){
var actionToRun = engine.atomStack.shift();
actionToRun[0](actionToRun[1]); } };
eventActivate = function(event) {
for (var i = 0; i < events[event].length ; i++) {
var actionAndParam = events[event][i].split('|');
translateActions(actionAndParam[0],actionAndParam[1]); } };
engine.action1 = function( param ) {
console.log("executed action 1, param "+param[0]); }
engine.action2 = function( param ) {
console.log("executed action 2, params "+param[0]+" "+param[1]); }
actions.action1 = function( param ) {
var params = param.split(';');
engine.atomStack.push([engine.action1,params]); }
actions.action2 = function( param ) {
var params = param.split(';');
params[1]=parseInt(params[1],10)+2
engine.atomStack.push([engine.action2,params]); }
translateActions = function(action, param) { actions[action](param); };
</script> </body> </html>
Something happens, and I need to run the actions inside an event. I call eventActivate passing the event that should happen. The function translateAction read this information and calls the function that set up the actions. My logic is based that a level contain events, an event can contain actions, and each different action contain atoms.
Example: at some point you call eventActivate(1) and that will push the relative events on the stack. Then from time to time the engine is used and calls engine.runatomStack() to execute whatever is there.
//engine.atomStack is Array [ ]
eventActivate(2)
//engine.atomStack is Array [ Array[2], Array[2] ]
engine.runatomStack()
//prints:
// "executed action 2, params 5 4" example.html:18
// "executed action 2, params 2 4" example.html:18
//engine.atomStack is Array [ ]
Ok, so my engine start to grow and all and now I think I need to add IF/ELSE statements and WHILE/BREAK loops. I have some ideas on implementation but wanted help to what's works best using this queue. Sorry if it's duplicate, but couldn't find help using Google.
I thought something like, if I had events:
4: ["action2|5;2","IF|condition","action2|2;2","END|"]
5: ["action2|5;2","IF|condition","action2|2;2","ELSE|","action1|2","END|"]
I'm not sure how exactly to go, what's works best...
Link to jsFiddle version: http://jsfiddle.net/e3b0kocc/
Ok,
I have a implementation that can solve some stuff, but I think I can't put an if inside another if, which is a problem.
<!DOCTYPE html> <html> <body> <script>
var engine={}, actions={}; engine.atomStack=new Array();
events = {
1: ["action1|5","action2|2;2","action1|2"],
2: ["action2|5;2","if|true","action1|5","else|","action2|2;2","end|"],
3: ["action2|5;2","action1|2"] };
engine.runatomStack = function(){
while(engine.atomStack.length > 0){
var actionToRun = engine.atomStack.shift();
actionToRun[0](actionToRun[1]); } };
eventActivate = function(event) {
for (var i = 0; i < events[event].length ; i++) {
var actionAndParam = events[event][i].split('|');
translateActions(actionAndParam[0],actionAndParam[1]); } };
evalCondition = function( param ){
return false
}
engine.if = function( param ) {
if ( evalCondition(param)) {
var removeActions = false
for (var i = 0; i < engine.atomStack.length ; i++) {
if(engine.atomStack[i][0] == engine.else) {
removeActions = true
}
if(engine.atomStack[i][0] == engine.end) {
return
}
if(removeActions == true){
engine.atomStack.splice(i)
}
}
} else {
var actionToRun =[0,0]
while(engine.atomStack.length > 0 &&
actionToRun[0] != engine.end &&
actionToRun[0] != engine.else ){
var actionToRun = engine.atomStack.shift();
}
}
}
engine.end = function () {}
engine.else = function () {}
engine.action1 = function( param ) {
console.log("executed action 1, param "+param[0]); }
engine.action2 = function( param ) {
console.log("executed action 2, params "+param[0]+" "+param[1]); }
actions.action1 = function( param ) {
var params = param.split(';');
engine.atomStack.push([engine.action1,params]); }
actions.if = function( param ) {
var params = param.split(';');
engine.atomStack.push([engine.if,params]); }
actions.else = function( param ) {
engine.atomStack.push([engine.else,'']); }
actions.end = function( param ) {
engine.atomStack.push([engine.end,'']); }
actions.action2 = function( param ) {
var params = param.split(';');
params[1]=parseInt(params[1],10)+2
engine.atomStack.push([engine.action2,params]); }
translateActions = function(action, param) { actions[action](param); };
</script> </body> </html>
It can be tested it by running
eventActivate(2)
engine.runatomStack()
Modifying evalCondition return value for true will reach different result. Can someone modify the engine.if code to allow if inside if?

Converting an array to cursor

Cursors can be easily converted to arrays using .toArray(foo) method:
var cursor = col.find({});
cursor.toArray(function (err, itemsArray) {
/* do something */
});
But is it possible to convert itemsArray in a cursor so I will have all cursor functions?
var newCursor = foo (itemsArray);
typeof newCursor.toArray === "function" // true
Well it is all just JavaScript so why not create your own iterator:
var Iterator = function () {
var items = [];
var index = 0;
return {
"createCursor" : function (listing) {
items = listing;
},
"next" : function () {
if ( this.hasNext() ) {
return items[index++];
} else {
return null;
}
},
"hasNext" : function () {
if ( index < items.length ) {
return true;
} else {
return false;
}
}
}
}();
So then you use it like this with an array:
var cursor = new Iterator();
cursor.createCursor( array );
cursor.next(); // returns just the first element of the array
So just a general way to write an iterator. If you want more functionality then just add the other methods to the prototype.

how to sync between two functions

I have two functions that I want to call to third function when the other functions( one and two ) will be finished.
I need that the first function and the second function will be called Asynchronous.
for example
var func1 = function( do something..... return arr )
var func2 = function ( do something ..... return arr2 )
if ( arr.length > 0 && arr2.length > 0 )
var func3 = function( do something )
my qeustions:
what is the best way to do it ?
How I call to function in Asynchronous way ?
If you have jQuery, you could use their Deferred objects:
var func1 = function () {
var dfd = $.Deferred();
setTimeout(function () {
// do your processing
dfd.resolve(arr1);
}, 0);
return dfd.promise();
};
var func2 = function () {
var dfd = $.Deferred();
setTimeout(function () {
// do your processing
dfd.resolve(arr2);
}, 0);
return dfd.promise();
};
$.when(func1(), func2()).then(function (arr1, arr2) {
if ( arr.length > 0 && arr2.length > 0 ) {
func3();
}
});
Related questions:
How can jQuery deferred be used?
How can I create an Asynchronous function in Javascript?
Pass the func3 function as a callback and check inside your callback if both arrays are filled.
var func1 = function(callback) ( do something; callback();..... return arr );
var func2 = function(callback) ( do something; callback(); ..... return arr2 );
var func3 = function() {
if(arr != undefined && arr2 != undefined){
//do stuff
}
};
func1(func3);
func2(func3);
var arr1 = [], arr2 = [];
function arraysAreReady() {
if(arr1.length && arr2.length) {
func3();
}
}
var func1 = function() {
var localArray = [];
/// create the local array
arr1 = localArray;
arraysAreReady();
}
var func2 = function() {
var localArray = [];
/// create the local array
arr2 = localArray;
arraysAreReady();
}
func1(); funct2();
when func1 has created the first array it wil assign it to the global variable arr1 and call arraysAreReady() function. when func2 has created the second array it will asign it to the global variable arr2 and call arraysAreReady().
the arraysAreReady() function checks on each call if the 2 global arrays are not empty. Is they are not the it will call the third function (func3)
If your program logic is suitable, you can imitate asynchronous behavior in javascript by doing partial processing and using setTimeout() function as follows:
var result1 = []
var result1Ready = false;
var result2 = []
var result2Ready = false;
func1 = function(list, start, end) {
if(start>=end) {
result1Ready = true;
}
else {
partialEnd = start+10>end ? end : start+10;
for(i=start;i<partialEnd;i++) {
//process 10 items
//append results to array result1
}
//schedule second partial process
setTimeout(function () { func1(list, partialEnd, end); }, 50);
}
};
func2 = function(list, start, end) {
//similar to func1...
};
waitResults = function() {
if(result1Ready && result2Ready) {
func3();
}
else {
setTimeout(function () { waitResults(); }, 50);
}
};
setTimeout(function () { func1(someList, 0, listLength); }, 5);
setTimeout(function () { func2(someOtherList, 0, otherListLength); }, 5);
setTimeout(function () { waitResults(); }, 10);

Categories

Resources