I have this function
$scope.updateValue = function(key, selectedProductname, numberUsed){
var selectedKey = key;
var selectedProductname = selectedProductname;
var numberUsed = numberUsed;
var useageRef = ref.child('/useage/');
var updateObj = $firebase(useageRef);
var myData = {
productName : selectedProductname,
numberUsed : numberUsed
}
var decrementLocation = inventoryRef.child(key + '/amount')
updateObj.$push(myData).then(
decrementLocation.transaction(function (current_value, numberUsed) {
console.log(numberUsed);
return (current_value || 0) - 1;
})
);
}
I pass "numberUsed" into $scope.updateValue and use it inside myData and then push it to the server and there is no problem with that but when I use it at this line "decrementLocation.transaction(function (current_value, numberUsed) {" and then I try to console.log(numberUsed); the console says undefined. Why? and how can I use numberUsed in this line "decrementLocation.transaction(function (current_value, numberUsed) {" ? how to code it successfully?
There is a number of things going on here.
First of all, in the following code:
decrementLocation.transaction(function (current_value, numberUsed) {
console.log(numberUsed);
return (current_value || 0) - 1;
})
You are re-declaring numberUsed as the second parameter of the .transaction() callback function. Thus, whatever numberUsed was outside of this small function does not matter. If you want to use the var from the surrounding function, you would need to do:
decrementLocation.transaction(function (current_value) {
console.log(numberUsed);
return (current_value || 0) - 1;
})
Second of all, there is no closing ; to your .transaction() function. I don't think it will materially affect your operating here, but cannot be sure. This should be run through jslint/jshint.
Third, you are redeclaring numberUsed inside the entire surrounding $scope.updateValue() function.
$scope.updateValue = function(key, selectedProductname, numberUsed){
var numberUsed = numberUsed;
So you are declaring a new variable numberUsed, whose value will be, well, numberUsed, but it is a new var, so it should be set to undefined. If it is set to anything at all, that would be surprising. If you need the var, then you should do:
$scope.updateValue = function(key, selectedProductname, numberUsed){
var nu2 = numberUsed;
or something similar. But even then, why bother to redeclare the var? It is copied by value anyways.
A good linter will catch any of this.
Related
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.
What am I doing wrong, and how can one pass variables to a different function within the same wrapping variable/function.
Example:
function customFunctionWrap(){
this.myVar1 = 0;
this.getCurrentPosition = function(){
if (navigation.geolocation) {
navigator.geolocation.getCurrentPosition(function(position){});
}
},
this.doSomething = function(){ // Works
//Do something, return
this.callWithParams(); //Works
},
//If I remove passing in 'value1',calling it elsewhere works
this.doSomethingWithParams = function(value1){
//Use value1
//Return
},
this.callWithParams = function(){
var value1 = 'xyz'; //Is a variable that changes based on some DOM element values and is a dynamic DOM element
this.doSomethingWithParams(value1); //THROWS TYPEDEF ERROR: this.doSomethingWithParams is not a function
this.getCurrentPosition();
}
};
var local = new customFunctionWrap();
local.doSomething(); //WORKS
I know there is another way to do it and then directly use customFunctionWrap.callWithParams(), but am trying to understand why the former approach is erroring out.
var customFunctionWrap = {
myVar1 : 0,
callWithParams : function(){
}
}
What JS sees:
var customFunctionWrap = (some function)()
returned function is fired, because the last (), so it has to yield/return something, otherwise, like in your code it is "returning" undefined.
So your given code does not work.
The very first fix is to delete last 2 characters from
var customFunctionWrap = (some function)()
to make it return constructor.
The variable cont is being lost in the following:
__factory.setupMenu = function(cont,input,multiSelect,exclusive,popMenu){
var __menu = {multiSelect:multiSelect};
spotter.events.setEventTrigger(input,'change');
__menu.exclusive = {inputs:[],values:exclusive||[],simpleValues:[]};
alert(cont);//<-- is defined here
window.popSelectComponent= cont;//<-- saved it globally to test reference
return function(ajaxResult){
var data = ajaxResult.template.response||[];
var info = {},l=data.length;
while(--l > -1){
info[String(data[l].value)] = data[l].abbr||data[l].name;
}
var textTarget;
alert(window.popSelectComponent);//<-- this is defined as expected
alert(cont);//<-- is now undefined
alert(input);//<-- this is defined as expected
if(!(textTarget = cont.querySelector('[data-pop-selected]'))){textTarget = cont;}
if(!input.popSelectTemplate){
spotter.data.bindElementToInput(textTarget,input,function(content){
content = content.split(',');
var l=content.length;
while(--l > -1){
content[l] = info[content[l]];
}
content = content.join(',');
return (content.length ? content : 'ignore');
});
}
else{
var cont = document.createElement('SPAN');//<-- PROBLEM IS CAUSED HERE. HOISTING IS CAUSING CONT TO BE UNDEFINED AT CLOSURE START
cont.className="multi-select";
cont.appendChild(cont);
//removal function
var remove = (function(input){
return function(e){
var evt = e ? e:window.event;
if (evt.stopPropagation) evt.stopPropagation();
if (evt.cancelBubble!=null) evt.cancelBubble = true;
if(input.value !== input.spotterPopSelectDefaultValue){
input.value = input.value.removeListValue(this.getAttribute('data-id'),',');
spotter.deleteElement(this);
if(input.value === '' && input.value !== input.spotterPopSelectDefaultValue){
input.value = input.spotterPopSelectDefaultValue;
input.eventTriggers['pop-select-change']();
}
}
};
}(input));
input.spotterPopMenuOptions = __menu;
input.addEventListener('pop-select-change',(function(cont, info, template){
return function(){
var HTML = '';
this.value.split(',').forEach(function(val){
HTML += template.replace('$[ID]', val).replace('$[NAME]', info[val]);
});
cont.innerHTML = HTML;
spotter.castToArray(cont.children).forEach(function(el){ console.log('option el',el); el.addEventListener('click',remove,false); });
console.log('input.spotterPopMenuOptions',input.spotterPopMenuOptions);
};
}(cont, info, input.popSelectTemplate.innerHTML)),false);
}
....
So running var func = __factory.setupMenu(...)({template:{}}) I am receiving an error message that cont is undefined while window.popSelectComponent is defined like expected. I tried changing the name of cont thinking I was overlooking something that was changing the value but that did not work either.
After running the function, I check cont in the context that initially created this closure and cont is still defined so it is not a matter of an object reference being lost as far as I can tell.
Perhaps a highly simplified example would make the problem more obvious:
var outer = function(theVariable) {
console.log("In the outer function, theVariable is", theVariable);
var inner = function() {
console.log("In the inner function, theVariable is", theVariable);
if (false) {
var theVariable = 2;
}
};
inner();
}
outer(1)
In the outer function, theVariable is 1
In the inner function, theVariable is undefined
As you have seen, the fact that a different variable with the same name has been declared (even though not initialized) in the inner function hides the properly initialized variable in the outer function that would have otherwise been visible.
You might think that because the variable is declared in a block, it would not affect other parts of the function. No, var is function scoped, not block scope.
This flaw has been addressed in modern versions of Javascript, and the var keyword has been superseded by let, which has the block scope you were expecting. var is kept for backwards compatibility, but you should not use it in new code.
I'm using dajaxice to retrieve a json attribute - that I would like to be global. I'm not sure why my global var is always "undefined":
var recent_id;
$(function(){
recent_id = Dajaxice.ticker.get_home_timeline(get_home_timeline_callback);
alert(recent_id);
});
function get_home_timeline_callback(data){
if(data==Dajaxice.EXCEPTION){
alert('Error! Something happens!');
}else{
var parsed = JSON.parse(data.home_timeline);
var parsed_id = {'parsed_id':parsed[0].id_str};
console.log(parsed_id);
}
return parsed_id;
}
#dajaxice_register
def get_home_timeline(request):
home_timeline = oauth_req(
'http://api.twitter.com/1/statuses/home_timeline.json?count=1',
settings.TWITTER_TOKEN_KEY,
settings.TWITTER_TOKEN_SECRET
)
return simplejson.dumps({'home_timeline': home_timeline })
Is this a bad way to access a var to be used in another ajax function?
Seems like async issue. Modify your get_home_timeline_callback function as following
function get_home_timeline_callback(data){
if(data==Dajaxice.EXCEPTION){
alert('Error! Something happens!');
}else{
var parsed = JSON.parse(data.home_timeline);
var parsed_id = {'parsed_id':parsed[0].id_str};
console.log(parsed_id);
}
//debug
alert(parsed_id);
//since the value has come, now assign it to the global variable
recent_id = parsed_id;
}
It seems like the variable scope issue. The scope of the variable parsed_id is declared within the else statement within the { }, so its scope is within the else statement. And when you return the parsed_id outside the brackets it might be giving undefined.
Go through the scope of variables explanation here
Change your function as shown below.
function get_home_timeline_callback(data)
{
var parsed_id = "";
if(data==Dajaxice.EXCEPTION)
{
alert('Error! Something happens!');
}
else
{
var parsed = JSON.parse(data.home_timeline);
parsed_id = {'parsed_id':parsed[0].id_str};
console.log(parsed_id);
}
return parsed_id;
}
Now here the scope of the variable parsed_id can be accessed anywhere within function.
Hope this solves your problem if not sorry. This was my assumption that the scope might be affected.
This should be a simple if statement, but it's not working for me. Essentially, when you click an element, I want that element to be highlighted and the ID to be put into a the variable value. However, if in the situation the same element is clicked twice, I want to value = NULL.
(function($){
$(".list").click(function() {
$(this).toggleClass("hilite");
var temp = $(this).attr('id');
if (value != temp) {
var value = $(this).attr('id');
} else {
value = NULL;
}
});
})(jQuery);
Your primary problem is that you're "hoisting" the value variable by redefining it with the var keyword. This code can also be written more efficiently with a lot less code. This should work:
(function($) {
// somewhere outside click handler
var value = '';
// click handler
$(".list").click(function() {
var id = $(this).toggleClass('hilite').attr('id');
value = (value === id) ? null : id;
/* or if you prefer an actual if/else...
if (value === id) {
value = null;
else {
value = id;
}
*/
});
})(jQuery);
Edit: a couple general comments about the original snippet that might be useful:
NULL should be null
Try not to run the same selector multiple times, or recreate a jQuery object from the same DOM object multiple times - it's much more efficient and maintainable to simply cache the result to a variable (e.g., var $this = $(this);)
Your comparison there is probably "safe", but better to use !== than != to avoid unintentional type coercion.
Not sure how exactly you intended to use value in the original example, but always remember that variables are function-scoped in JavaScript, so your var value statement is hoisting the value identifier for that entire function, which means your assignments have no effect on anything outside that click handler.
You need to declare var value outside the scope of the function, so that its value is maintained across function calls. As it is, the value variable is lost right after it is set, because it goes out of scope.
var value = null;
(function($){
$(".list").click(function() {
$(this).toggleClass("hilite");
var temp = $(this).attr('id');
if (value != temp) {
value = temp;
} else {
value = null;
}
});
})(jQuery);
You could do:
(function($){
var tmp = {};
$(".list").click(function() {
$(this).toggleClass("hilite");
var id = $(this).attr('id');
if (!tmp[id]) {
var value = id;
tmp[id] = true;
} else {
value = NULL;
tmp[id] = false;
}
});
})(jQuery);
In this way you use a tmp object that stores the state for all the different id's
It might not be skipping that statement, you might just be getting a confusion over the implied global "value" and the local "value".
(function($){
$(".list").click(function() {
$(this).toggleClass("hilite");
var temp = $(this).attr('id');
if (value != temp) { // <-----------------Implied global var called "value"
var value = $(this).attr('id'); // <---Local variable valled "value"
} else {
value = NULL; // <---------------------Which one am I
}
});
})(jQuery);
Also, it ought to be value = null as NULL is just an undefined variable.
This should be a working example of both points:
var value = null;
(function($){
$(".list").click(function() {
$(this).toggleClass("hilite");
var temp = $(this).attr('id');
if (value != temp) {
value = $(this).attr('id');
} else {
value = null;
}
});
})(jQuery);
Do you not need to declare value before you use it in the conditional statement?
you aren't setting a value in this function.
var value = "NULL";
(function($){
$(".list").click(function() {
$(this).toggleClass("hilite");
var temp = $(this).attr('id');
if (value != temp) {
value = $(this).attr('id');
} else {
value = "NULL";
}
});
})(jQuery);
The variable value is not defined. And it either needs to be a global variable or you could use jQuery's $('.selector).data() method to attach it to the element:
http://api.jquery.com/data/
I also recommend using !== for the comparison, since that compares the type of the variable as well as the content.