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.
Related
I have this object:
var registered_screens = {
handle_1 : 'step_1',
handle_2 : 'step_2',
handle_3 : 'step_3'
};
And here's what I tried to get its neighbors:
function get_neighbors( current_step ) {
var steps = {
next: '',
previous: ''
};
for( var i in registered_screens ) {
if( current_step == registered_screens[i] ) {
if(registered_screens.hasOwnProperty(registered_screens[i])) {
steps.next = registered_screens[i+1];
}
if(registered_screens.hasOwnProperty(registered_screens[i-1])) {
steps.previous = registered_screens[i-1];
}
}
}
return steps;
}
Obviously, this is a no-go because an object can't be parsed the same as an array, but just wanted to show what I tried.
What I'd want to get is, if I call get_neighbors('handle_2'), return:
steps { prev : 'handle_1' , next : 'handle_3' }
Or, for get_neighbors('handle_3'):
steps { prev : 'handle_2', next : null }
I've also attempted:
var registered_screens = {
handle_one : 'step_1',
handle_2 : 'step_2',
handle_3 : 'step_3'
};
var key_values = Object.keys(registered_screens);
for( var i = 0; i < key_values.length; i++ ) {
console.log(registered_screens.key_values[i]);
}
But this throws:
main.js?ver=4.9.6:18 Uncaught TypeError: Cannot read property '0' of undefined
main.js?ver=4.9.6:18
main.js?ver=4.9.6:270
Funnily enough, I checked what the values for key_values[i] are and they're the right handles.
It seems JS has a hard time building variables out of strings?
I don't like it much and would look at a restructure to make registered_screens an array. I also would not trust this code due to object order can not be guaranteed.
That said, this will work with my browser.
Edit: Added an array version, which I would trust but would expand for blank (undefined) results.
// array version
var aScreens = [];
aScreens['handle_one'] = 'step_1';
aScreens['handle_2'] = 'step_2';
aScreens['handle_3'] = 'step_3';
function getArrayPrevNext(a,current) {
var x,p = '',n = '',found = false;
for(x in a) {
if (found) {
n = x;
break;
} else if (x == current) {
found = true;
} else {
p = x;
}
}
return {prev:p,next:n};
}
var aSteps = getArrayPrevNext(aScreens,'handle_3');
console.log('array prev['+ aSteps.prev +'], next['+ aSteps.next +']');
var p = aSteps.prev, n = aSteps.next;
console.log('handle prev['+ aScreens[p] +'], next['+ aScreens[n] +']');
console.log('handle alt prev['+ aScreens[aSteps.prev] +'], next['+ aScreens[aSteps.next] +']');
// Object version
var registered_screens = {
handle_one : 'step_1',
handle_2 : 'step_2',
handle_3 : 'step_3'
};
function getPreviousNext(obj,current) {
var prev = '', nxt = '', found = false;
Object.keys(obj).forEach(function(key) {
if (! nxt) {
if (found) {
nxt = key;
} else if (key == current) {
found = true;
} else {
prev = key;
}
}
});
return {prev:prev,next:nxt};
}
var steps = getPreviousNext(registered_screens,'handle_3');
console.log('Object steps:['+ steps.prev +']['+ steps.next +']');
Your second attempt is what I thought as well, it should work fine if you correct the key access like below
var registered_screens = {
handle_one : 'step_1',
handle_2 : 'step_2',
handle_3 : 'step_3'
};
var key_values = Object.keys(registered_screens);
for( var i = 0; i < key_values.length; i++ ) {
console.log(registered_screens[key_values[i]]);
}
As far as I know, the keys in the object are un-ordered and we should not rely on that order, like others have mentioned, it's order will not be the same as when you created, but your requirement seems like it can make use of Object.keys to iterate and find next and prev keys to some extent
To your question, why this registered_screens[key_values[i]] works and not registered_screens.key_values[i], the dot notation will not work for dynamic keys, i.e key_values[i] is not a key, it's a variable holding the key, in such cases you have to access it like an array like Object[keyNameHolder]
This script does a very basic parsing of object keys - it assumes it is always in the format of handle_{n} - based on that it creates an array that holds the keys in proper order, which then is searched for and uses n-1 and n+1 to return prev and next (if possible, else null). And yes i know, most browsers would sort it correctly nonetheless so that in most scenarios you would get the proper order (included a console output for comparison)
var screens = {
handle_1 : 'step_1',
handle_2 : 'step_2',
handle_3 : 'step_3',
handle_4 : 'step_4',
handle_5 : 'step_5',
handle_6 : 'step_6',
handle_7 : 'step_7',
handle_8 : 'step_8',
handle_9 : 'step_9',
handle_10 : 'step_10',
handle_11 : 'step_11',
},
keyParser = (key) => parseInt(key.replace('handle_', '')),
keySorter = (a, b) => keyParser(a) - keyParser(b),
handleKeys = Object.keys(screens).sort(keySorter);
// Compare key ordering in your browser
// It will be most likely identic, since most modern browsers understand that
// it should sort by {str}_{int} and not by {str}_{str} if an {int} is present
// but chances are that for instance IE9 would do the latter, so it could be that
// with browser ordering handle_10 and handle_11 come after handle_1
console.log('browser ordering:', Object.keys(screens));
console.log('parsed ordering:', handleKeys);
function getSteps(handle) {
var pos = handleKeys.indexOf(handle);
if(pos === -1) throw(`Can't find handle ${handle} in screens`);
return {
current: screens[handleKeys[pos]],
prev: pos > 0 ? screens[handleKeys[pos-1]] : null,
next: pos < handleKeys.length-1 ? screens[handleKeys[pos+1]] : null
}
}
console.log(
getSteps('handle_1'),
getSteps('handle_2'),
getSteps('handle_6'),
getSteps('handle_10'),
getSteps('handle_11')
);
Also a good read: https://hackernoon.com/out-of-order-keys-in-es6-objects-d5cede7dc92e
As far as I know the answer is there is no direct way, but you can play around this in many ways.
One idea is that you can play with the naming convention of your data, for example,
call the object items as handle_1 instead of "handle_one" and so on, that
way you can loop around the array using index ['handle_' + i] but notice that you can't do ['handle_' + i + 1] or else you will have a wrong index value because the string conversion will happen before the summation.
I hope this helps.
I made this work:
var registered_screens = {
handle_1 : 'step_1',
handle_2 : 'step_2',
handle_3 : 'step_3'
};
function get_neighbors( current_step ) {
var steps = {
next: '',
previous: ''
};
var key_values = Object.keys(registered_screens);
for( var i = 0; i < key_values.length; i++ ) {
if( current_step == registered_screens[key_values[i]]) {
if( !(registered_screens[key_values[i-1]] == null) ) {
steps.previous = registered_screens[key_values[i-1]];
}
if( !(registered_screens[key_values[i+1]] == null) ) {
steps.next = registered_screens[key_values[i+1]];
}
}
}
return steps;
}
And so, get_neighbors('step_2') reliably (in my tests) returns:
steps : { next : 'step_3', previous: 'step_1' };
I created a quiz as a form, results come after the form has been clicked. Each result comes out as a value. I need the result to populate in a form generated by Marketo (knowledge of marketo not needed right now). So the values need to show up after a click, which is fine, I have the values showing up, but it's the incorrect value.
Can't call to the correct index that corresponds with the value for some reason. Any help?
Form code:
<select id="personaBucket" name="personaBucket" class="mktoField mktoHasWidth mktoRequired" style="width: 300px;">
<option value="">I need to work on...</option>
<option value="Customer">Customer</option>
<option value="Compliance">Compliance</option>
<option value="Continuity">Continuity</option>
</select>
JS (to assign value for quiz result):
if (customer < continuity && customer < compliance) {
result = customer;
} else if (compliance < continuity && compliance < customer) {
result = compliance;
} else if (continuity < compliance && continuity < customer) {
result = continuity;
} else {
result = continuity;
}
grading = [
{score:customer,value:"customer",feedback:"You need to work on customer experience. Fill out the form below to learn more."},
{score:compliance,value:"compliance",feedback:"You need to work on compliance. Fill out the form below to learn more."},
{score:continuity,value:"continuity",feedback:"You need to work on continuity. Fill out the form below to learn more."}
];
JS (to have value correspond to quiz result):
var select = document.getElementById("personaBucket");
var persona = "Persona is: ";
var i;
for (i = 0; i < select.length; i++) {
persona=persona + "\n" + select.options[i].text + " has index: " + select.options[i].index;
}
console.log(persona);
for (i = 0; i < select.length; i++) {
var selectNone = function () {
document.getElementById("personaBucket").selectedIndex = "0";
};
var selectCustomer = function () {
document.getElementById("personaBucket").selectedIndex = "1";
};
var selectCompliance = function () {
document.getElementById("personaBucket").selectedIndex = "2";
};
var selectContinuity = function () {
document.getElementById("personaBucket").selectedIndex = "3";
};
}
for(i=0; i<grading.length; i++) {
if(result == grading[i].score) {
if (grading[i].value = customer) {
selectCustomer ();
}
else if (grading[i].value = compliance) {
selectCompliance ();
}
else if (grading[i].value = continuity) {
selectContinuity ();
}
else {
selectContinuity ();
}
}
}
The index is coming out wrong even though I'm calling to correct index #
EDIT: Got rid of selectIndex, but the biggest issue was that I didn't put "" around my values below and, like Rob mentioned below, replacing the = with ==. So, I replaced this:
for(i=0; i<grading.length; i++) {
if(result == grading[i].score) {
if (grading[i].value = customer) {
selectCustomer ();
}
else if (grading[i].value = compliance) {
selectCompliance ();
}
else if (grading[i].value = continuity) {
selectContinuity ();
}
else {
selectContinuity ();
}
}
}
With this:
for(i=0; i<grading.length; i++) {
if(result == grading[i].score) {
personaVal = grading[i].value;
}
}
if ( personaVal == "customer" ) {
$('#personaBucket').children().remove().end().append('<option selected value="customer">Customer</option>') ;
}
if ( personaVal == "compliance" ) {
$('#personaBucket').children().remove().end().append('<option selected value="compliance">Compliance</option>') ;
}
if ( personaVal == "continuity" ) {
$('#personaBucket').children().remove().end().append('<option selected value="continuity">Continuity</option>') ;
}
Works perfectly now, thanks for the help!
It is much easier just to set value of the <select> than to mess with selectedIndex:
select.value = 'Customer';
While we're at it, all of your functions do pretty much the same exact thing - it would be better to have this be one function that accepts an index and returns another function that contains the index in a closure:
function setSelectValue(val) {
return function() {
select.value = val;
}
}
var selectContinuity = setSelectValue('Customer');
var selectCustomer = setSelectValue('Continuity');
One more thing, assignment is not the same as comparison:
if (grading[i].value = customer) {
Unless customer is falsey, this will always return true since assignment statements return the value that is being set. You should at the very least use == for comparisons, but it is much better to use === to check value and type of the value for equality.
Got rid of selectIndex, but the biggest issue was that I didn't put "" around my values below and, like Rob mentioned, replacing the = with ==. So, I replaced this:
for(i=0; i<grading.length; i++) {
if(result == grading[i].score) {
if (grading[i].value = customer) {
selectCustomer ();
}
else if (grading[i].value = compliance) {
selectCompliance ();
}
else if (grading[i].value = continuity) {
selectContinuity ();
}
else {
selectContinuity ();
}
}
}
With this:
for(i=0; i<grading.length; i++) {
if(result == grading[i].score) {
personaVal = grading[i].value;
}
}
if ( personaVal == "customer" ) {
$('#personaBucket').children().remove().end().append('<option selected value="customer">Customer</option>') ;
}
if ( personaVal == "compliance" ) {
$('#personaBucket').children().remove().end().append('<option selected value="compliance">Compliance</option>') ;
}
if ( personaVal == "continuity" ) {
$('#personaBucket').children().remove().end().append('<option selected value="continuity">Continuity</option>') ;
}
Thanks for all the help!
What is the correct way of breaking out of a nested if statement/for loop? I have tried the following approach but the preferred approach does not work:
service.js - NOT WORKING but better because it breaks out as soon as a match is found
getSelectedService: function(serviceId) {
serviceId = parseInt(serviceId);
for(i=0;i<servicesData.length;i++) {
if(servicesData[i].id === serviceId) {
var service = servicesData[i];
return service;
}
}
}
services.js - WORKING but not good as it loops through everything even when a match is found
getSelectedService: function(serviceId) {
serviceId = parseInt(serviceId);
servicesData.forEach(function(service) {
if(service.id === serviceId) {
var selectedService = service;
}
});
return selectedService;
}
If you want to stop on the first match, you shoud use a while loop.
var keepGoing = true;
var i = 0;
var service;
while( keepGoing && i < servicesData.length ) {
if( servicesData[i].id === serviceId ) {
service = servicesData[i];
keepGoing = false;
} else {
i++;
}
}
return service;
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?
I have an append button which appends endlessly if you click it endlessly.
Lets say i want this button to do this 10 times.
Let me tell you in fantasy code :p what i was thinking so that i can learn from my mistakes; ( i know its wrong but hey im learning)
thismany = 1;
appendbutton.onClick = "thismany = +1";
if{ thismany = <9}
appendbutton.onClick = disabled
thanks in advance
(function(){
var count = 1;
document.getElementById("the_node_id").onclick = function(){
if(count > 10){
return;
}
do_stuff();
count ++;
};
})()
UPDATE:
var count = 1;
addEvent(append, "click", function(/* someargument */){
if(count > 10){
return;
}
// if you need arguments that are passed to the function,
// you can add them to the anonymous one and pass them
// to appendFunction
appendFunction(/* someargument */);
count++;
});
This is straight javascript. You might also consider looking into a framework such as jQuery to make it easier for you.
This assumes your HTML for the button has id="appendButton" as an attribute.
var count = 0;
document.getElementById("appendButton").onClick = function(e) {
if( count >= 10 ) {
return false;
}
else {
count ++;
document.getElementById("id_of_thing_you_append_to").innerHTML += "Whatever you're appending";
}
}
Using your variable names:
var thismany = 0;
appendbutton.onclick = function() {
if (thismany++ < 10) {
// append things
}
};
Variable encapsulated:
appendbutton.onclick = function() {
if (this.count == undefined) {
this.count = 0;
}
if (this.count++ < 10) {
// append things
}
};