Create array of objects Javascript - javascript

I created this Object with 3 properties:
Node = {
name : "",
isOkay : true,
rotation : 0.0
};
How would i go creating an array of these objects, in size of 100.
So later i could do something like this:
nodeList[74].name = "Peter";
nodeList[74].isOkay = false;
nodeList[74].rotation = 1.3;
or similar...
I'm really new to this, i found couple of topics about this, but it never compiles properly.
I would be really grateful if anyone could show the proper syntax, Thanks!

I would use this way:
var Node = function() {
this.name = "";
this.isOkay = true;
this.rotation = 0.0
}
var nodeList = [];
for (var i = 0; i < 10; i++)
{
nodeList.push(new Node());
}
nodeList[0].name = "test";
So you could create a new object(really new) in order to manage it later. Look here.
EDIT:
What I have done is created an object with a constructor method, you can check it on MDN here.
Creating an object like you have done:
var Node = { /* ... */ }
Is like having one object initiated. To have another, you'll have to write another one and so on. With that contructor you may create any instances you want based on that model.

You might want to do this lazily
Depending on the situation might be helpful to do this lazily
var Node = function(name, isOkay,rotation){
if(!(this instanceof Node)) return new Node(name,isOkay,rotation);
else {
this.name = name;
this.isOkay = isOkay;
this.rotation = rotation;
}
}
var NodeCollective = function(numberOfNodes){
if(!(this instanceof NodeCollective)) return new NodeCollective(numberOfNodes);
else{
var _collective={};
var _defaultName = "", _defaultIsOkay = true, _defaultRotation=0.0;
this.length = numberOfNodes;
this.getNode=function(nodeNumber){
if(!_collective.hasOwnProperty(nodeNumber) && nodeNumber < numberOfNodes){
_collective[nodeNumber]=
Node(_defaultName,_defaultIsOkay,_defaultRotation);
}
//I am just assuming I am not going to get garbage
//you can put in checks to make sure everything is kosher
//if you really want to
return _collective[nodeNumber];
};
}
}
but it also depends on what you are trying to do... if you might not be getting all of the nodes in your program then implementing them in some way that avoids greedily creating them could save you a lot of time if the code is executed often, but if the piece of code isn't executed often this might be over kill.

var nodeList = []; // create empty array
nodeList.push(Node); // add the object to the end of the array
nodeList[0].rotation = 1.3; // set rotation property of the object
console.log(nodeList[0]); // prints the object to console

Related

Handling Complex Dependencies Between Object Properties (Auto Update Dependent Properties)

I have a tree structure of objects, and their properties have very complicated dependencies on surrounding objects determined by where they are in the tree. I have hard coded a lot of these dependencies, and tried to create some sort of update loop (where if a property gets updated, based on the design, all of the properties that depend on it get updated, and in the correct order), but I want to handle it in a more generic/abstract way, instead of hard coding a bunch of update calls to different objects.
Let's say, for example, I have 1 superclass, and 3 subclasses, and then a separate container object.
Shape
properties: parentContainer, index, left, top, width, height
methods: updateLeft(), updateTop(), updateWidth(), updateHeight()
Square inherits from Shape
Triangle inherits from Shape
Circle inherits from Shape
ShapeContainer
properties: shapes
methods: addShape(shape, index), removeShape(index)
I'll give a pseudocode example update method to illustrate how these dependencies crop up:
Square.updateTop() {
var prevShape = null;
if (this.index != 0) {
prevShape = this.parentContainer.shapes[this.index - 1];
}
var nextSquareInContainer = null;
for (var i = this.index; i < this.parentContainer.shapes.length; i++) {
var shape = this.parentContainer.shapes[i];
if(shape instanceof Square) {
nextSquareInContainer = shape;
break;
}
}
var top = 0;
if (prevShape != null && nextSquareInContainer != null) {
top = prevShape.top + nextSquareInContainer.width;
} else {
top = 22;
}
this.top = top;
}
So, any square objects added to the shapeConatiner will depend on the previous shape's top value and the next square found in the container's width value for its top value.
Here is some code to set up an example shape container:
var shapeContainer = new ShapeContainer();
var triangle = new Triangle();
var circle = new Circle();
var square1 = new Square();
var square2 = new Square();
shapeContainer.addShape(triangle, 0);
shapeContainer.addShape(circle, 1);
shapeContainer.addShape(square1, 2);
shapeContainer.addShape(square2, 3);
So, I guess the crux of the issue is, if I update the above circle's top value, I want the top value of square1 to be automatically updated (because there is a one way dependency between square1's top value, and circle's top value). So one way I can do this (the way I've been doing it, in combination with some other specific knowledge of my problem domain to simplify the calls), is to add the code similar to the following to Circle's updateTop method (really it would have to be added to each shape's updateTop method):
Circle.updateTop() {
// Code to actually calculate and update Circle's top value, note this
// may depend on its own set of dependencies
var nextShape = this.parentContainer.shapes[this.index + 1];
if (nextShape instanceof Square) {
nextShape.updateTop();
}
}
This type of design is fine for a few simple dependencies between objects, but my project has dozens of types of objects with probably hundreds of dependencies between their properties. I've coded it this way, but it is very difficult to reason about when trying to add new features, or troubleshoot a bug.
Is there some sort of design pattern out there to set up dependencies between object properties, and then when one property is updated, it updates all of the properties on other objects that depend on it (which may then trigger further updating of properties that depend on the now newly updated properties)? Some sort of declarative syntax for specifying these dependencies would probably be best for readability/maintainability.
Another issue is, a property may have several dependencies, that ALL must be updated before I want that property to update itself.
I've been looking into a pub/sub type of solution, but I thought this was a complicated enough problem to reach out for help. As a side note, I'm working in javascript.
Here is the hackish solution I came up with. I create a wrapper class, that you pass in anonymous functions for getter/setter/updaters. Then you make a call of prop1.dependsOn(prop2) to declaratively set up dependencies. It involves setting up a directed acyclic graph of the dependencies between object properties, and then when a property value is updated, explicitly making a call to resolve the related dependencies using a topological sort. I didn't put much thought into efficiency, and I bet somebody could come up with a much more robust/performant solution, but I think this will do for now. Sorry for the code dump, but I thought it could be of some help to somebody trying to solve a similar problem down the road. If somebody wants to make this syntactically cleaner, be my guest.
// This is a class that will act as a wrapper for all properties
// that we want to tie to our dependency graph.
function Property(initialValue, ctx) {
// Each property will get a unique id.
this.id = (++Property.id).toString();
this.value = initialValue;
this.isUpdated = false;
this.context = ctx;
Property.dependsOn[this.id] = [];
Property.isDependedOnBy[this.id] = [];
Property.idMapping[this.id] = this;
}
// Static properties on Property function.
Property.id = 0;
Property.dependsOn = {};
Property.isDependedOnBy = {};
Property.idMapping = {};
// Calling this updates all dependencies from the node outward.
Property.resolveDependencies = function (node) {
node = node.id;
var visible = [];
// Using Depth First Search to mark visibility (only want to update dependencies that are visible).
var depthFirst = function (node) {
visible.push(node);
for (var i = 0; i < Property.isDependedOnBy[node].length; i++) {
depthFirst(Property.isDependedOnBy[node][i]);
}
};
depthFirst(node);
// Topological sort to make sure updates are done in the correct order.
var generateOrder = function (inbound) {
var noIncomingEdges = [];
for (var key in inbound) {
if (inbound.hasOwnProperty(key)) {
if (inbound[key].length === 0) {
// Only call update if visible.
if (_.indexOf(visible, key) !== -1) {
Property.idMapping[key].computeValue();
}
noIncomingEdges.push(key);
delete inbound[key];
}
}
}
for (var key in inbound) {
if (inbound.hasOwnProperty(key)) {
for (var i = 0; i < noIncomingEdges.length; i++) {
inbound[key] = _.without(inbound[key], noIncomingEdges[i]);
}
}
}
// Check if the object has anymore nodes.
for (var prop in inbound) {
if (Object.prototype.hasOwnProperty.call(inbound, prop)) {
generateOrder(inbound);
}
}
};
generateOrder(_.clone(Property.dependsOn));
};
Property.prototype.get = function () {
return this.value;
}
Property.prototype.set = function (value) {
this.value = value;
}
Property.prototype.computeValue = function () {
// Call code that updates this.value.
};
Property.prototype.dependsOn = function (prop) {
Property.dependsOn[this.id].push(prop.id);
Property.isDependedOnBy[prop.id].push(this.id);
}
function PropertyFactory(methodObject) {
var self = this;
var PropType = function (initialValue) {
Property.call(this, initialValue, self);
}
PropType.prototype = Object.create(Property.prototype);
PropType.prototype.constructor = PropType;
if (methodObject.get !== null) {
PropType.prototype.get = methodObject.get;
}
if (methodObject.set !== null) {
PropType.prototype.set = methodObject.set;
}
if (methodObject.computeValue !== null) {
PropType.prototype.computeValue = methodObject.computeValue;
}
return new PropType(methodObject.initialValue);
}
And here is an example of what setting up a property looks like:
function MyClassContainer() {
this.children = [];
this.prop = PropertyFactory.call(this, {
initialValue: 0,
get: null,
set: null,
computeValue: function () {
var self = this.context;
var updatedVal = self.children[0].prop.get() + self.children[1].prop.get();
this.set(updatedVal);
}
});
}
MyClassContainer.prototype.addChildren = function (child) {
if (this.children.length === 0 || this.children.length === 1) {
// Here is the key line. This line is setting up the dependency between
// object properties.
this.prop.dependsOn(child.prop);
}
this.children.push(child);
}
function MyClass() {
this.prop = PropertyFactory.call(this, {
initialValue: 5,
get: null,
set: null,
computeValue: null
});
}
var c = new MyClassContainer();
var c1 = new MyClass();
var c2 = new MyClass();
c.addChildren(c1);
c.addChildren(c2);
And here is an example of actually updating a property once all of this infrastructure is set up:
c1.prop.set(3);
Property.resolveDependencies(c1.prop);
I feel like this is a pretty powerful pattern for programs that require really complicated dependencies. Knockout JS has something similar, with computedObservables (and they use a wrapper in a similar fashion), but you can only tie the computed property to other properties on the same object from what I can tell. The above pattern allows you to arbitrarily associate object properties as dependencies.

How can I make Ember.js handlebars #each iterate over objects?

I'm trying to make the {{#each}} helper to iterate over an object, like in vanilla handlebars. Unfortunately if I use #each on an object, Ember.js version gives me this error:
Assertion failed: The value that #each loops over must be an Array. You passed [object Object]
I wrote this helper in attempt to remedy this:
Ember.Handlebars.helper('every', function (context, options) {
var oArray = [];
for (var k in context) {
oArray.push({
key : k,
value : context[k]
})
}
return Ember.Handlebars.helpers.each(oArray, options);
});
Now, when I attempt to use {{#every}}, I get the following error:
Assertion failed: registerBoundHelper-generated helpers do not support use with Handlebars blocks.
This seems like a basic feature, and I know I'm probably missing something obvious. Can anyone help?
Edit:
Here's a fiddle: http://jsfiddle.net/CbV8X/
Use {{each-in}} helper. You can use it like like {{each}} helper.
Example:
{{#each-in modelWhichIsObject as |key value|}}
`{{key}}`:`{{value}}`
{{/each-in}}
JS Bin demo.
After fiddling with it for a few hours, I came up with this hacky way:
Ember.Handlebars.registerHelper('every', function(context, options) {
var oArray = [], actualData = this.get(context);
for (var k in actualData) {
oArray.push({
key: k,
value: actualData[k]
})
}
this.set(context, oArray);
return Ember.Handlebars.helpers.each.apply(this,
Array.prototype.slice.call(arguments));
});
I don't know what repercussions this.set has, but this seems to work!
Here's a fiddle: http://jsfiddle.net/CbV8X/1/
I've been after similar functionality, and since we're sharing our hacky ways, here's my fiddle for the impatient: http://jsfiddle.net/L6axcob8/1/
This fiddle is based on the one provided by #lxe, with updates by #Kingpin2k, and then myself.
Ember: 1.9.1, Handlebars: 2.0.0, jQuery 2.1.3
Here we are adding a helper called every which can iterate over objects and arrays.
For example this model:
model: function() {
return {
properties: {
foo: 'bar',
zoo: 'zar'
}
};
}
can be iterated with the following handlebars template:
<ul class="properties">
{{#every p in properties}}
<li>{{p.key}} : {{p.value}}</li>
{{/every}}
</ul>
every helper works by creating an array from the objects keys, and then coordinating changes to Ember by way of an ArrayController. Yeah, hacky. This does however, let us add/remove properties to/from an object provided that object supports observation of the [] property.
In my use case I have an Ember.Object derived class which notifies [] when properties are added/removed. I'd recommend looking at Ember.Set for this functionality, although I see that Set been recently deprecated. As this is slightly out of this questions scope I'll leave it as an exercise for the reader. Here's a tip: setUnknownProperty
To be notified of property changes we wrap non-object values in what I've called a DataValueObserver which sets up (currently one way) bindings. These bindings provide a bridge between the values held by our internal ArrayController and the object we are observing.
When dealing with objects; we wrap those in ObjectProxy's so that we can introduce a 'key' member without the need to modify the object itself. Why yes, this does imply that you could use #every recursively. Another exercise for the reader ;-)
I'd recommend having your model be based around Ember.Object to be consistent with the rest of Ember, allowing you to manipulate your model via its get & set handlers. Alternatively, as demonstrated in the fiddle, you can use Em.Get/Em.set to access models, as long as you are consistent in doing so. If you touch your model directly (no get/set), then every won't be notified of your change.
Em.set(model.properties, 'foo', 'asdfsdf');
For completeness here's my every helper:
var DataValueObserver = Ember.Object.extend({
init: function() {
this._super();
// one way binding (for now)
Em.addObserver(this.parent, this.key, this, 'valueChanged');
},
value: function() {
return Em.get(this.parent, this.key);
}.property(),
valueChanged: function() {
this.notifyPropertyChange('value');
}
});
Handlebars.registerHelper("every", function() {
var args = [].slice.call(arguments);
var options = args.pop();
var context = (options.contexts && options.contexts[0]) || this;
Ember.assert("Must be in the form #every foo in bar ", 3 == args.length && args[1] === "in");
options.hash.keyword = args[0];
var property = args[2];
// if we're dealing with an array we can just forward onto the collection helper directly
var p = this.get(property);
if (Ember.Array.detect(p)) {
options.hash.dataSource = p;
return Ember.Handlebars.helpers.collection.call(this, Ember.Handlebars.EachView, options);
}
// create an array that we will manage with content
var array = Em.ArrayController.create();
options.hash.dataSource = array;
Ember.Handlebars.helpers.collection.call(this, Ember.Handlebars.EachView, options);
//
var update_array = function(result) {
if (!result) {
array.clear();
return;
}
// check for proxy object
var result = (result.isProxy && result.content) ? result.content : result;
var items = result;
var keys = Ember.keys(items).sort();
// iterate through sorted array, inserting & removing any mismatches
var i = 0;
for ( ; i < keys.length; ++i) {
var key = keys[i];
var value = items[key];
while (true) {
var old_obj = array.objectAt(i);
if (old_obj) {
Ember.assert("Assume that all objects in our array have a key", undefined !== old_obj.key);
var c = key.localeCompare(old_obj.key);
if (0 === c) break; // already exists
if (c < 0) {
array.removeAt(i); // remove as no longer exists
continue;
}
}
// insert
if (typeof value === 'object') {
// wrap object so we can give it a key
value = Ember.ObjectProxy.create({
content: value,
isProxy: true,
key: key
});
array.insertAt(i, value);
} else {
// wrap raw value so we can give it a key and observe when it changes
value = DataValueObserver.create({
parent: result,
key: key,
});
array.insertAt(i, value);
}
break;
}
}
// remove any trailing items
while (array.objectAt(i)) array.removeAt(i);
};
var should_display = function() {
return true;
};
// use bind helper to call update_array if the contents of property changes
var child_properties = ["[]"];
var preserve_context = true;
return Ember.Handlebars.bind.call(context, property, options, preserve_context, should_display, update_array, child_properties);
});
Inspired by:
How can I make Ember.js handlebars #each iterate over objects?
http://mozmonkey.com/2014/03/ember-getting-the-index-in-each-loops/
https://github.com/emberjs/ember.js/issues/4365
https://gist.github.com/strathmeyer/1371586
Here's that fiddle again if you missed it:
http://jsfiddle.net/L6axcob8/1/

Game Server OOP Design

I have a class called Room, with an array containing all the Player entities as one of its properties,
players = [];
In the Room class is a method that only returns the players who actually competed in the round.
// below method is called by the room's timer
var getPlayersWhoFinished = function() {
playersWhoFinished = [];
for (i = 0; i < players.length; i++) {
if (players[i].isFinished()) {
playersWhoFinished.push(players[i]);
};
};
return playersWhoFinished;
}
So I know that I could just leave the above in the Room class as is, but I already have three other functions with more complex mapping, in an already large class (300+ lines).
I don't understand how to encapsulate these sort of methods into other classes, as they're so closely related to the Room class and all the the Room reference to be sent to the appropiate users.
Modifying the above code and slotting it into Player class would sort of make sense to me, but the only way I can think of getting this to work is using a static method and sending the room object to it.
// players is now a member of the Player class
Player.getPlayersWhoFinished = function(room, players) {
playersWhoFinished = [];
for (i = 0; i < players; i++) {
if (players[i].getRoom() == room) {
playersWhoFinished.push(players[i]);
}
}
return playersWhoFinished;
}
Anyway, this seems cumbersome and inefficent to me. I've really been struggling to figure out how to make my Room class lithe as possible.
Consider splitting logic into Objects and Collections. It is similar to what backbone offers (Model, Collection).
As collections logic is usually specific to objects it contains, but have some shared functionality as well (simple iterations, filters and so on), you can create generic Collection, and then through Inheritance add more methods in order to fit your needs of that specific Object it stores.
So you would have your room:
function Room() {
// ..
this.players = new PlayerCollection();
// ..
}
For collection I've added some 'bonus' methods, so it would look like:
function Collection() {
this.list = [ ];
this.length = 0;
}
// adds item
Collection.prototype.add = function(item) {
this.list.push(item);
this.length = this.list.length;
}
// removes by index
Collection.prototype.remove = function(index) {
this.list.splice(index, 1);
this.length = this.list.length;
}
// finds one item based on filter function, and triggers callback with item and index
Collection.prototype.findOne = function(fn, callback) {
for(var i = 0, len = this.list.length; i < len; ++i) {
var result = fn(this.list[i]);
if (result) {
return callback(this.list[i], i);
}
}
return callback(null, -1);
}
// filters off
Collection.prototype.filter = function(fn) {
return this.list.filter(fn);
}
Then you would define PlayerCollection, that will have extra method just to filter off players who is finished:
function PlayerCollection() {
Collection.call(this);
}
// some inheritance here
PlayerCollection.prototype = Object.create(Collection.prototype);
PlayerCollection.prototype.constructor = PlayerCollection;
// returns list of finished players
PlayerCollection.prototype.finished = function() {
return Collection.prototype.filter.call(this, function(player) {
return player.isFinished();
});
}
You still can reuse that filter method, as it helps to create some bespoke queries.
Your room logic would look like:
var room = new Room();
// add some players to room
// ...
var finishedPlayers = room.players.finished(); // what you need
It looks clear and straight forward, as well keeps all collection logic away from Room, so you can simply reuse it all over your game code. And improving in one place - would improve it as a whole.
Dividing logic into abstracts like that, helps to scale your code and separate dependencies.
Bear in mind Browser support for filter and if you need -IE8, then get shim from here.
The getPlayersWhoFinished() method belongs to Room, which is the object that should track players. You also are performing a search in O(n) complexity every time you need to find finished players, which can be improved.
You could have a callback mean to be called each time a player finishes:
Player.prototype.onFinished = function() {
this.getRoom().addFinished(this);
}
And then manage a private array in Room containing all the finished players:
function Room() {
this._finishedPlayers = [];
}
Room.prototype.addFinished = function(player) {
this._finishedPlayers.push(player);
}
Room.prototype.getPlayersWhoFinished = function() {
return this._finishedPlayers;
}
As a side note, you should always declare variables with var, or else you will get them declared in the global scope (i.e. usually the window object).

JavaScript variables giving the correct value when stepped through using the console, but not otherwise

I have a variable in a JavaScript constructor that appears to be set to the correct value when stepped through using breakpoints. However, when run without breakpoints, the variable (supposed to be an array that I give it), comes up as an empty array in the console. I don't know whether or not using the get/set property of prototype, as described here. Also-- I'm working in webkit, so if someone could help explain to me why it isn't working there, I'd appreciate it. Thanks!
function Box(inElement){
var self = this;
this.element = inElement;
this.boxes = (function () {
var boxes = [];
for (var i = 0; i < inElement.childNodes.length; ++i) {
if (3 !== inElement.childNodes[i].nodeType) {
boxes.push(inElement.childNodes[i]);
}
}
return boxes;
})();
this.rotation = [-40,-20,0,20,40];
}
Box.prototype =
{
get rotation(){
return this._rotation;
},
set rotation(rotArray){
console.log('rotArray');
console.log(rotArray);
var thisrot;
this._rotation = rotArray;
for(var i=0; i<this.boxes.length; i++){
thisrot = rotArray.shift();
this.boxes[i].style.webkitTransform = 'rotateY(' + thisrot + 'deg) translateZ(170px)';
}
}
}
function loaded()
{
new Box(document.getElementById('area'));
}
window.addEventListener('load',loaded, true);
So, after some fiddling, I discovered that boxes.push(inElement.childnodes[i] is the problematic line. When commented out, the value comes out as expected.
You are removing all elements from your array in the loop inside of set rotation using shift. Arrays are passed by reference in JavaScript, not by value. If you want to create a copy of your array, you will have to use Array.slice:
this._rotation = rotArray.slice();

Functional object basics. How to go beyond simple containers?

On the upside I'm kinda bright, on the downside I'm wracked with ADD. If I have a simple example, that fits with what I already understand, I get it. I hope someone here can help me get it.
I've got a page that, on an interval, polls a server, processes the data, stores it in an object, and displays it in a div. It is using global variables, and outputing to a div defined in my html. I have to get it into an object so I can create multiple instances, pointed at different servers, and managing their data seperately.
My code is basically structured like this...
HTML...
<div id="server_output" class="data_div"></div>
JavaScript...
// globals
var server_url = "http://some.net/address?client=Some+Client";
var data = new Object();
var since_record_id;
var interval_id;
// window onload
window.onload(){
getRecent();
interval_id = setInterval(function(){
pollForNew();
}, 300000);
}
function getRecent(){
var url = server_url + '&recent=20';
// do stuff that relies on globals
// and literal reference to "server_output" div.
}
function pollForNew(){
var url = server_url + '&since_record_id=' + since_record_id;
// again dealing with globals and "server_output".
}
How would I go about formatting that into an object with the globals defined as attributes, and member functions(?) Preferably one that builds its own output div on creation, and returns a reference to it. So I could do something like...
dataOne = new MyDataDiv('http://address/?client');
dataOne.style.left = "30px";
dataTwo = new MyDataDiv('http://different/?client');
dataTwo.style.left = "500px";
My code is actually much more convoluted than this, but I think if I could understand this, I could apply it to what I've already got. If there is anything I've asked for that just isn't possible please tell me. I intend to figure this out, and will. Just typing out the question has helped my ADD addled mind get a better handle on what I'm actually trying to do.
As always... Any help is help.
Thanks
Skip
UPDATE:
I've already got this...
$("body").prepend("<div>text</div>");
this.test = document.body.firstChild;
this.test.style.backgroundColor = "blue";
That's a div created in code, and a reference that can be returned. Stick it in a function, it works.
UPDATE AGAIN:
I've got draggable popups created and manipulated as objects with one prototype function. Here's the fiddle. That's my first fiddle! The popups are key to my project, and from what I've learned the data functionality will come easy.
This is pretty close:
// globals
var pairs = {
{ div : 'div1', url : 'http://some.net/address?client=Some+Client' } ,
{ div : 'div2', url : 'http://some.net/otheraddress?client=Some+Client' } ,
};
var since_record_id; //?? not sure what this is
var intervals = [];
// window onload
window.onload(){ // I don't think this is gonna work
for(var i; i<pairs.length; i++) {
getRecent(pairs[i]);
intervals.push(setInterval(function(){
pollForNew(map[i]);
}, 300000));
}
}
function getRecent(map){
var url = map.url + '&recent=20';
// do stuff here to retrieve the resource
var content = loadResoucrce(url); // must define this
var elt = document.getElementById(map.div);
elt.innerHTML = content;
}
function pollForNew(map){
var url = map.url + '&since_record_id=' + since_record_id;
var content = loadResoucrce(url); // returns an html fragment
var elt = document.getElementById(map.div);
elt.innerHTML = content;
}
and the html obviously needs two divs:
<div id='div1' class='data_div'></div>
<div id='div2' class='data_div'></div>
Your 'window.onload` - I don't think that's gonna work, but maybe you have it set up correctly and didn't want to bother putting in all the code.
About my suggested code - it defines an array in the global scope, an array of objects. Each object is a map, a dictionary if you like. These are the params for each div. It supplies the div id, and the url stub. If you have other params that vary according to div, put them in the map.
Then, call getRecent() once for each map object. Inside the function you can unwrap the map object and get at its parameters.
You also want to set up that interval within the loop, using the same parameterization. I myself would prefer to use setTimeout(), but that's just me.
You need to supply the loadResource() function that accepts a URL (string) and returns the HTML available at that URL.
This solves the problem of modularity, but it is not "an object" or class-based approach to the problem. I'm not sure why you'd want one with such a simple task. Here's a crack an an object that does what you want:
(function() {
var getRecent = function(url, div){
url = url + '&recent=20';
// do stuff here to retrieve the resource
var content = loadResoucrce(url); // must define this
var elt = document.getElementById(div);
elt.innerHTML = content;
}
var pollForNew = function(url, div){
url = url + '&since_record_id=' + since_record_id;
var content = loadResoucrce(url); // returns an html fragment
var elt = document.getElementById(div);
elt.innerHTML = content;
}
UpdatingDataDiv = function(map) {
if (! (this instanceof arguments.callee) ) {
var error = new Error("you must use new to instantiate this class");
error.source = "UpdatingDataDiv";
throw error;
}
this.url = map.url;
this.div = map.div;
this.interval = map.interval || 30000; // default 30s
var self = this;
getRecent(this.url, this.div);
this.intervalId = setInterval(function(){
pollForNew(self.url, self.div);
}, this.interval);
};
UpdatingDataDiv.prototype.cancel = function() {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
})();
var d1= new UpdatingDataDiv('div1','http://some.net/address?client=Some+Client');
var d2= new UpdatingDataDiv('div2','http://some.net/otheraddress?client=Some+Client');
...
d1.cancel();
But there's not a lot you can do with d1 and d2. You can invoke cancel() to stop the updating. I guess you could add more functions to extend its capability.
OK, figured out what I needed. It's pretty straight forward.
First off disregard window.onload, the object is defined as a function and when you instantiate a new object it runs the function. Do your setup in the function.
Second, for global variables that you wish to make local to your object, simply define them as this.variable_name; within the object. Those variables are visible throughout the object, and its member functions.
Third, define your member functions as object.prototype.function = function(){};
Fourth, for my case, the object function should return this; This allows regular program flow to examine the variables of the object using dot notation.
This is the answer I was looking for. It takes my non-functional example code, and repackages it as an object...
function ServerObject(url){
// global to the object
this.server_url = url;
this.data = new Object();
this.since_record_id;
this.interval_id;
// do the onload functions
this.getRecent();
this.interval_id = setInterval(function(){
this.pollForNew();
}, 300000);
// do other stuff to setup the object
return this;
}
// define the getRecent function
ServerObject.prototype.getRecent = function(){
// do getRecent(); stuff
// reference object variables as this.variable;
}
// same for pollForNew();
ServerObject.prototype.pollForNew = function(){
// do pollForNew(); stuff here.
// reference object variables as this.variable;
}
Then in your program flow you do something like...
var server = new ServerObject("http://some.net/address");
server.variable = newValue; // access object variables
I mentioned the ADD in the first post. I'm smart enough to know how complex objects can be, and when I look for examples and explanations they expose certain layers of those complexities that cause my mind to just swim. It is difficult to drill down to the simple rules that get you started on the ground floor. What's the scope of 'this'? Sure I'll figure that out someday, but the simple truth is, you gotta reference 'this'.
Thanks
I wish I had more to offer.
Skip

Categories

Resources