Dynamic Javascript Variable? - javascript

I am not very sure how to name the question. What i am trying to achieve is this..
I have a set of Global Variable, they will need to be replicated over and over, but assigned with different set's name example. For example
var start
var end
var time
And i have many set/model that i have to create and change, so i am wondering if it is possible to create 1 set and i just have a var modelnumber which then i can just copy and paste them and change the modelnumber so i wont have to change thousands of variable names?
Example
var modelnumber = "1";
var modelstart = modelnumber + "modelstart";
var modelend = modelnumber + "modelend";
var modeltime = modelnumber + "modeltime";
Edit: To provide more info
So i have model1.js , model2.js model3.js and so on....and all the variable names function names are the same, and to save me time, i want to write 1 set of code that i can just change the var modelname at the top of each field so i wont have to change the thousands of variable names and function names..

You can always write a function:
function createVariables(modelNumber) {
window[modelNumber + 'modelstart'] = 1;
window[modelNumber + 'modelend'] = 2;
window[modelNumber = 'modeltime'] = 3;
}
createVariables(1);
Or change it to however you want. :)
UPDATE: (use global in place of window for NodeJS).

I think you're looking for a normal object literal. You can specify the property keys of the object with strings, which will give you the dynamic effect you're looking for.
Here's an example, using a for loop to populate the object.
var models = {};
var number_of_keys = 1000;
for(var i = 1; i < number_of_keys; i++) {
var keyName = 'model' + i;
var model = {
'start': i + 'modelstart',
'end': i + 'modelend',
'time': i + 'modeltime'
}
models[keyName] = model;
}
console.log(models);
Update:
As an example of how you could access your populated models, consider the following:
// You can effectively replace the `1` in this example with any number:
var model1 = models['model1'];
// model1 would be:
// {
// 'start': '1modelstart',
// 'end' : '1modelend',
// 'time': '1modeltime'
// }
var start1 = model1.start;
var end1 = model1.end;
var time1 = model1.time;
// Pseudo-code
var modelN = models['modelN'];
var startN = modelN.start;
var endN = modelN.end;
var timeN = modelN.time;
HTH

You could (should?) use an object or an array of objects.
For example:
// The "Model"
var Model = function(start,end,time) {
this.start = start;
this.end = end;
this.time = time;
}
// One option.
// Assign "Model" to the models
var models = {
'm1': new Model(x,y,z),
'm2': new Model(a,b,c)
}
// Access values
if (models.m1) {
alert("m1 end:["+ models.m1.end +"]");
}
// Add a "new" model
models['ace'] = new Model(r,s,t);
// or even
models.club = new Model(e,f,g);
You could also extend it like so:
Model.prototype.debug = function(id) {
if (id) {
console.log("model id:["+ id +"]");
}
console.log("start:["+ this.start +"]");
console.log("end:["+ this.end +"]");
console.log("time:["+ this.time +"]");
}
Which you would call like so:
models.m1.debug();
Or even:
for(x in models) {
models[x].debug(x);
}
Here is a code snippet example.
var Model = function(start,end,time) {
this.start = start;
this.end = end;
this.time = time;
}
Model.prototype.debug = function(id) {
if (id) {
console.log("model id:["+ id +"]");
}
console.log("start:["+ this.start +"]");
console.log("end:["+ this.end +"]");
console.log("time:["+ this.time +"]");
}
var models = {
'm1' : new Model('x','y','z'),
'm2' : new Model('a','b','c')
};
models.ace = new Model('r','s','t');
for(x in models) {
models[x].debug(x);
}

Related

How do I determine which value has been called from an array, to use in another function?

I have the below code which is called onclick, and want to be able to show a second image after a few seconds, depending on which one is chosen from the array - so for example if 1.png is shown, then I want to show 1s.png, 2.png then show 2s.png etc
function displayImage () {
var img_name = new Array("images/1.png", "images/2.png", "images/3.png");
var l = img_name.length;
var rnd_no = Math.floor(l*Math.random());
document.getElementById("imgHolder").src = img_name[rnd_no];
}
How do I determine which image has been chosen from the array to then use in another function please ?
You're gonna need a global var for knowing that function is running for the first time or not.
var alreadyRandom = false;
function displayImage()
{
var img_name = new Array("images/1.png", "images/2.png", "images/3.png");
if(alreadyRandom)
{
// If the random for first time is done
var rnd_no = img_name.indexOf(document.getElementById("imgHolder").getAttribute('src'));
if(rnd_no === img_name.length-1)
{
// If the current image is the last one in array,
// go back to the first one
rnd_no = 0;
}
else
{
// Choose the next image in array
rnd_no++;
}
document.getElementById("imgHolder").src = img_name[rnd_no];
}
else
{
var l = img_name.length;
var rnd_no = Math.floor(l*Math.random());
document.getElementById("imgHolder").src = img_name[rnd_no];
alreadyRandom = true; // Tell the function not to random again
}
return img_name[rnd_no];
}
Demo: http://jsbin.com/kanejugahi/edit?html,js,console,output
Moreover, making the array global would make your function more efficient.
Hope this helps,
I think it's important you understand how Functions work in JavaScript and how scope works.
What you need to do is you need to expose that information so that both functions have access. You have the array of images defined and you have already determined the random number so just make them available by declaring them outside of the function so now these variables are available. Defining variables in the global scope is generally bad practice but this is simply for teaching.
var selectedImage; // defined outside so it is available for other functions
function displayImage() {
var img_name = new Array("images/1.png", "images/2.png", "images/3.png");
var rnd_no = Math.floor(img_name.length * Math.random());
selectedImage = img_name[rnd_no];
document.getElementById("imgHolder").src = selectedImage;
}
function anotherFunction() {
console.log(selectedImage);
}
As far as I understand the question, you can use a return and make the image array global.
var img_name = new Array("images/1.png", "images/2.png", "images/3.png");
var img_class = '';
//this function will return the index of the image in array
function displayImage () {
var l = img_name.length;
var rnd_no = Math.floor(l*Math.random());
document.getElementById("imgHolder").src = img_name[rnd_no];
return rnd_no;
}
var nextimage;
function showImages(){
//your logic to show the next image here
nextimage = (displayImage ()+1)%img_name.length;
var myVar = setInterval(function(){
if(img_class==''){
document.getElementById("imgHolder").src = img_name[nextimage];
img_class = 's';
}else{
var img_arr = img_name[nextimage].split(".");
if(img_arr.length===2){
document.getElementById("imgHolder").src = img_arr[0]+"s."+img_arr[1];
}
img_class = '';
nextimage = (nextimage+1)%img_name.length;
}
}, 1000);
}
var img_name = new Array("images/1.png", "images/2.png", "images/3.png");
var img_class = '';
//this function will return the index of the image in array
function displayImage () {
var l = img_name.length;
var rnd_no = Math.floor(l*Math.random());
document.getElementById("imgHolder").src = img_name[rnd_no];
return rnd_no;
}
var nextimage;
function showImages(){
//your logic to show the next image here
nextimage = (displayImage ()+1)%img_name.length;
var myVar = setInterval(function(){
if(img_class==''){
document.getElementById("imgHolder").innerHTML = img_name[nextimage];
img_class = 's';
}else{
var img_arr = img_name[nextimage].split(".");
if(img_arr.length===2){
document.getElementById("imgHolder").innerHTML = img_arr[0]+"s."+img_arr[1];
}
img_class = '';
nextimage = (nextimage+1)%img_name.length;
}
}, 1000);
}
showImages();
<div id="imgHolder"></div>
Mayve something like this?
var images = ["images/1.png", "images/2.png", "images/3.png"];
function displayImage () {
var dom = document.getElementById("imgHolder");
if ( images.indexOf(dom.src) >=0 ) {
dom.src = dom.src.replace(".png", "s.png"); // Seems like a stupid way to do this
return;
}
var l = images.length;
dom.src = images[Math.floor(l*Math.random())];
}

How to properly structure class in Node.js

I have a class called TileStreamer that I am currently defining as follows:
function TileStreamer {
};
This class has constants, which I define as follows:
// Tiles are 256 x 256 pixels
TileStreamer.prototype.TILE_SIZE = 256;
// Header size in bytes
TileStreamer.prototype.HEADER_SIZE = 28;
// Various table entry sizes in bytes
TileStreamer.prototype.RESOLUTION_ENTRY_SIZE = 12;
TileStreamer.prototype.TILE_COUNT_SIZE = 4;
TileStreamer.prototype.TILE_ENTRY_SIZE = 12;
// Offsets within header
TileStreamer.prototype.WIDTH_OFFSET = 3;
TileStreamer.prototype.HEIGHT_OFFSET = 4;
TileStreamer.prototype.NUM_TABLES_OFFSET = 7;
TileStreamer.prototype.UNPOPULATED_OFFSET = 12092;
There also other variables. These variables are important because they need to be accessible from other classes. They get their values within the methods of this class. This is what I am unsure of as far as structure. What I'm currently trying is:
TileStreamer.prototype.header;
TileStreamer.prototype.resolutionEntry;
TileStreamer.prototype.resolutionTable;
TileStreamer.prototype.filepath;
TileStreamer.prototype.s3;
TileStreamer.prototype.level;
TileStreamer.prototype.ncols;
TileStreamer.prototype.nrows;
TileStreamer.prototype.nlevels;
TileStreamer.prototype.toffset;
TileStreamer.prototype.tsize;
TileStreamer.prototype.modifiedTime;
TileStreamer.prototype.tile;
TileStreamer.prototype.host;
TileStreamer.prototype.bucket;
This class also has methods such as:
TileStreamer.prototype.Init = function(filepath, index, s3config){
var retval = false;
AWS.config.update({accessKeyId: s3config.access_key, secretAccessKey: s3config.secret_key});
var blc = new BlockLibraryConfigs();
var awsConfig = blc.awsConfig;
AWS.config.update({region: awsConfig.region});
var aws = new AWS.S3();
var params = {
Bucket: s3config.bucket,
Key: s3config.tile_directory + filepath,
Range: 'bytes=0-' + (this.HEADER_SIZE - 1)
};
aws.getObject(params, function(err, data){
if(err == null){
TileStreamer.modifiedTime = data.LastModified;
var header = bufferpack.unpack('<7I', data.Body);
TileStreamer.header = header;
TileStreamer.nlevels = header[TileStreamer.NUM_TABLES_OFFSET];
if(TileStreamer.nlevels == 5){
TileStreamer.level = 0;
TileStreamer.ncols = Math.ceil((header[TileStreamer.WIDTH_OFFSET] * 1.0) / TileStreamer.TILE_SIZE);
TileStreamer.nrows = Math.ceil((header[TileStreamer.HEIGHT_OFFSET] * 1.0) / TileStreamer.TILE_SIZE);
}
}
});
};
The method above should set some of the values of the variables, such as modifiedTime so that I can access it in another class such as:
TileStreamer = require('tilestreamer.js');
var ts = new TileStreamer();
ts.Init(parPath, index, config);
var last_modified = ts.modifiedTime;
Just put any public properties you want to initialise when the object is created, directly in the init function. Here's a small example...
function TileStreamer() {
};
TileStreamer.prototype.Init = function() {
this.modifiedTime = new Date();
};
var ts = new TileStreamer();
ts.Init();
console.log(ts);
jsfiddle example
https://jsfiddle.net/v6muohyk/
To get around the issue you're having with setting the object properties in a callback from an asynchronous function, just create a locally accessible variable to reference the object that you are creating at that time...
TileStreamer.prototype.Init = function() {
var thisTileStreamer = this;
asynchFunction(function(err, data) {
thisTileStreamer.modifiedTime = data.lastModified;
});
};
To take it one step further, if you need to execute some code after the init function has completed, then that will require waiting for the asynchronous function to complete, as well. For that, pass a further parameter to init, that is a function to be executed after all the work is done...
TileStreamer.prototype.Init = function(callback) {
var thisTileStreamer = this;
asynchFunction(function(err, data) {
thisTileStreamer.modifiedTime = data.lastModified;
callback();
});
};
var ts = new TileStreamer();
ts.Init(function() {
// put code here that needs to be executed *after* the init function has completed
alert(ts.modifiedTime);
});

Auto increment value in javascript class

I'm trying to auto increment a properties value each time I instantiate a new instance of the class. This is what my class constructor looks (I abstracted it down just a bit):
var Playlist = function(player, args){
var that = this;
this.id = ?; //Should auto increment
this.tracks = [];
this.ready = false;
this.unloaded = args.length;
this.callback = undefined;
this.onready = function(c){
that.callback = c;
};
this.add = function(tracks){
for(var i = 0; i < tracks.length; i++){
this.tracks.push(tracks[i]);
this.resolve(i);
}
};
this.resolve = function(i){
SC.resolve(that.tracks[i]).then(function(data){
that.tracks[i] = data;
if(that.unloaded > 0){
that.unloaded--;
if(that.unloaded === 0){
that.ready = true;
that.callback();
}
}
});
};
player.playlists.push(this);
return this.add(args);
};
var playlist1 = new Playlist(player, [url1,url2...]); //Should be ID 0
var playlist2 = new Playlist(player, [url1,url2...]); //Should be ID 1
I'd like to not define an initial variable that I increment in the global scope. Could anyone hint me in the right direction? Cheers!
You can use an IIFE to create a private variable that you can increment.
var Playlist = (function() {
var nextID = 0;
return function(player, args) {
this.id = nextID++;
...
};
})();
You can set Playlist.id = 0 somewhere in your code, then increment it in the constructor and assign the new value to the instance property, as: this.id = Playlist.id++.
This suffers from the fact that it is not well encapsulated, so it could be misused.
Otherwise, I was to propose the solution described by Mike C, but he already set a good answer that contains such an idea, so...

Javascript object become undefined on recordset

I have an acces database and I would like to import data to javascript.
This is my code:
function Flight(){
this.number;
this.day;
this.updateDate;
this.html;
}
var dbPath = "mypath\\flight_bdd.mdb";
var flights = [];
function executeRequest(request){
//get datas
var adoConn = new ActiveXObject("ADODB.Connection");
var adoCmd = new ActiveXObject("ADODB.Command");
adoConn.Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source='" + dbPath + "'");
adoCmd.ActiveConnection = adoConn;
var adOpenDynamic=2;
var adLockOptimistic=3;
var rs = new ActiveXObject("ADODB.Recordset");
rs.open(request, adoConn, adOpenDynamic, adLockOptimistic);
return rs;
}
function loadFlightsFromDatabase(){
//get datas
var rs = executeRequest("SELECT * FROM flight_data");
//empty flight array
flights = [];
//create flights
var i = 0
while(!rs.eof){
flights[i] = new Flight();
//set flight data
flights[i].number = rs.fields("flight_number");
console.log(flights[i].number);
rs.MoveNext();
console.log(flights[i].number);
i++;
}
}
The first console output returns the flight number and the second one returne undefined.
I think the value of the recordset is updated in my object when I have a move next, is there a way to prevent it ?
I think your connection goes out of scope and is getting closed. Try creating a disconnected recordset:
var adOpenStatic = 3;
var adUseClient = 3;
var adLockBatchOptimistic = 4;
var rs = new ActiveXObject("ADODB.Recordset");
rs.CursorLocation = adUseClient;
rs.open(request, adoConn, adOpenStatic, adLockBatchOptimistic);
rs.ActiveConnection = null;
adoConn.Close;
return rs;
But that said, rs.MoveNext(); should not affect already assigned property of your object (unless it's a reference type). What type is .number - can u show structure of Flight?
I find a solution,
I I concatenate my recordset
flights[i].number = rs.fields("flight_number") + "";
it works !!

Get Next and Previous Elements in JavaScript array

I have a large array, with non-sequential IDs, that looks something like this:
PhotoList[89725] = new Array();
PhotoList[89725]['ImageID'] = '89725';
PhotoList[89725]['ImageSize'] = '123';
PhotoList[89726] = new Array();
PhotoList[89726]['ImageID'] = '89726';
PhotoList[89726]['ImageSize'] = '234';
PhotoList[89727] = new Array();
PhotoList[89727]['ImageID'] = '89727';
PhotoList[89727]['ImageSize'] = '345';
Etc....
I'm trying to figure out, given an ID, how can I can get the next and previous ID... So that I could do something like this:
<div id="current">Showing You ID: 89726 Size: 234</div>
Get Prev Get Next
Obviously, if we're at the end or beginning of the array we just a message...
Why don't you add properties 'Prev' & 'Next' to that array?
PhotoList[89725] = new Array();
PhotoList[89725]['Prev'] = 89724;
PhotoList[89725]['Next'] = 89726;
PhotoList[89725]['ImageID'] = '89725';
PhotoList[89725]['ImageSize'] = '123';
This is just 'doubly-linked list' data structure.
Based on your example the IDs are sequential...
This is another way of writing your example. new Array() really isn't what you should be using because those are objects you are creating. Also, I left the numbers as strings, but I'm not sure why you would want to do that. You could add next and prev like kuy suggested
PhotoList[89725] = {ImageID: '89725',
ImageSize: '123'};
PhotoList[89725] = {ImageID: '89726',
ImageSize: '234',
Next: '89727',
Prev: '89725'};
PhotoList[89725] = {ImageID: '89727',
ImageSize: '345'};
All of these are accessible just like your other structure.
There's really no way other than to iterate through the possible ids sequentially until you find one which has an entry in your array. For example:
function findClosest(arr, id, increasing) {
var step = increasing ? 1 : -1;
for(var i=id+step; i>=0 && i<=max_id; i+=step)
if( arr[id] )
return id;
}
Obviously, this approach requires that you keep track of the max_id so that you don't iterate forever; here I assume that it's a global variable, but you might want to make it a parameter to the findClosest function. You'd call this function like so:
var prev = findClosest(arr, id, false);
var next = findClosest(arr, id, true);
I agree with the rest quotes you should be using objects not an array. Also make sure you create new arrays using the literal notation and not the new keyword with built in types. The new keyword is bad news and you could clobber the global object. Check out JSLint.
var a = new Array(); //bad dont use
var a = []; //this is the best way to create a new array
var o = {}; //create new objects like this
As for the problem at hand. Why not write a simple container that has its own internal counter?
function PhotoListContainer(PhotoList)
{
if(PhotoList === undefined)
throw("no photo list");
this.counter = 0;
var self = this;
this.current = function(){
return PhotoList[self.counter];
};
this.next = function(){
return PhotoList[self.counter + 1];
};
this.prev = function(){
return PhotoList[self.counter - 1];
};
// You could even write a function that loops each value from the current counter :)
this.each_from_counter = function(callback){
for(var i = self.counter; i < PhotoList.length; i++)
{
callback(PhotoList[i], i);
self.counter++;
}
};
}
//use
var pc = new PhotoListContainer(PhotoList);
pc.counter = 500;
pc.next(); //returns the 501st object
pc.prev(); //returns the 499th object
pc.each_from_counter(function(photo, index){
photo.somehting;
});
No arrays at all are better..
images = {
0: {
size: 12345, /* dont realy need as you can use JS to mesure the size. */
title: "day 1 on holiday"
},
1: {
size: 13549, /* dont realy need as you can use JS to mesure the size. */
title: "day 2 on holiday"
},
2: {
size: 16548, /* dont realy need as you can use JS to mesure the size. */
title: "day 3 on holiday"
},
}
for(x in images){
/* x = "the id of the image." */
url[] = "/images/" + x + ".png";
title[] = images[x].title;
size[] = images[x].size;
console.log("File: " + url[x] + " , Title: " + title[x] + " , Size: " + size + "bytes")
}
var sibNum = 0;
var sibList = [];
var prevSiblingID = false;
for (n in w) {
sibNum++;
sibList[n] = {
title : n,
prevSiblingID : prevSiblingID
};
if (prevSiblingID) {
sibList[prevSiblingID].nextSiblingID = n;
}
prevSiblingID = n;
};
sibList[prevSiblingID].nextSiblingID = false;
you can use grep function and calculate prev or next item of specified array:
object = $.grep(data, function(e) {
if(e.id == yourId) {
return data[data.indexOf(e) + 1]; // or -1 for prev item
}
});
i think your image list will come from DB so you may can try this code, this code is working for me.
<?
$prev="";
$next="";
$cur=0;
$i=0;
$pid=$_GET['pid'];
while($rowcon=mysql_fetch_assoc($result))
{
$arr[$i]=$rowcon['pid'];
if($rowcon['pid']==$pid)
{
$cur=$i;
}
$i++;
}
if($cur<$num_rows)
$next=$arr[$cur+1];
else
$next="";
if($cur>0)
$prev=$arr[$cur-1];
else
$prev="";
echo $prev." ".$cur." ".$next;
?>

Categories