First of all I want to say that I am sorry for not using the Code sample. This is my first time asking on stackoverflow and I found it really confusing.
I have this javascript code which works perfectly, but when I try to duplicate it and change the variable names it doesn't seem to work.
JavaScript
function saveEdits() {
var editElem = document.getElementById("edit");
var userVersion = editElem.innerHTML;
localStorage.userEdits = userVersion;
document.getElementById("update").innerHTML="Edits saved!";
}
function checkEdits() {
if(localStorage.userEdits!=null)
document.getElementById("edit").innerHTML=localStorage.userEdits;
}
the way i tried to edit(im new to javascript i have no idea what i was doing):
JavaScript
<script type="text/javascript">
function saveEditsplus() {
var editElemplus = document.getElementById("editplus");
var userVersionplus = editElemplus.innerHTML;
localStorageplus.userEditsplus = userVersionhtml;
}
function checkEditsplus() {
if(localStorage.userEditsplus!=null)
document.getElementById("editplus").innerHTML=localStorageplus.userEditplus;
}
</script>
in your code, you changed the name of localStorage to localStoragePlus - but localStorage is something provided by your browser (see .
If you change it back to localStorage, it might work again.
For reference, here's the part with the renamed variable:
function saveEditsplus() {
var editElemplus = document.getElementById("editplus");
var userVersionplus = editElemplus.innerHTML;
localStorageplus.userEditsplus = userVersionhtml;
^^^^
}
By the way, you're not using localStorage correctly. If you want to save something across page reloads, you need to call "set" I learned that this is not true. sorry for the confusion. (tutorial)
Yes, looks like you have no idea what the code is doing… localStorage is a browser api, you can't just rename it (like you can't - and didn't - change document or innerHTML).
However, there's no reason to rename any of the variables at all. By using the var declarations, you made them local to each of the functions, so they won't interfere with each other anyway. All you need to change are the references to the element:
function saveEditsplus() {
var editElem = document.getElementById("editplus");
var userVersion = editElem.innerHTML;
localStorage.userEditsplus = userVersion; // no …html suffix, either
// ^^^^^^^^^^^^^ the storage reference is global, though
}
function checkEditsplus() {
if(localStorage.userEditsplus!=null)
document.getElementById("editplus").innerHTML=localStorage.userEditplus;
}
However, even better than copying the code would have been to give these functions parameters - one for the id of the element, one for the property of localStorage that is supposed to be used.
You cannot modify the localStorage (browser api)!
function saveEdits() {
var editElem = document.getElementById("edit");
var userVersion = editElem.innerHTML;
localStorage.userEdits = userVersion;
document.getElementById("update").innerHTML="Edits saved!";
}
function checkEdits() {
if(localStorage.userEdits!=null)
document.getElementById("edit").innerHTML = localStorage.userEdits;
}
Related
I am launching an html page when users click a button. I need to be able to pass in an array of addresses to the new window so that I can load them into a table, however I have been unable to find any way to pass an array over to the new window.
My most recent attempt looks like the following:
<button onclick="openWindow(['Joe Smith\n1 Address\nCity 12345',
'Joe Smith\n2 Address\nCity 12345'])">Button</button>
function openWindow(addresses){
var myWindow = window.open("NewPage.html");
myWindow.addresses = addresses;
}
And then in NewPage.html I've got:
<script type="text/javascript">
function bodyLoaded() { //gets called when the body loads
var addresses;
alert(addresses);
}
</script>
I always get undefined in the alert on the new window. I did confirm that I am getting the addresses if I set up an alert in the openWindow() function.
I've tried several other things as well, including using localStorage (How to pass an array to a new page using javascript?) altho I don't know if I did it correctly. I also tried executing the function to load the table on the new window from the openWindow function (passing in the addresses variable) but I keep getting errors saying "Error: Object doesn't support property or method". For example:
function openWindow(addresses){
var myWindow = window.open("NewPage.html");
myWindow.loadTable(addresses); //the loadTable function exists in a .js file
}
Ideally I just want to pass a single array to the new window but I've been stuck on this for a while now. Any assistance or suggestions would be greatly appreciated.
One possibility is to pass the array of params as a query in the url. So something like this:
var myWindow = window.open("NewPage.html?addresses[0]=Joe Smith\n1 Address\nCity 12345&addresses[1]=Joe Smith\n2 Address\nCity 12345");
Then in javascript using this function
<script type="text/javascript">
function bodyLoaded() { //gets called when the body loads
var urlParams = new URLSearchParams(window.location.search);
var addresses = urlParams.get('addresses'));
alert(addresses);
}
</script>
Edit:
Also localstorage works according to this answer: (How to pass an array to a new page using javascript?)
window.localStorage.setItem("cart", JSON.stringify(cart)); // Saving
var cart = JSON.parse(window.localStorage.getItem("cart")); // Retrieving
The new window is open by code so the code has some control over that window. Try something like this.
function openWindow(addresses) {
var myWindow = window.open("newpage.html");
myWindow.onload = function() {
var myDiv = this.document.createElement('div');
this.document.body.appendChild(myDiv);
for (var i = 0, a; a = addresses[i]; ++i) {
myDiv.innerHTML += a;
}
}
}
I am trying to write a JavaScript function that will update the labels and attributes of my CSS menu. The CSS menu I create dynamically with PHP and a database, and I want to update the CSS menu so the top item is the currently selected one, and the currently selected one does not appear in the list below it. Now that you know what I am trying to accomplish, here is my code:
var vodName = Array();
var vodAddress = Array();
var vodDate = Array();
function switchVod(vodID) {
alert("switchVod ran");
var x = document.getElementById("vod1");
var y = x.getElementsByTagName("span");
y[0].innerHTML = vodName[vodID];
for (var i = 0; i < vodName.length; i++) {
if (i != vodID) {
var gameNum = i + 2;
var gameID = "vod" + gameNum;
var x = document.getElementByID(gameID);
var y = x.getElementsByTagName("span");
y[0].innerHTML = vodName[i]
x.onclick = function () {
switchVod(id);
}
}
}
alert("after for loop");
alert("1"); //works
document.getElementById('vodObj').innerHTML = 'some string';
alert("2"); //doesn't work
document.getElementById("vodDate").innerHTML = " some string ";
alert("finished"); //doesn't work
}
Deeper in the webpage, after getting my information from the database and storing the strings I need in the vodName, vodAddress, and vodDate arrays, and creating the CSS menu and <div id="vodObj"> and <div id="vodDate">, I initialize the page by calling
window.onload = switchVod(0);
It wasn't doing what I hoped, so I added some alert() calls to see how far into the function it was going before failing. alert("after for loop") worked, as did alert("1"). But, alert("2") does not pop up, and neither does alert("finished"), so I think the problem is with document.getElementById('vodObj').innerHTML = 'some string';.
Any ideas of what I could be doing wrong?
window.onload = switchVod(0);
executes switchVod and assigns the return value to window.onload. So it is very likely that the elements you are trying to access (#vodObj in particular) are not loaded yet.
You have to assign a function to window.onload:
window.onload = function() {
switchVod(0);
};
See also Why does jQuery or a DOM method such as getElementById not find the element?
There is an other problem which will encounter eventually:
x.onclick = function () {
switchVod(id);
}
You never defined id anywhere, and if you define it inside the loop, you will run into closure issues. See JavaScript closure inside loops – simple practical example for a solution.
y[0].innerHTML = vodName[vodID];
At this point vodName is an empty array. Actually throughout all of this, you never provide any values to vodName. Please provide complete document.
This is my first SO post. I'm eternally grateful for the information this community has and shares. Thanks.
I'm coming from Flash and I'm not even sure what the right question to ask is. All I can do is lay out my code example and then explain what I am trying to do. I do not fully grasp the terms that I am trying to illustrate here so I feel it is best to omit them.
The code below is incomplete as it only includes the parts that I feel are relevant to my question. Please refer to the comments in my code to see my issue.
EDIT: Full source file here: [link removed] The console.log outputs the issue in question.
<script type="text/javascript">
var a_chests = [];
var chestID = 0;
//I'm creating a plugin to be able to make multiple instances
(function ($) {
$.fn.chestPlugin = function (option) {
//This function creates a master sprite object which many of my sprites will use
//I've simplified the features to get to the heart of my question
var DHTMLSprite = function (params) {
var ident = params.ident,
var that = {
getID: function(){
return ident;
}
};
return that;
};
//ChestSprite inherits DHTMLSprites properties and then adds a few of its own
var chestSprite = function(params) {
var ident = params.ident,
that = DHTMLSprite(params);
that.reveal=function(){
console.log(ident);
};
return that;
};
//Here I create multiple instances of the chests
var treasure = function ( $drawTarget,chests) {
for (i=0;i<chests;i++){
var cs = chestSprite({
ident: "chest"+chestID
})
console.log(cs.reveal())
//This logs "chest0", "chest1", "chest2" as the for loop executes
//This behavior is correct and/or expected!
a_chests[chestID]={id:i,ob:cs};
//I add a reference to the new chestSprite for later
chestID++;
//increment the chestID;
}
console.log(a_chests[1].ob.reveal());
//This always logs "chest2" (the last chest that is created), even though
//the logs in the for loop were correct. It seems it is referencing the
//DHTML object (since the DHTMLSprite function returns that;) and since
//there is no reference to which chest I need, it passes the last one.
//Is there any way I can pass a reference to DHTMLSprite in order to retain
//the reference to the three individual chests that are created?
//Is there another solution altogether? Thanks!!!
};
//The rest of the code.
return this.each(function () {
var $drawTarget = $(this);
treasure($drawTarget,3);
});
};
})(jQuery);
</script>
You forgot to declare `that' as a local variable, so it's being overwritten on each iteration.
var chestSprite = function(params) {
var that;
var animInterval;
...
When you write:
a_chests[chestID]={id:i,ob:cs};
You are assigning the cs object itself, not an instance of this object. If later you modify cs, this will also modify what you stored in the ob property.
I guess what you need is a closure:
for (i=0;i<chests;i++){
(function(){
var cs = chestSprite({ident: "chest"+chestID});
a_chests[chestID]={id:i,ob:cs};
})();
}
This way, each loop creates a different cs object.
how can i access a variable that was intialsed in a function, but the main.name is giving me a null value, i know the value is initliased in the function, or on main, but not in the feed!! this is my example,
var main = Titanium.UI.createWindow();
var feed = Titanium.UI.createWindow({
title:'feeds',
url:'main_windows/feeds.js',
barImage:'bg_content.gif',
username:main.name //im trying too access this varibale from main.
});
Ti.App.addEventListener('grantEntrance',function(event)
{
main.title ='Welcome'+event.username;
main.url = 'main_windows/main.js';
main.name = event.username; // this is where the varibale is intialised
main.email = event.email;
main.barImage='bg_content.gif';
});
sorry if this seems like a stupid question but im a newbie to javascript, so just tell me to delete it. i was wondering if you can turn it into a gloab or something.
You're trying to get variable that is not initialized yet. Since you're assigning main.name in a callback of event it will be initialized only after that event is fired. I'm not sure what's the logic of you'r application, but I guess you're able to initialize window inside this callback:
Ti.App.addEventListener('grantEntrance',function(event) {
main.title ='Welcome'+event.username;
main.url = 'main_windows/main.js';
main.name = event.username;
main.email = event.email;
main.barImage='bg_content.gif';
var feed = Titanium.UI.createWindow({
title:'feeds',
url:'main_windows/feeds.js',
barImage:'bg_content.gif',
username:main.name
});
});
Or, just set username property of the window inside callback:
var feed = Titanium.UI.createWindow({
title:'feeds',
url:'main_windows/feeds.js',
barImage:'bg_content.gif',
});
Ti.App.addEventListener('grantEntrance',function(event) {
main.title ='Welcome'+event.username;
main.url = 'main_windows/main.js';
main.name = event.username;
main.email = event.email;
main.barImage='bg_content.gif';
feed.username = main.name
});
Also, from personal experience: Titanium is not the best way to "fill the power" of js: some of methods are running asynchroniusly, and it causes weird issues. So if you're newbie it could be a pain in the ass..
Anyway good luck :)
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.