Accesing function within function JavaScript - javascript

I got this piece of code below which is not DRY. What i want to do is to cut it,so everything below var = text would be used only once not twice.
My concept is,to close these two functions in bigger function (e.g. guess()) and keep trimmed correctGuess() and incorrectGuess() within it.
Now here's the question,how can I call such nested function as describe above from outside scope. I was thinking about smth like: guess().correctGuess() which is obviously wrong but I wanted to share a concept.
Additionally, when e.g. correctGuess() would be called, is rest of the commands within our main guess() function would be executed?
function correctGuess(i) {
totalScore++;
questionNumber++;
var text = "Correct!";
var updatePage = ['<div id="answerDiv">' +
'<h1>' + text + '<h1>' +
'<h2>Total Score: ' + totalScore + '</h2></div>'
];
mainContent[html](updatePage);
$('#answerDiv')[fadeIn]("slow");
$('#answerDiv').append('<button id="nextButton">Next Question</button>');
$('#nextButton').on('click', function() {
if (questionNumber == allQuestions.length && totalScore <= 4) {
results()
} else {
question(questionNumber)
}
})
};
var incorrectGuess = function(i) {
totalScore--;
questionNumber++;
var text = "Wrong!";
var updatePage = ['<div id="answerDiv">' +
'<h1>' + text + '<h1>' +
'<h2>Total Score: ' + totalScore + '</h2></div>'
];
mainContent[html](updatePage);
$('#answerDiv')[fadeIn]("slow");
$('#answerDiv').append('<button id="nextButton">Next Question</button>');
$('#nextButton').on('click', function() {
if (questionNumber == allQuestions.length && totalScore <= 4) {
results();
} else {
question(questionNumber);
}
});
};

http://www.w3schools.com/js/js_objects.asp
From your question it seems like you aren't very familiar with object notation. Read up on the above link and then try to create a js "guess" object with 2 member functions. Correct and Incorrect guess.

You need to use the this keyword.
function guess(){
/* do stuff here for guess() */
this.correct = function(){
/* Do stuff for correct */
}
this.wrong = function(){
/* Do stuff for wrong */
}
return this;
}
Because you returned this you can now access the correct() and wrong() functions using:
guess().correct();
// AND
guess().wrong();
Note that whatever code you write inside guess() and outside the two nested functions will also be called every time you call guess().correct() or guess().wrong()
If you do not want any particular code to execute every time they "guess" regardless of right or wrong then I would suggest just storing the correct() and wrong() functions in an object literal.
var guess = {
correct: function(){
// Code for "correct" here
},
wrong: function(){
// Code for "wrong" here
}
}
And then you can access them using
guess.correct();
// AND
guess.wrong();

Related

Update global variable for javascript Calculator

I can't figure out how to update a global variable for a javascript calculator I am working on. I know using eval would make this a lot easier but from what I read online, eval from user input is not advised.
My idea is store the first number until an operation comes is clicked. Once that is clicked, store second number and then see what operation comes up by the user, where it is '=' or '+/*-' do the appropriate action. I have not completed the CE or AC or '.' buttons yet. There's no point in completely that if I can not update the global variable.
Within the function itself, I can change the variable firstNum and secondNum.
From what I have read online, I believe I am not changing the global variable but the local instance of the variable.
I am hoping to be pointed in the right direction to get this done. I attempted to store in the number in an object and later reference that object when I needed to do an operation but I do not believe I did that quite right since I receiving a Reference Error.
Thank you in advance.
var theParent = document.querySelector("#container");
var display = document.querySelector("#display");
theParent.addEventListener("click", doSomething, false);
var reg = new RegExp('^\\d+$');
var result=0;
var symbol='';
var firstNum=0;
var secondNum=0;
function doSomething(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.innerHTML;
if (reg.test(clickedItem)) {
if (display.innerHTML==="0"){
display.innerHTML=clickedItem;
}
else {
display.innerHTML+=clickedItem;
}
}
}
if (clickedItem==='='){
console.log('check firstNum:' +firstNum);
console.log('check symbol:'+ symbol);
console.log('operations return: '+ operations(symbol));
result= operations(symbol);
console.log('result: '+ result);
display.innerHTML=result;
firstNum=result;
secondNum=0;
symbol='';
}
if (!(reg.test(clickedItem))&&symbol===' '&&clickedItem!=='=')
{
symbol=clickedItem;
display.innerHTML='0';
console.log('first op '+ symbol);
}
if (!(reg.test(clickedItem))&&symbol!==clickedItem&&clickedItem!=='=') {
solve(symbol);
symbol=clickedItem;
console.log('second op '+symbol);
}
if (symbol===''){
//firstNum = parseInt(display.innerHTML);
setFirstNum();
console.log("this firstNum in If: " +firstNum)
}
else if (reg.test(clickedItem)){
setSecondNum();
console.log("this secondNum in If: " +secondNum)
}
else {display.innerHTML='0';}
e.stopPropagation();
}
function setFirstNum(){
window.firstNum=parseInt(display.innerHTML);
}
function setSecondNum(){
window.secondNum=parseInt(display.innerHTML);
}
function operations(symbol){
var operation=[{
'+': firstNum + secondNum ,
'-': firstNum - secondNum ,
'÷': firstNum/secondNum ,
'X': firstNum*secondNum
}];
return operation[symbol];
}
function solve(symbol){
result=operations(symbol);
display.innerHTML=result;
firstNum=result;
secondNum=0;
}
You are referencing the global variables fine, the problem is with the global variable theParent. Most of the times, the browser executes the javascript before it loads the document, and hence cannot find any element with id #container.
In order to fix this, you can declare the global variable, and define it on loading the document.
var theParent;
window.onload = function() {
theParent = document.querySelector("#container");
theParent.addEventListener(...);
}
Similarly for the display variable.
Hope this helps.

How to get Javascript object from HTML element

I have 3 "dice" objects created from this custom constructor:
function Dice() {
this.value = 0;
this.keep = false;
this.roll = function() {
this.value = Math.floor(Math.random()*6)+1;
};
}
Then, inside function rollOnce(), I have 3 HTML buttons inside a document.getElementById("paragraph1").innerHTML command that will display each dice's value as follows:
function rollOnce() {
(...)
document.getElementById("paragraph1").innerHTML =
'<button id="diceOne" class="unkept" onclick="keepDice(this.id)">'+dice1.value+'</button> ' +
'<button id="diceTwo" class="unkept" onclick="keepDice(this.id)">'+dice2.value+'</button> ' +
'<button id="diceThree" class="unkept" onclick="keepDice(this.id)">'+dice3.value+'</button> ';
}
Now, function keepDice(diceId) will set attribute class="kept" for each dice/button that has been clicked.
The next thing I want to do is to know which dice variable (dice1, dice2, dice3) has been clicked (in order to keep their value by doing diceN.keep = true;. Because after that there will be another round of the game in which only those dice which are "unkept" will get another diceN.roll() call. But my knowledge is still very limited and I only know how to access (HTML only) elements by using document.getElementsBy(...) (this is the HTML DOM, right? I'm currently learning this at W3Schools).
I have not yet learned about jQuery, AngularJS and all the other cool webdev stuff. So if it is possible to answer using only Javascript it would be much appreciated (even if other libs would make it easier! It's a bonus if there are alternative solutions and I would be happy to learn too!). Is this possible at all?
Thanks in advance,
Maybe something like class="kept-'+dice1.keet+'" onclick="keepDice(1)"
then
function keepDice(index){
dices[index].keep = true;
turns--;
if (turns > 0) {
rollOnce()
}
}
Try this:
function keepDice(id) {
var whichDice;
switch(id) {
case 'diceOne':
whichDice = dice1;
break;
case 'diceTwo':
whichDice = dice2;
break;
case 'diceThree':
whichDice = dice3;
break;
}
whichDice.keep = true;
}
If you stored your dice in an associative array like this:
dice['diceOne'] = new Dice();
dice['diceTwo'] = new Dice();
dice['diceThree'] = new Dice();
you would create the buttons almost the same way
<button id="diceOne" class="unkept" onclick="keepDice(this.id)">dice["diceOne"].value</button>
you could then write your dice function like this
function keepDice(id)
{
dice[id].keep = true;
document.GetElementById(id).setAttribute("class","kept");
//...
}
I came back to this again and realised there's a better way. It's quite a different approach than what you've got so far, but let me explain...
I know your question title is "How to get Javascript object from HTML element" but my answer better serves the question "How to get HTML element from Javascript object" and also better solves the problem you're facing.
First, I set the stage by creating a container element #paragraph1 and a "Roll Once" button which runs the rollOnce() function
<p id="paragraph1"></p>
<button onclick="rollOnce()">Roll Once</button>
Then I create the Dice() Object which takes a parameter - this parameter is the id of the element we wish to use as a container. We must wait for the HTML to load before we can find that container because until then, it simply doesn't exist yet. That's why I have bound a function to the document.onreadystatechange event.
So when the HTML has loaded and the document is ready, I initialise the Object, storing it in a var and the Object has all the required functions built-in for managing it's button.
function Dice(container) {
this.button = document.createElement("button");
this.button.innerHTML = 0;
document.getElementById(container).appendChild(this.button);
this.button.addEventListener('click', function() {
this.className = 'kept';
});
this.roll = function() {
if(this.button.className != 'kept') {
this.button.innerHTML = Math.floor(Math.random()*6)+1;
}
}
}
var dice1;
var dice2;
var dice3;
document.onreadystatechange = function () {
if(document.readyState == "complete") {
dice1 = new Dice("paragraph1");
dice2 = new Dice("paragraph1");
dice3 = new Dice("paragraph1");
rollOnce();
}
}
function rollOnce() {
dice1.roll();
dice2.roll();
dice3.roll();
}
Fully working demonstration is here: http://codepen.io/anon/pen/groEmg
Edit: If you want to get the values of the dice later, you can access the Objects' properties like so: dice1.button.innerHTML
You need to keep track of what has been kept and what has not been kept. It would be useful to hold all the dice functionality inside the dice class. every time you run rollOnce() you must also represent the kept/unkept state in the className.
Here's an example including what I gather is your current initialisation - define var dice then define rollOnce() then run rollOnce()
function Dice() {
this.value = 0;
this.kept = false;
this.roll = function() {
if(!this.kept) this.value = Math.floor(Math.random()*6)+1;
};
this.keep = function(id) {
this.kept = true;
document.getElementById(id).className = 'kept';
}
}
var dice1 = new Dice();
var dice2 = new Dice();
var dice3 = new Dice();
function rollOnce() {
dice1.roll();
dice2.roll();
dice3.roll();
document.getElementById("paragraph1").innerHTML =
'<button id="diceOne" class="'+(dice1.kept?'kept':'keep')+'" onclick="dice1.keep(\'diceOne\')">'+dice1.value+'</button> ' +
'<button id="diceTwo" class="'+(dice2.kept?'kept':'keep')+'" onclick="dice2.keep(\'diceTwo\')">'+dice2.value+'</button> ' +
'<button id="diceThree" class="'+(dice3.kept?'kept':'keep')+'" onclick="dice3.keep(\'diceThree\')">'+dice3.value+'</button> ';
}
rollOnce();
I've made it pass an ID to Dice.keep(id) just to have a live update of the DOM element which represents this Object variable.
Some clarification on the classnames since you're a beginner: I used ternary logic operators to quickly perform an IF THEN ELSE
So the part that says dice1.kept?'kept':'keep'
Actually means IF dice1.kept THEN 'kept' ELSE 'keep'
You can put a blank '' instead of 'keep' if you like since I don't think it's being used (but you might use it for CSS). Of course, there is plenty of room for improvement all over this code, but I wanted to keep it as similar to your sample code as possible. In fact, the first thing I would do is probably change the onclick to this: onclick="dice1.keep(this)" and then change your object like:
this.keep = function(button) {
this.kept = true;
button.className = 'kept';
}
http://codepen.io/anon/pen/MyrxyX
Edit: here's a slightly modified version where the Dice() object is agnostic to the DOM but still provides all the relevant data: http://codepen.io/anon/pen/MyrxbB

Optimal/preferred way to call 'SP.ClientContext.executeQueryAsync' in SharePoint

I have been learning client-side object model and came across the method executeQueryAsync. I found there are quite a few ways to call this method. Some of the one I found were these:
var context = new SP.ClientContext.get_current();
// Option 1
context.executeQueryAsync(
function(sender, args){ },
function(sender, args){ }
);
// Option 2
context.executeQueryAsync(
Function.createDelegate(this, _onSucceed),
Function.createDelegate(this, _onFail)
);
// Option 3
context.executeQueryAsync(
Function.createDelegate(this, this._onSucceed),
Function.createDelegate(this, this._onFail)
);
// Option 4
context.executeQueryAsync(_onSucceed, _onFail);
Which of this way is the most optimal/preferred one? Also what does the statement Function.createDelegate do? The documentation for this function seems to be very cryptic for me.
First I would say there is no 'optimal way' as these all just behave somewhat differently... Second, I would add this isn't so much a SharePoint or executeQueryAsync specific thing as it is a JS thing in general...
Next we need to understand that executeQueryAsync expects two functions as arguments: the first is a function to perform if executeQueryAsync succeeds, the second is a function to perform if the method encounters an error. These functions are passed parameters (from executeQueryAsync, not from your JS) representing the sending object as well as an arguments object that can have some data (args.get_message() and args.get_stackTrace() are common in the case of a failed call)
In your 'Option 1' example, executeQueryAsync is given two anonymous functions, you won't be able to re-use them anywhere, but if the behavior is simple this may be sufficient.
In Option 2 you use the createDelegate method to give the success and failure callbacks a context -- this speaks to scoping within JavaScript; if you need to reference a variable that is only accessible in the function that calls executeQueryAsync, you'll need to use this sort of pattern so that this within the callback references the function that called executeQueryAsync instead of the success or failure function that you're now in. You can think of creating a delegate as the calling function calling on some other function, but saying 'I want that function to be able to see what I can see no matter where it's located at within the code.' This may all seem a bit arcane, but such is scoping within JavaScript... You could completely circumvent the need for doing this by referencing variables at higher scope levels (say inside of a function that contains the calling method as well as the success and failure methods)
Option 3 is just like Option 2, except it just specifies that the _onSucceed or _onFail functions should be the ones that are contained within the calling object
Option4 is just like Option 1, except that you've named the functions (and that they are available within the current scope) and are calling them by name.
I usually use something like option 2, or option 4 -- but I hope you can see that it really just depends on how you're trying to structure your code.
EDIT:
In response to a comment about Function.createDelagate() -- It seems to just be a helper in an ASP.NET script resource; it does nothing other than calling apply() (which is the standard JS way of doing this -- see MDN documentation here). It might also provide some backward compatibility somewhere within ASP.NET, but I'm not really sure!
Here is the code for the function from a script resource file in my SP environment:
Function.createDelegate = function(a, b) {
return function() {
return b.apply(a, arguments)
}
};
And as a bonus, I was thinking about how I use executeQueryAsync and I realized that I actually use it more often like option 1, with a promise pattern using jQuery deferreds like this:
function getSPDataAsync(context) {
var deferred = $.Deferred();
context.executeQueryAsync(function(sender, args) {
deferred.resolve(sender, args);
}, function(sender, args) {
deferred.reject(sender, args);
});
return deferred.promise();
}
Then you can do things a little less-spaghetti-like, such as:
...
ctx.load(items);
getSPDataAsync(ctx).then(function() {
//do some stuff with the data when the promise resolves
});
Just in case anyone cares! :)
Please try the below answer...this should help..Below code uses the context.ExecutequeryAsync method but since the items are captured separately on a string array there should not be any issues with respect to asynchronous behavior..
<style>
table { table-layout: fixed; }
td { width: 50%; }
</style><script type="text/javascript">
function ShowselectedItems() {
var ctx = new SP.ClientContext.get_current();
web = ctx.get_web();
if (ctx != undefined && ctx != null) {
var listId = SP.ListOperation.Selection.getSelectedList();
var oList = ctx.get_web().get_lists().getByTitle('Testform'); // Put your list name here
var selectedItems = SP.ListOperation.Selection.getSelectedItems(ctx);
var camlquerystr = '';
if(selectedItems.length > 0){
if(selectedItems.length == 1)
{
camlquerystr += '<Where><Eq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>' + selectedItems
[0].id + '</Value></Eq></Where>';
}
else if(selectedItems.length == 2)
{
camlquerystr += '<Where><Or><Eq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>' + selectedItems
[0].id + '</Value></Eq><Eq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>' + selectedItems[1].id +
'</Value></Eq></Or></Where>';
}
else
{
var i;
camlquerystr += '<Where>';
for (i = 0; i < selectedItems.length - 1; i++) {
camlquerystr += '<Or><Eq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>' + selectedItems
[i].id + '</Value></Eq>';
}
camlquerystr += '<Eq><FieldRef Name=\'ID\'/><Value Type=\'Number\'>' + selectedItems[i].id +
'</Value></Eq>';
for (i = 0; i < selectedItems.length - 1; i++) {
camlquerystr += '</Or>';
}
camlquerystr += '</Where>';
}
}
else
{
alert('Please select your item');
retrun;
}
var camlQuery = new SP.CamlQuery();
camlQuery.set_viewXml('<View><Query>' + camlquerystr + '</Query></View>');
this.collListItem = oList.getItems(camlQuery);
ctx.load(collListItem, 'Include(Id, Title,Name,First_x0020_Name,Last_x0020_Name)');
ctx.executeQueryAsync(Function.createDelegate(this, this.success), Function.createDelegate(this,
this.failed));
}
}
function success() {
var listItemInfo = '';
var headstr = "<html><head><title></title></head><body>";
var footstr = "</body>";
var content;
var listItemEnumerator = collListItem.getEnumerator();
while (listItemEnumerator.moveNext()) {
var oListItem = listItemEnumerator.get_current();
content += "<table border='1' width='100%' style='table-layout: fixed;'><tr><td>Title:</td><td>" + oListItem.get_item('Title') + "</td></tr><tr><td>Name:</td><td>" + oListItem.get_item('Name') + "</td></tr><tr><td>First Name:</td><td>" + oListItem.get_item('First_x0020_Name') + "</td></tr><tr><td>LastName:</td><td>" + oListItem.get_item('Last_x0020_Name') + "</td></tr></table><br/><br/>";
}
w = window.open("", "_blank", "k");
w.document.write(headstr + content + footstr);
w.print();
}
function failed(sender, args) {
alert('failed. Message:' + args.get_message());
}
</script>Show Items​​​​​

JavaScript: Implementing Callback Functions

This is a three part question.
In the code shown below, whenever I execute the functions (walk, run, crawl) I am observing that it is displaying the output for the method distance_travelled in a cumulative manner:
Trey says thank you
Trey walked a distance of 3
Trey ran a distance of 13
Trey crawled a distance of 16
Trey ran a distance of 26
I would like to ensure that each function calculates the distance by considering the method distance_travelled to be initialized to 0.
My second question is related to the callback function.
I am trying to create another property/method called doSomething() and have this method return a random function back (walk, run, crawl).
For example if I execute the following code:
var returned_function = person.doSomething();
returned_function();
It should execute one of the three methods. I have managed to execute the method run(). However, when I run the code in my browser, the alert pop up message displays undefined. Also, I encounter the same issue as in my first question. It calculates distance_travelled in a cumulative manner. How can I solve this?
My third question. I am trying to add a new method called 'fly' to the person object. The 'fly' method takes two functions as arguments.
I have to give a 30% chance for the person to fly. The function fly method should execute if the person is successfully able to fly (30% chance that this can happen). The second function should execute if the person is NOT able to fly (70% chance this would happen).
How can I implement this functionality into my code? Can someone suggest how to approach this problem?
<script type="text/javascript">
var person = new Object();
person.name = "Trey";
person.distance_travelled = 0;
person.say_name = alert(person.name);
person.say_something = function(xyz) {
document.write(person.name + " says " + xyz + '<br>');
}
person.say_something("thank you");
person.walk = alert(person.name + " is walking");
function walk(){
person.distance_travelled +=3;
document.write(person.name + " walked a distance of " + person.distance_travelled + '<br>');
}
walk();
person.run = alert(person.name + " is running");
function run(){
person.distance_travelled +=10;
document.write(person.name + " ran a distance of " + person.distance_travelled + '<br>');
}
run();
person.crawl = alert(person.name + " is crawling");
function crawl(){
person.distance_travelled +=3;
document.write(person.name + " crawled a distance of " + person.distance_travelled + '<br>');
}
crawl();
person.doSomething = function(abc){
alert(run());
}
var returned_function = person.doSomething();
returned_function();
</script>
First of all:
person.walk = alert(person.name + " is walking");
probably does nothing like what you think it would (because I can't ever think a line like that might make sense).
Your first question is trivial. If you want to output 3, just output 3, not distance_travelled.
Second question:
var activities = ['run', 'walk', 'crawl'];
person.doSomething = function() {
var randomActivity = activities[Math.floor(Math.random() * activities.length)];
return function() {
this[randomActivity]();
}
}
var personDoActivity = person.doSomething();
personDoActivity();
or
person.doSomething = function() {
var activities = [this.run, this.walk, this.crawl];
var randomActivity = activities[Math.floor(Math.random() * activities.length)];
return randomActivity;
}
var doActivity = person.doSomething();
doActivity.call(person);
Third question (and I'm changing it from object-oriented to procedural because you're not using OO correctly, anyway):
function maybeFly(fly, noFly) {
if (Math.random() < 0.3) {
return fly();
} else {
return noFly();
}
}
Because I still can't comment on answers -.-
#Amadan
the second version of doSomething can maybe be even nicer using .bind()
person.doSomething = function() {
var activities = [this.run, this.walk, this.crawl];
var randomIndex = Math.floor(Math.random() * activities.length);
return activities[randomIndex].bind(this);
}
var doActivity = person.doSomething();
doActivity();
Also worth noting that it is better to use, and more in the spirit of javascript to write
var person = {};
instead of
var person = new Object();

What does the method clog() do?

I am trying to learn url persistence, and a friend told me to study this block of code:
$(document).ready(function(){
var objects = {};
var DEFAULT_LOCATION = "diameter";
$("#animateObjects").hide();
var urlDimension = location.hash.replace("#","");
if (urlDimension.length == 0) {
// location.hash = "#" + DEFAULT_LOCATION;
urlDimension = DEFAULT_LOCATION;
$("#"+DEFAULT_LOCATION).addClass("active");
clog("started with no dimension, defaulted to " + DEFAULT_LOCATION);
}
else {
$("#"+urlDimension).toggleClass("active");
clog("started with dimension: " + urlDimension);
}
What does the clog() method accomplish?
Full code is here.
I'd bet its a wrapper around console.log to cater for IE not being able to handle it.
something like this:
function clog(message) {
try {
console.log('message');
}
catch (ex) {}
}
Reference: http://benwong.me/javascript-console-log-and-internet-explorer/

Categories