Reputation: 11809
Basically, I have a form submits the selected radio item. To detect the selected item, I used a for-each loop (standard one).
As you can see, I am able to return an object with the value of testVar to be used in another function constructor. However, the value of emotionSelected becomes undefined.
https://codepen.io/aguerrero/pen/PQopxw
var diaryUI = (function() {
var emotionSelected, emotionList, testVar;
emotionList = document.getElementsByName("emotion");
for (var i = 0; i < emotionList.length; i++) {
if (emotionList[i].checked) {
emotionSelected = emotionList[i].value;
break;
}
}
testVar = "hello";
return {
getInput: function() {
return {
emotion: emotionSelected,
test: testVar
}
}
}
})();
var mainController = (function(diaryUICtrl) {
var addEntry = function() {
var input = diaryUICtrl.getInput();
console.log(input);
}
document.getElementById("submit-entry").addEventListener("click", addEntry);
})(diaryUI);
However, if I move the for-each loop inside the method getInput, then it works.
What could be wrong?
Upvotes: 3
Views: 90
Reputation: 33726
You're using something called Self-Invoking-Function, so, your initialized objects are being executed before you really submit your form.
(function () {
// body of the function
}());
The anonymous function above will be invoked right after it has been defined. The benefit of self-invoking functions is that they enable us to execute code once without cluttering the global namespace (without declaring any globals). Reference
Run this code snippet to see how your code executes the function diaryUI
immediately.
var diaryUI = (function() {
var emotionSelected, emotionList, testVar;
emotionList = document.getElementsByName("emotion");
for (var i = 0; i < emotionList.length; i++) {
console.log(emotionList[i].checked);
if (emotionList[i].checked) {
emotionSelected = emotionList[i].value;
break;
}
}
testVar = "hello";
return {
getInput: function() {
return {
emotion: emotionSelected,
test: testVar
}
}
}
}
)();
var mainController = (function(diaryUICtrl) {
var addEntry = function() {
var input = diaryUICtrl.getInput();
console.log(input);
}
document.getElementById("submit-entry").addEventListener("click", addEntry);
}
)(diaryUI);
<label for="emotion"></label>
<input type="radio" name="emotion" value="Happy" id="Happy"> Emotion 1<br>
<input type="radio" name="emotion" value="Sad" id="Sad"> Emotion 2<br>
<input type="radio" name="emotion" value="Neutral" id="Neutral"> Emotion 3
<br><br>
<a href="#" id="submit-entry">Submit Diary</a>
See? your code is being executed immediately at start.
You need to rethink how your declaring/implementing your functions.
This approach could help you, but you need to decide if you have to execute that code immediately
var diaryUI = function() {
var emotionSelected, emotionList, testVar;
emotionList = document.getElementsByName("emotion");
for (var i = 0; i < emotionList.length; i++) {
console.log(emotionList[i].checked);
if (emotionList[i].checked) {
emotionSelected = emotionList[i].value;
break;
}
}
testVar = "hello";
return {
emotion: emotionSelected,
test: testVar
}
}
var mainController = (function(diaryUICtrl) {
var addEntry = function() {
var input = diaryUI();
console.log(input);
}
document.getElementById("submit-entry").addEventListener("click", addEntry);
}
)();
<label for="emotion"></label>
<input type="radio" name="emotion" value="Happy" id="Happy"> Emotion 1<br>
<input type="radio" name="emotion" value="Sad" id="Sad"> Emotion 2<br>
<input type="radio" name="emotion" value="Neutral" id="Neutral"> Emotion 3
<br><br>
<a href="#" id="submit-entry">Submit Diary</a>
Upvotes: 1
Reputation: 31024
You are immediately invoking diaryUI
(IIFE) before the click event even happens.
I would pass the diaryUI
as a function reference and invoke it inside the click handler.
by the way, no need to wrap the function with parentheses if its to the right side of the equal sign (=
). It is already an expression.
Running example:
var diaryUI = function() {
var emotionSelected, emotionList, testVar;
emotionList = document.getElementsByName("emotion");
for (var i = 0; i < emotionList.length; i++) {
if (emotionList[i].checked) {
emotionSelected = emotionList[i].value;
break;
}
}
testVar = "hello";
return {
getInput: function() {
return {
emotion: emotionSelected,
test: testVar
};
}
};
};
var mainController = (function(diaryUICtrl) {
var addEntry = function() {
var ctrl = diaryUICtrl();
var input = ctrl.getInput();
console.log(input);
};
document.getElementById("submit-entry").addEventListener("click", addEntry);
})(diaryUI);
<label for="emotion"></label>
<input type="radio" name="emotion" value="Happy" id="Happy"> Emotion 1<br>
<input type="radio" name="emotion" value="Sad" id="Sad"> Emotion 2<br>
<input type="radio" name="emotion" value="Neutral" id="Neutral"> Emotion 3
<br><br>
<a href="#" id="submit-entry">Submit Diary</a>
Upvotes: 1
Reputation:
The function after the assignment operator to dairyUI
is running immediately, which is probably before the DOM is loaded. You probably want to have the DOM selection performed when the getInput
runs instead, which by the way can be done more succinctly.
var diaryUI = (function() {
var testVar = "hello";
return {
getInput: function() {
return {
emotion: (document.querySelector("[name=emotion]:checked") || {}).value,
test: testVar
}
}
}
})();
Upvotes: 1