So, I have this jQuery .each
loop, and for the most part its working as intended; there is one issue, but first the loop:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.1.min.js"></script>
<script type="text/javascript">
function Pushpin(){}
Pushpin.prototype.XZX = {
site: null,
getHtmlDescription: function () {
var html = '<b id="infoboxTitle" style="position:absolute; top:10px; left:10px; width:220px;">' + this.site.Name + '</b>';
html += '<a id="infoboxDescription" style="position:absolute; top:30px; left:10px; width:220px; height:120px;">{0}</a>';
var description = 'Headcount: ' + this.site.Headcount + '<br />';
description += 'Leases: ' + this.site.LeaseCount + '<br />';
html = html.replace('{0}', description);
return html;
}
};
var data = [
{"Address":{"City":"Atlanta","Country":"USA","County":"","Latitude":33.9882404987503,"Longitude":-84.1629638209203,"Region":"Southeast","State":"GA","StreetAddress":"Atlanta 177","ZipCode":"30096"},"Headcount":0,"ImageBytes":null,"ImageRefPath":"","LeaseCount":1,"Leases":null,"Name":"Atlanta","NextExpire":"\/Date(1495083600000-0500)\/","Number":"1052","PrimaryUse":"Garage","PropertyID":"OMNI","RecID":32839,"RecordID":1004,"RentableSquareFootage":22000,"SiteRecordID":"DEMO_29626","SiteTotalDollars":0,"Status":null,"Type":"LSE"},
{"Address":{"City":"Bellevue","Country":"USA","County":"","Latitude":47.6043250620083,"Longitude":-122.14236047437,"Region":"Northwest","State":"WA","StreetAddress":"Seattle 51","ZipCode":"98007"},"Headcount":0,"ImageBytes":null,"ImageRefPath":"","LeaseCount":1,"Leases":null,"Name":"Bellevue","NextExpire":"\/Date(1260424800000-0600)\/","Number":"1078","PrimaryUse":"Tower","PropertyID":"OMNI","RecID":32865,"RecordID":1027,"RentableSquareFootage":7652,"SiteRecordID":"DEMO_275651","SiteTotalDollars":0,"Status":null,"Type":"LSE"}
];
var mylist = [];
$.each(data, function (i, item) {
try {
var pin = new Pushpin();
pin.XZX.site = item;
mylist.push(pin);
} catch (e) { alert (e); }
});
$(document).ready(function() {
$('#btnAlert').click(function () {
$('#content').html(mylist[$('#index').val()].XZX.getHtmlDescription());
} );
});
</script>
</head>
<body >
<div style="margin-left:auto; margin-right:auto; width:300px;">
<div style="position:relative; width:250px;">
<select id="index">
<option>0</option>
<option>1</option>
</select>
<input type="submit" id="btnAlert"/>
</div>
<div id="content" style="position:relative;width:250px;"></div>
</div>
</body>
</html>
Also available on jsfiddle: http://jsfiddle.net/M8YS2/
At the end of the loop, mylist[x].site
for any x
all point to the same instance of my data item, how can I get around this?
The issue is that each pin.XYZ
is the same object -- namely Pushpin.prototype.XYZ
.
The simple "fix" is to use:
var pin = new Pushpin(...)
pin.XYZ = {
site: item
// the following will get tedious fast, consider one of the "property copy"
// implementations floating about -- including jQuery.extend
getHtmlDescription: Pushpin.prototype.XYZ.getHtmlDescription
}
Which will assign a new object to the XYZ
property of each new Pushpin object. Of course, this could be designed differently as well :)
At the very least, move XYZ
off the Pushpin.prototype object -- this will allow it to treated nicely as an object (the way that this
is passed about actually makes it nigh-impossible for a function dangling off an object of a prototype to access instance data of the object to which the prototype applies); the end-code might look something like:
// We .. "wrap" the real Pushpin constructor
// somewhere global after Bing Mapi JS loaded
Pushpin = (function (bingPushpin) {
return function Pushpin (...) {
var pin = new bingPushpin(...)
pin.XYZ = new XYZ()
// trick of "returning" from ctor
return pin
}
})(PushPin)
// ...
var pin = new Pushpin(...)
pin.XYZ.site = item
Happy coding.
Pre-update answer:
This actually isn't a scoping issue -- there are no inadvertent closures created and each expression is strictly evaluated.
I suspect there is another problem, such as unexpected input (data contains a bunch of the same item ) or flawed assumption (such that objects are magically cloned) or something unrelated.
Happy coding.
Analysis:
var mylist = [];
$.each(data, function (i, item) {
// creates new object
var pin = new Pushpin(x, y);
// property of new object assigned
// remember that no "duplication" is occurring
pin.site = item;
// new object pushed to array
mylist.push(pin);
});
Therefor, no pin
will be the same but it is possible that item
evaluates to the same object each loop . (The only exception to this is if the Pushpin constructor uses return
to return an existing object, which would be a fun fine indeed.)
Do you need to declare the var pin outside of the .each? then set it to new inside the .each.
var pin;
var mylist = [];
$.each(data, function (i, item) {
try {
pin = new Pushpin(x, y);
pin.site = item;
mylist.push(pin);
} catch (e) { alert (e); }
});
Considering you're within a function I would say yes of course they all point to the same object as you're only passing by reference. After looking around I stumbled upon this - http://my.opera.com/GreyWyvern/blog/show.dml/1725165 - but it doesn't look like there is a straight-forward option for cloning a Javascript object.
Perhaps your best approach would be to write a function that clones an input object and returns it as a new instance?
After reading MoarCodePlz's answer I thought maybe this could help getting around the 'by reference' issue. Haven't verified it though.
var mylist = [];
$.each(data, function (i, item) {
// Creates the new object as a part of yourlist
mylist.push(new Pushpin(x, y));
// property of new object assigned item
mylist[x].site = item;
});
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.