I am currently building a website like PCPartPicker but for watercooling parts for a school project. I dove in and I am having some issues. The most important on being this:
Here is my object constructor to start
var cpuCollection = [];
var myComputer = [];
function CPU(frequency,cores,socket,name) {
this.name = name;
this.frequency = frequency;
this.cores = cores;
this.socket = socket;
cpuCollection.push(this);
}
var i75930k = new CPU(3.6, 6, 2011.3, "i7 5930k");
var i54690k = new CPU(3.6, 4, 1150, "i5 4960k");`
After I built the object constructor I made some test objects using real computer parts.
In my HTML I have drop down menus that are populated by the objects on load using this code:
$(cpuCollection).each(function() {
$('#cpusel').append($("<option> " + this.name + "</option>"))
});
From there I wanted to make it so that when an option was selected in the dropdown the proper object would be pushed into the myCPU var for compatibility testing in another function. The code I used to accomplish this is as follows:
$('#cpusel').change(function() {
myCPU = new CPU();
$(cpuCollection).each(function(){
if(this.name = $('#cpusel :selected').text()) {
myCPU = this;
}
});
});
Unfortunately this code currently isn't working and is telling me that myCPU.socket is 1150 when the i75930k is selected when it really should be 2011.3. I am getting to wits end here and want to make some progress.
Thanks for the help in advance.
Edit: I fixed the equals sign issue and now I am thinking that the problem may be stemming from the way I push the objects into the cpuCollection array. When I try and log cpuCollection I get [CPU, CPU] which is obviously not what I want. How can I push the CPU objects on creation into cpuCollection with all of their properties intact.
Try this in your if() statement:
$('#cpusel').change(function() {
myCPU = new CPU();
$(cpuCollection).each(function(){
if(this.name === $('#cpusel :selected').text()) {
myCPU = this;
}
});
So, there were a few issues with some of your logic/syntax, and I will try to address them individually so you can better understand how I got a working solution:
1) You are pushing the element to an array from inside your object definition. This is typically bad practice, as it is not reusable, and will throw an error if an array called cpuCollection is not defined prior to the instantiation of that instance of the CPU object. It is better to say cpuCollection.push(new CPU(...));
2) When you append the options to the dropdown list, you should add the value property as well, so you can more easily grab the value in #3
3) If you set the value propery on the <option> elements, there is no need to look for the text of the selected option, you can simplify your selector to $('#cpusel').val()
4) There is no need to wrap your arrays in a jQuery object by saying $(cpuCollection).each(...), you can (and should) use the built-in vanilla javascript array operations.
5) I changed your .each() in the change handler to be a .some() this is because when you return true from .some() it stops any further iteration, which is what you want. Previously, it would continue to loop to the end, even if it already found the matching CPU.
6) I added a myCPU variable and instantiated it to null, so if you are running in strict mode, your change handler wouldn't throw an error for the variable not having been previously defined.
7) Your logic in your if statement was doing an assignment, rather than a comparison because you used = instead of == or ===, simple mistake.
Hope this helps!
var cpuCollection = [];
var myComputer = [];
var myCPU = null;
function CPU(frequency,cores,socket,name) {
this.name = name;
this.frequency = frequency;
this.cores = cores;
this.socket = socket;
}
cpuCollection.push(new CPU(3.6, 6, 2011.3, "i7 5930k"));
cpuCollection.push(new CPU(3.6, 4, 1150, "i5 4960k"));
cpuCollection.forEach(function(cpu, index) {
$('#cpusel').append($('<option value="'+ cpu.name + '">' + cpu.name + '</option>'))
});
$('#cpusel').change(function() {
myCPU = new CPU();
cpuCollection.some(function(cpu, index){
if(cpu.name === $('#cpusel').val()) {
myCPU = cpu;
return true;
}
});
console.log(myCPU);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="cpusel"></select>
There is simple way(s) :
var cpuCollection = [];
var myComputer = [];
function CPU(frequency,cores,socket,name) {
cpuCollection.push({
name: name,
frequency: frequency,
cores: cores,
socket: socket
});
}
var i75930k = CPU(3.6, 6, 2011.3, "i7 5930k");
var i54690k = CPU(3.6, 4, 1150, "i5 4960k");
$(cpuCollection).each(function(i,cpu) {
var option = $('<option/>').html(cpu.name).data('cpu',cpu);
$('#cpusel').append(option);
});
$('#cpusel').change(function() {
var selected = $(this).find('option:selected');
var text = $(selected).text();
var myCPU;
// You can simply use : myCPU = $(selected).data("cpu")
console.log('via data:',$(selected).data("cpu"));
$(cpuCollection).each(function(i,cpu){
if($.trim(cpu.name) == $.trim(text)) {
myCPU = cpu;
// return false; ==> break the each();
}
});
console.log('via each:',myCPU);
});
See this demo.
Related
I'm pretty new (a few weeks in) to js and have a question about an incremental game I'm developing. My issue has to do with creating an array from an object I have and then fetching a property of the object, which is used in a compare statement and updated in my HTML.
I have the following object called UPGRADES:
var UPGRADES = {
newClothes: {
name: "New Clothes",
desc: "Give your bums a new look and some more motivation! \n Bum
production bonus: 100%",
moneyCost: 1000,
scienceCost: 10,
requiredScience: 10,
buildingAffected: BUILDINGS.bumBuilding,
upgVal: 2,
id: 'newClothes'
},
//{upgrade 2}
//{upgrade 3 etc.}
}
For one part of my code I need to go through each element of UPGRADES, return the nth object WITHIN "upgrades" (with newClothes as index 0), and then call (Nth index.scienceCost).
So far I've done the following:
var numBuildings = objectLength(BUILDINGS);
var numUpgrades = objectLength(UPGRADES);
function checkVisiblityOnUpgrades () {
var upgArray = [];
for (var a = 0; a < numUpgrades; a++) {
upgArray[a] = Object.keys(UPGRADES)[a].toString();
console.log(UPGRADES.upgArray[a]);
if (UPGRADES.upgArray[a].requiredScience <= resources.science) {
var idString = upgArray[a].id.toString();
getId(idString.concat("Button")).style.visibility = "visible";
getId(idString.concat("MoneyCostDisp")).innerHTML =
numFormat(upgArray[a].moneyCost);
getId(idString.concat("ScienceCostDisp")).innerHTML =
numFormat(upgArray[a].scienceCost);
}
}
}
I get this error along with it:
Uncaught TypeError: Cannot read property '0' of undefined
at checkVisiblityOnUpgrades (game.js:268)
at update (game.js:290)
268 is console.log(UPGRADES.upgArray[a]);
I was wondering how I would actually go about grabbing the values of the object I wanted. I'm creating an array in checkVisibilityOnUpgrades() so I can iterate through each upgrade with a for loop.
Another question I have is: If I was going to store 100+ instances of upgrades, would it be better to switch UPGRADES to an array rather than its own object? That way I could grab values a lot more easily.
You can drastically simplify your initial logic there with Object.entries:
Object.entries(UPGRADES).forEach(({ key, thisUpgradeObject }) => {
// `key` references the outer property, eg., 'newClothes'
// `thisUpgradeObject` references the inner object
});
So
Object.entries(upgArray).forEach(({ key, obj }) => {
const {
requiredScience,
id,
moneyCost,
scienceCost,
} = obj;
if (requiredScience < resources.science) return;
const idString = id.toString();
getId(idString.concat("Button")).style.visibility = "visible";
getId(idString.concat("MoneyCostDisp")).innerHTML = numFormat(moneyCost);
getId(idString.concat("ScienceCostDisp")).innerHTML = numFormat(scienceCost);
});
I see the problem here:
You create an array called upgArray, but then try to access UPGRADES.upgArray which is undefined. What you want to write there is likely UPGRADES[upgArray[a]].
function checkVisiblityOnUpgrades () {
var upgArray = Object.keys(UPGRADES);
for (var a = 0; a < numUpgrades; a++) {
if (UPGRADES[upgArray[a]].requiredScience <= resources.science) {
var idString = UPGRADES[upgArray[a]].id.toString();
getId(idString.concat("Button")).style.visibility = "visible";
getId(idString.concat("MoneyCostDisp")).innerHTML =
numFormat(UPGRADES[upgArray[a]].moneyCost);
getId(idString.concat("ScienceCostDisp")).innerHTML =
numFormat(UPGRADES[upgArray[a]].scienceCost);
}
}
}
I got to the point with my project where I decided to simplify some of the js functions where I am looking for a parent in a DOM tree, then drill down to the elements many many times in one function. instead I though I will make instances of a function which will keep some data so then I can refer and operate on objects in easy way. I got it working but as I was going along, I decided to extend functionality and add some extra functions like getElementsByClassNameThenTagName.
I loop through the arrays and if add matching elements to the array.
I have noticed (sadly only now) that I am creating an array with elements rather than HTML collection. As a results, I cannot refer to the objects in my findings by typing buttons['reset'].disabled = false;. I can access my reset button by buttons[3].disabled = false; but this would cause a lot of inconvenience.
I am therefore looking for a way to convert my array with object into a HTML collection.
Please see below my current function:
this.getElementsByClassNameThenTagName = function (elementClass, elementTag) {
if (parentNode == null) {
this.init();
}
var results = [];
var regexStr = elementClass;
var regex = new RegExp(regexStr);
var x = moduleNode.getElementsByClassName(elementClass);
// console.log(x);
var y;
for ( var i = 0; i < x.length; i++ ) {
// console.log(i);
y = x[i].getElementsByTagName(elementTag);
// console.log(y);
for (var k=0; k<y.length; k++){
// console.log(y[k]);
results.push(y[k]);
}
// console.log(results);
}
return results;
};
Any suggestions please?
Thanks.
this.getElementsByClassNameThenTagName = function (elementClass, elementTag) {
if (parentNode == null) {
this.init();
}
var results = {}; // thid should be an object (collection)
var x = moduleNode.querySelectorAll("." + elementClass + " " + elementTag);
x.forEach(function(y) {
var name = y.getAttribute("name"); // if you really sure that all the matched elements have names
results[name] = y;
});
return results;
};
Now you can use the results array like this:
var someElement = results['some name'];
NOTE: All the matched elements x should have a name attribute, and all the name attributes of the matched elements should be unique.
This is what i have so far. Basically every time i make a new Item object i need it to create a specific number of another object called Sensor. I've tried a few other methods and none seem to way the work that i need.
function Item (id,number,operator,numOfSensors){
this.id = id;
this.number = number;
this.operator = operator;
this.numOfSensors = numOfSensors;
var sensor = new Sensor[numOfSensors];
}
var Sensor = {
timeStamp:[],
itemPassed: function(){
timeStamp.push(Date.now());
}
}
Thanks so much for any help :) i'm a bit new to js
EDIT:
Hey guys! Thanks for the help. Basically my issue is neatly making an array of Objects. In the item object i want to make a [numOfSensors] amount of the Sensor object. I cant seem to find a way to do that. SO i guess my question is how would i go about creating an array of objects with a set number of elements?
Not sure when you really want to call itemPassed() and whether this is not rather a function of Item, but here is some code that might get you get started:
var Item = function (id, number, operator, numOfSensors) {
this.id = id;
this.number = number;
this.operator = operator;
this.numOfSensors = numOfSensors;
var sensorArray = [];
for (var i = 0; i<numOfSensors; i++) {
sensorArray.push(new Sensor());
}
}
var Sensor = function() {
this.timeStamps = [];
}
Sensor.prototype.itemPassed = function(){
this.timeStamps.push(Date.now());
}
See:
How to initialize an array's length in javascript?
http://code.tutsplus.com/tutorials/prototypes-in-javascript-what-you-need-to-know--net-24949
I tried a lot searching and didnt get desired solutions.
What I want to achieve is
var myObject {
id1 : {
name:place_name,
location : place_loc
},
id2 : {
name:place_name,
location : place_loc
},
id3 : {
name:place_name,
location : place_loc
}
}
What I want to do is that Initially I want the properties "id1", "id2".. to be dynamic. And then dynamically assign name:place_name and other properties of each property.
I dont know the number of properties (id1,id2,id3...) hence would like to add them dynamically and following the addition of properties(id1,id2... ) I want to dynamically add the property values. (place_name & place_loc) of each id.
My code looks something like this.
var myObject = {};
myObject[idnumber1].place = "SomePlace1";
myObject[idnumber1].place = "SomeLoc1";
myObject[idnumber2].place = "SomePlace1";
myObject[idnumber2].place = "SomeLoc1";
But it gives error.
I know it seems simple doubt but any help would be grateful.
Thanks in advance. :)
You are trying to set a value of already assigned objects at keys "idnumber1", etc.
What you'll need is to initialize each objects for your ids like this:
var myObject = {};
myObject[idnumber1] = {};
myObject[idnumber1].place = "SomePlace1";
myObject[idnumber2] = {};
myObject[idnumber2].place = "SomeLoc1"
I would do it this way, it's not exactly what you did ask for, but I think it will become easier to change this later on.
function Place(name, location) {
this.name = name;
this.location = location;
}
var myObject = {}
myObject['id1'] = new Place('Foo', 'Bar');
myObject['id2'] = new Place('Internet', 'test');
console.log(myObject);
To dynamically create objects in your collection, you can use a numerical counter variable to create your object collection (myObject["id" + i] = {name: place_name, location: place_loc}).
An example:
var myObject = {};
for (i = 0; i < 20; i++){
myObject["id" + i] = {name: place_name, location: place_loc}
}
In practice, you can use a counter that you increment outside of a loop.
In my Notes Database, I perform an audit when the document is saved. Pretty easy in LotusScript. I grab the original document (oDoc) from the server, then in the document I modified (mDoc), I do a Forall loop that gets the names of each item; forall item in mDoc.items. Grab the same item from oDoc, execute a function with the new item as an argument that will run down a case statement that will see if its a field we care about. if so, I update a set of list values in the document with "When", "Who", "What field", and the "New Value".
I'm doing this in a server side script. In trying this, I discovered a couple of interesting things;
currentDocument is the NotesXSPDocument that contains everything that was just changed.
currentDocument.getDocument() contains the pre-change values. It also returns a NotesDocument which has the "items" field that I can run through.
Thing is, I need something similar in the NotesXSPDocument. Is there a way in an iterative loop to grab the names and values of all items from there?
Here's the broken code. (Currently it's walking through the NotesDocument items, but those are the old values. I'd rather walk down the XSP document items)
function FInvoice_beginAudit() {
var original_doc:NotesDocument = currentDocument.getDocument();
var oItem:NotesItem;
var oItems:java.util.Vector = original_doc.getItems();
var iterator = oItems.iterator();
while (iterator.hasNext()) {
var oItem:NotesItem = iterator.next();
item = currentDocument.getItemValue(oItem.getName());
if (oItem == undefined) {
var MasterItem = ScreenAudit(doc,item,True)
if (MasterItem) { return true }
} else {
if (item.getValueString() != oItem.getValueString()) {
var MasterItem = ScreenAudit(doc,Item,True);
if (MasterItem) { return true }
}
}
}
}
You can get both versions of a document after submit - the original and the one with changed/new values:
original: var original_doc:NotesDocument = currentDocument.getDocument();
changed: var changed_doc:NotesDocument = currentDocument.getDocument(true);
This way you can compare the items for changes.
But, there is a pitfall: after assigning "changed_doc" to currentDocument.getDocument(true) the "original_doc" has the changed values too because both variables point to the same document. That's why we have to copy all items from currentDocument.getDocument() to a new temporary document first and only after get the changed values with currentDocument.getDocument(true). As an alternative you could read the original document from server like you do in LotusScript.
This is a code for detecting changed items as a starting point:
var original_doc:NotesDocument = database.createDocument();
currentDocument.getDocument().copyAllItems(original_doc, true);
var changed_doc:NotesDocument = currentDocument.getDocument(true);
var oItems:java.util.Vector = original_doc.getItems();
var iterator = oItems.iterator();
while (iterator.hasNext()) {
var oItem:NotesItem = iterator.next();
var itemName = oItem.getName();
var cItem:NotesItem = changed_doc.getFirstItem(itemName);
if (cItem.getText() !== oItem.getText()) {
print("changed: " + itemName);
}
oItem.recycle();
cItem.recycle();
}
original_doc.remove(true);
original_doc.recycle();