I am stuck with slight problem for a while now : Need to store in state a random number, that would persist to all participants.
alert(delta[random]);
returns value so everything is expected to be ok to this point however that's where mystery starts:
i already tried
$.each(gapi.hangout.data.getKeys(),function(i,o){
alert(o);
});
but it never enters loop. however if I place
alert('dfsdasd');
after submitDelta it works.
last two lines
alert(gapi.hangout.data.getValue(random));
$("#randomNumber").val(gapi.hangout.data.getValue(random));
are dead, no alert with 'undefined' or [object].
function setRandom()
{
var rand = Math.floor(Math.random()*100);
var random = "randomNumber";
var delta = {};
delta[random] = JSON.stringify(rand);
alert(delta[random]);
gapi.hangout.data.submitDelta(delta);
alert(gapi.hangout.data.getValue(random));
$("#randomNumber").val(gapi.hangout.data.getValue(random));
}
i have included
both libraries
src="//talkgadget.google.com/hangouts/_/api/hangout.js?v=1.1"
and src="http://code.jquery.com/jquery-1.7.2.js"
no handler on onStateChanged
what am I doing wrong here?
anytime I touch gapi.hangouts.data it fails.
It looks like there are are two issues here that I see.
The first is that submitDelta is defined as taking two parameters, and you provide only one.
The other issue is that submitDelta() is asynchronous, so you should not expect getValue() or getState() to work immediately after it is called. The best way to handle things in this case is to register for a StateChangedEvent using onStateChanged.add().
So, for example, you might do something like this:
function init(){
gapi.hangout.data.onStateChanged.add( handleChange );
submitRandom();
}
function handleChange( stateChangedEvent ){
var random = "randomNumber";
var val = gapi.hangout.data.getValue(random);
alert(val);
$("#randomNumber").val(val);
}
function submitRandom(){
var rand = Math.floor(Math.random()*100);
var random = "randomNumber";
var delta = {};
delta[random] = JSON.stringify(rand);
alert(delta[random]);
gapi.hangout.data.submitDelta(delta, []);
}
Related
I'm sorry if this is a duplicate, but i really don't actually know how to even ask this question. I'm coming from a native language background where you have control of how parameters are pass (by value, reference or pointer), and even though i've been using javascript for many years, i still have a tough time with knowing when variables are being passed by reference or value sometimes.
I'm would like to allow a function to be overridden in a javascript class, but basically i'm having a problem passing the arguments as a reference to the function.
I'll have to provide an example because i don't know exactly how to explain this.
So i have a "class", i'll call it exampleClass:
exampleClass = function()
{
var m_largearray = [];
var m_width = 100;
var m_funcParams = {data: m_largearray, width:m_width};
var m_someFunction = function(_params){
// do stuff
}
var m_finalValues = [];
return {
doProcessing: function()
{
// do some things
m_finalValues = m_someFunction(m_funcParams);
// do stuff with the m_finalValues
}
setFunction: function(_func, _params)
{
m_someFunction = _func;
m_funcParams = _params;
},
largearray: m_largearray,
width: m_width
}
}
So this class has a function which gets called, doProcessing(). Inside this function, it calls another function that does part of the processing, but i would like to have control of this part of the processing outside the class when i do not want the default way to process the data.
So something like this:
var classinstance = exampleClass();
var somespecialarray = [];
var someint = 5;
var somewidth = 900;
classinstance.setFunction(function(_params){
// do some processing with different set of params
// even though somewidth was set to 400, i will still get _params.width = 900 here
// return some array
},
{data:somespecialarray, anint:someint, width:somewidth});
somewidth = 400;
classinstance.doProcessing();
This is just a complete example of what i'm trying to do, i just wrote this code here off the top of my head so if theres errors thats why.
Anyway, the problem with this is that the parameter list i set (i've tried using an array instead of an object). When i set m_funcParams, it seems the data is copied rather than referenced. When i change these arguments, m_largearray for example, when the default function gets called, the parameter data is what it was when i originally set m_funcParams, and not what i have updated m_largearray to be, the same as when i override the function, if i change somewidth from 900 to 800, when i call the function, the width parameter i still 900.
I hope this makes sense, i just need some clarity on why the function is not getting the updated values, and if there is a better way of doing this.
So, why is the function not getting the changed values, and is there a better way of doing this?
EDIT:
Here is a complete working example. I think i just realized when i set the variable to be something else, i'm basically losing a "pointer" to the value it was before. if i set an element in an array, it updates in the function, but if i set the whole array, it does not
<html>
<body>
<script>
var exampleClass = function()
{
var m_largearray = [1,2,3];
var m_width = 100;
var m_funcParams = {data: m_largearray, width:m_width};
var m_someFunction = function(_params){
// do stuff
alert(_params.data[0]);
}
var m_finalValues = [];
return {
doProcessing: function()
{
// do some things
m_finalValues = m_someFunction(m_funcParams);
// do stuff with the m_finalValues
},
setFunction: function(_func, _params)
{
m_someFunction = _func;
m_funcParams = _params;
},
largearray: m_largearray,
width: m_width
}
}
var classinstance = exampleClass();
classinstance.largearray[0] = 3;
classinstance.doProcessing();
classinstance.largearray = [7,8,9];
classinstance.doProcessing();
var somespecialarray = [4,5,6];
var someint = 5;
var somewidth = 900;
classinstance.setFunction(function(_params){
// do some processing with different set of params
// even though somewidth was set to 400, i will still get _params.width = 900 here
alert(_params.width);
// return some array
},
{data:somespecialarray, anint:someint, width:somewidth});
somewidth = 400;
classinstance.doProcessing();
</script>
</body>
</html>
I hope I understood correctly and that this helps.
First of all when you pass an object to a function it passes as a reference, so changing one of it's properties will change the referred object's property.
However, when you invoked classinstance.setFunction in your example, you passed an object with a property width which recieved the variable somewidth, which is not an object so it gets passed by value.
Finally, when you changed someWidth to 800 you only changed someWidth, because width was passed as a value.
Edit:
In addition, when invoking classinstance.setFunction, you passed a function with param _param which is not part of that scope.
I have discover that a custom code is not syncronous as I thought.
I have this pseudo code:
ObjectA = function ()
{
var pointer;
var value =[];
this.set_pointer = function (p) {pointer = p;}
this.return_value = function () {return value[pointer];}
}
ObjectB = function ()
{
var SCOPE = this;
var OBJ = new ObjectA();
....
this.reset = function ()
{ OBJ.set_pointer(0);}
this.draw = function (what)
{
SCOPE.update();
OBJ.set_pointer(from);
OBJ.get_value();
// do somethings with Three.js
// draw some lines and some little pointclouds.
// do some things
// update two text elements
}
}
Main = new ObjectB();
Main.draw(7);
Main.reset();
ObjectA is using arraybuffers, dataviews and typedarrays.
ObjectB is using Three.js to draw some very symple 3D things.
The problem is inside 'draw'.
OBJ.get_value(); is using the pointer value 0 (zero) instead 7.
Abnormally (as I think) main.draw(7) is not executed first and later Main.reset(); It seems that Main.reset() is inmediatelly executed, so I have 0 (zero)
I'm not going to wait any DOM synchronism.
What can be the reason of this bechaviour?. Maybe the Three,js use ? The OOP style I'm using ?
Is there any way to check why is this happen?
Any idea would be appreciated
NOTE: Sorry for use the Three.js tag.
SOLVED
I have found the reason (or I think ) of a NO synchonism
Sometimes 'this' could be pointing to 'window' instead of the self instance of your object.
Sometimes, a bad use of this (when it is 'window') can raise an error you have not taken into account. Then a next line of code can be executed, and sometimes you can have the impression of an incorrect (not syncronous) operation.
So.... review the bad use of 'this'....
I have created this:
var where = function(){
sym.getSymbol("Man").getPosition()
}
console.log(where);
if (where()<=0){
var playMan = sym.getSymbol("Man").play();
} else {
var playMan = sym.getSymbol("Man").playReverse();
}
This is for Edge Animate hence all the syms. I am trying to access the timeline of symbol Man, then if it is at 0 play it. But it isnt working and the reason, I think, is that I have an incomplete understanding of how a var works. In my mind I am giving the variable 'where' the value of the timeline position of symbol 'Man'. In reality the console is just telling me I have a function there, not the value of the answer. I have run into this before and feel if I can crack it I will be a much better human being.
So if anyone can explain in baby-language what I am misunderstanding I would be grateful.
Thanks
S
var where = function () { ... };
and
function where() { ... }
are essentially synonymous here. So, where is a function. You are calling that function here:
if (where()<=0)
However, the function does not return anything. You need to return the value from it, not just call sym.getSymbol("Man").getPosition() inside it.
That, or don't make it a function:
var where = sym.getSymbol("Man").getPosition();
if (where <= 0) ...
The value will only be checked and assigned once in this case, instead of updated every time you call where().
Try
var where = function()
{
return sym.getSymbol("Man").getPosition();
};
Your code wasn't returning anything.
var where = function() {
return sym.getSymbol("Man").getPosition()
}
console.log(where);
if(where()<=0) {
var playMan = sym.getSymbol("Man").play();
} else {
var playMan = sym.getSymbol("Man").playReverse();
}
The following script works correctly although I need to make few amends. In each function I am getting the values need for the different formulas. However I tend to replicate the same line of code in different functions.
Ex.
function one(){ var v1= document.getElementById('one').value; }
function two(){ var v1= document.getElementById('one').value; }
Full code
I would like to declare all of the variables once and than only use the ones I need for the specific functions. If I declare them right at the top than once they are called they still hold the original value so I need to update that value to the current one if changed of course.
Your code will be very hard to read if you do it like in your fiddle.
Instead do
var myVars;
window.onload=function() {
myVars = {
'list_price': document.getElementById('list_price'),
'negotiated': document.getElementById('negotiated'),
.
.
'lease_payment': document.getElementById('lease_payment')
}
now you can do
var price = myVars.list_price.value;
or perhaps add a function
function getVal(id) {
var val = document.getElementById(id).value;
if (val =="" || isNaN(val)) return 0;
return parsetInt(val,10);
}
now you can do
var price = getVal("list_price");
mplungjan's solution is a great one. If you're at all concerned by your global vars leaking into the window scope, wrap your code in an Immediately Invoked Function Expression to prevent that from happening:
(function(){
// code goes here
}());
There are two ways to go about this:
Update your variable when the value changes
Use a function that always returns the correct value
1) You can add a listener for the change event or the keyup event that changes your global variable:
// save initial value
var val = document.getElementById('one').value;
// update the value when input is changed
addEventListener(document.getElementById('one'), 'change', function() {
val = document.getElementById('one').value;
});
console.log(val);
2) You can use a function that always returns the current value:
var val = function() { return document.getElementById('one').value; };
console.log(val());
2b) If you hate parenthesis, you can define a property that uses the function above as a getter:
Object.defineProperty(window, 'one', {
get : function() { return document.getElementById('one').value; }
});
console.log(one);
I edited the question so it would make more sense.
I have a function that needs a couple arguments - let's call it fc(). I am passing that function as an argument through other functions (lets call them fa() and fb()). Each of the functions that fc() passes through add an argument to fc(). How do I pass fc() to each function without having to pass fc()'s arguments separately? Below is how I want it to work.
function fa(fc){
fc.myvar=something
fb(fc)
}
function fb(fc){
fc.myothervar=something
fc()
}
function fc(){
doessomething with myvar and myothervar
}
Below is how I do it now. As I add arguments, it's getting confusing because I have to add them to preceding function(s) as well. fb() and fc() get used elsewhere and I am loosing some flexibility.
function fa(fc){
myvar=something
fb(fc,myvar)
}
function fb(fc,myvar){
myothervar=something
fc(myvar,myothervar)
}
function fc(myvar,myothervar){
doessomething with myvar and myothervar
}
Thanks for your help
Edit 3 - The code
I updated my code using JimmyP's solution. I'd be interested in Jason Bunting's non-hack solution. Remember that each of these functions are also called from other functions and events.
From the HTML page
<input type="text" class="right" dynamicSelect="../selectLists/otherchargetype.aspx,null,calcSalesTax"/>
Set event handlers when section is loaded
function setDynamicSelectElements(oSet) {
/**************************************************************************************
* Sets the event handlers for inputs with dynamic selects
**************************************************************************************/
if (oSet.dynamicSelect) {
var ySelectArgs = oSet.dynamicSelect.split(',');
with (oSet) {
onkeyup = function() { findListItem(this); };
onclick = function() { selectList(ySelectArgs[0], ySelectArgs[1], ySelectArgs[2]) }
}
}
}
onclick event builds list
function selectList(sListName, sQuery, fnFollowing) {
/**************************************************************************************
* Build a dynamic select list and set each of the events for the table elements
**************************************************************************************/
if (fnFollowing) {
fnFollowing = eval(fnFollowing)//sent text function name, eval to a function
configureSelectList.clickEvent = fnFollowing
}
var oDiv = setDiv(sListName, sQuery, 'dynamicSelect', configureSelectList); //create the div in the right place
var oSelected = event.srcElement;
if (oSelected.value) findListItem(oSelected)//highlight the selected item
}
Create the list
function setDiv(sPageName, sQuery, sClassName, fnBeforeAppend) {
/**************************************************************************************
* Creates a div and places a page in it.
**************************************************************************************/
var oSelected = event.srcElement;
var sCursor = oSelected.style.cursor; //remember this for later
var coords = getElementCoords(oSelected);
var iBorder = makeNumeric(getStyle(oSelected, 'border-width'))
var oParent = oSelected.parentNode
if (!oParent.id) oParent.id = sAutoGenIdPrefix + randomNumber()//create an ID
var oDiv = document.getElementById(oParent.id + sWindowIdSuffix)//see if the div already exists
if (!oDiv) {//if not create it and set an id we can use to find it later
oDiv = document.createElement('DIV')
oDiv.id = oParent.id + sWindowIdSuffix//give the child an id so we can reference it later
oSelected.style.cursor = 'wait'//until the thing is loaded
oDiv.className = sClassName
oDiv.style.pixelLeft = coords.x + (iBorder * 2)
oDiv.style.pixelTop = (coords.y + coords.h + (iBorder * 2))
XmlHttpPage(sPageName, oDiv, sQuery)
if (fnBeforeAppend) {
fnBeforeAppend(oDiv)
}
oParent.appendChild(oDiv)
oSelected.style.cursor = ''//until the thing is loaded//once it's loaded, set the cursor back
oDiv.style.cursor = ''
}
return oDiv;
}
Position and size the list
function configureSelectList(oDiv, fnOnClick) {
/**************************************************************************************
* Build a dynamic select list and set each of the events for the table elements
* Created in one place and moved to another so that sizing based on the cell width can
* occur without being affected by stylesheet cascades
**************************************************************************************/
if(!fnOnClick) fnOnClick=configureSelectList.clickEvent
if (!oDiv) oDiv = configureSelectList.Container;
var oTable = getDecendant('TABLE', oDiv)
document.getElementsByTagName('TABLE')[0].rows[0].cells[0].appendChild(oDiv)//append to the doc so we are style free, then move it later
if (oTable) {
for (iRow = 0; iRow < oTable.rows.length; iRow++) {
var oRow = oTable.rows[iRow]
oRow.onmouseover = function() { highlightSelection(this) };
oRow.onmouseout = function() { highlightSelection(this) };
oRow.style.cursor = 'hand';
oRow.onclick = function() { closeSelectList(0); fnOnClick ? fnOnClick() : null };
oRow.cells[0].style.whiteSpace = 'nowrap'
}
} else {
//show some kind of error
}
oDiv.style.width = (oTable.offsetWidth + 20) + "px"; //no horiz scroll bars please
oTable.mouseout = function() { closeSelectList(500) };
if (oDiv.firstChild.offsetHeight < oDiv.offsetHeight) oDiv.style.height = oDiv.firstChild.offsetHeight//make sure the list is not too big for a few of items
}
Okay, so - where to start? :) Here is the partial function to begin with, you will need this (now and in the future, if you spend a lot of time hacking JavaScript):
function partial(func /*, 0..n args */) {
var args = Array.prototype.slice.call(arguments, 1);
return function() {
var allArguments = args.concat(Array.prototype.slice.call(arguments));
return func.apply(this, allArguments);
};
}
I see a lot of things about your code that make me cringe, but since I don't have time to really critique it, and you didn't ask for it, I will suggest the following if you want to rid yourself of the hack you are currently using, and a few other things:
The setDynamicSelectElements() function
In this function, you can change this line:
onclick = function() { selectList(ySelectArgs[0], ySelectArgs[1], ySelectArgs[2]) }
To this:
onclick = function() { selectList.apply(null, ySelectArgs); }
The selectList() function
In this function, you can get rid of this code where you are using eval - don't ever use eval unless you have a good reason to do so, it is very risky (go read up on it):
if (fnFollowing) {
fnFollowing = eval(fnFollowing)
configureSelectList.clickEvent = fnFollowing
}
And use this instead:
if(fnFollowing) {
fnFollowing = window[fnFollowing]; //this will find the function in the global scope
}
Then, change this line:
var oDiv = setDiv(sListName, sQuery, 'dynamicSelect', configureSelectList);
To this:
var oDiv = setDiv(sListName, sQuery, 'dynamicSelect', partial(configureSelectListAlternate, fnFollowing));
Now, in that code I provided, I have "configureSelectListAlternate" - that is a function that is the same as "configureSelectList" but has the parameters in the reverse order - if you can reverse the order of the parameters to "configureSelectList" instead, do that, otherwise here is my version:
function configureSelectListAlternate(fnOnClick, oDiv) {
configureSelectList(oDiv, fnOnClick);
}
The configureSelectList() function
In this function, you can eliminate this line:
if(!fnOnClick) fnOnClick=configureSelectList.clickEvent
That isn't needed any longer. Now, I see something I don't understand:
if (!oDiv) oDiv = configureSelectList.Container;
I didn't see you hook that Container property on in any of the other code. Unless you need this line, you should be able to get rid of it.
The setDiv() function can stay the same.
Not too exciting, but you get the idea - your code really could use some cleanup - are you avoiding the use of a library like jQuery or MochiKit for a good reason? It would make your life a lot easier...
A function's properties are not available as variables in the local scope. You must access them as properties. So, within 'fc' you could access 'myvar' in one of two ways:
// #1
arguments.callee.myvar;
// #2
fc.myvar;
Either's fine...
Try inheritance - by passing your whatever object as an argument, you gain access to whatever variables inside, like:
function Obj (iString) { // Base object
this.string = iString;
}
var myObj = new Obj ("text");
function InheritedObj (objInstance) { // Object with Obj vars
this.subObj = objInstance;
}
var myInheritedObj = new InheritedObj (myObj);
var myVar = myInheritedObj.subObj.string;
document.write (myVar);
subObj will take the form of myObj, so you can access the variables inside.
Maybe you are looking for Partial Function Application, or possibly currying?
Here is a quote from a blog post on the difference:
Where partial application takes a function and from it builds a function which takes fewer arguments, currying builds functions which take multiple arguments by composition of functions which each take a single argument.
If possible, it would help us help you if you could simplify your example and/or provide actual JS code instead of pseudocode.