[英]Buttons onClick wont work properly
Please bear with me as I've only just got in to JavaScript and I am completely new at OOP in Javascript, so... can someone please help me solve my problem? 请忍受,因为我才刚接触JavaScript,而我在Java语言的OOP中是一个全新的人,所以...有人可以帮助我解决我的问题吗? (pardon me for the length and annotations in the code)
(请原谅我的长度和代码中的注释)
To start: I have created 2 objects: Product, Basket A table is created on-load via the 'createProductRows()' function passing in an array of Product objects. 首先,我创建了2个对象:Product,Basket一个表是通过'createProductRows()'函数在加载时创建的,该函数传入Product对象的数组。 This prints out the product information and creates a button which adds a product a the basket.
这将打印出产品信息并创建一个按钮,将产品添加到购物篮中。 And its the button (or maybe something else) that giving me the problem.
它的按钮(或其他一些按钮)给了我这个问题。 *I want the button to call the addProduct() function with the index of the product within the productList array which in turn calls 2 functions;
*我希望按钮使用productList数组中产品的索引来调用addProduct()函数,而后者依次调用2个函数; addToBasket() and display() in the Basket object.. this should add the created elements to the shopping basket table
购物篮对象中的addToBasket()和display()。这应将创建的元素添加到购物篮表中
I am unsure if I'm passing in the productList array correctly or maybe I should use prototypes for the Basket methods, any help to get this working correctly would greatly appreciated. 我不确定我是否正确传递了productList数组,或者我应该对Basket方法使用原型,因此,对使其正常工作的任何帮助将不胜感激。 Thanks
谢谢
var productList = []; // array where product objects are to be held
var basket;
var obj;
//product constructor
var Product = function(name, description, quantity, price, gender) {
obj = this; // a reference to this object //could use
this.name = name;
this.description = description;
this.quantity = quantity;
this.price = price.toFixed(2);
this.gender = gender;
};
//product prototypes
Product.prototype = {
toString: function() { return this.name.toLowerCase(); }
};
Product.prototype.getPrice = function() {
return '\u00A3' + this.price;
};
Product.prototype.getQuantity = function() {
return this.quantity;
};
//instantiate new products
var shorts = new Product('Shorts', 'Stone Wash Demin Shorts', 20, 25.90, 'F');
var bag = new Product('Bag', 'Leather Shoulder Bag', 4, 50.45, 'F');
var blouse = new Product('Blouse', 'Vintage Blue Silk Polka Dot Blouse', 8, 45.99, 'F');
var boots = new Product('Boots', 'Soft Leather Brown Ankle Boots', 3, 65.35, 'F');
var belts = new Product('Belts', 'Woven Finish Fashion Belt', 15, 21.99, 'F');
var shirt = new Product('Shirt', 'Jacquard Pattern Wrangler Western Shirt', 19, 34.87, 'M');
var shoes = new Product('Shoes', 'Suede Ankle Boots', 6, 55.00, 'M');
var trousers = new Product('Trousers', 'Izod Peach Chinos', 23, 31.75, 'M');
var belt = new Product('Belt', 'Suede Casual Belt', 4, 22.98, 'M');
var hat = new Product('Hat', 'Trilby Style Brown Woven Fix', 2, 67.80, 'M');
//push all product objects to an array
productList.push(shorts, bag, blouse, boots, belts, shirt, shoes, trousers, belt, hat);
// basket constructor
var Basket = function(container, products) { // passes in the product list
this.container = container; // this tells me where to add the data
this.products = products; //reference to product values
this.quantity = []; // stores quantities in bag
for (var i=0; i < products.length; i++) { //find product
this.quantity[i] = 0; //amount of each product in basket
// method to add to basket
this.addToBasket = function(index) { //reference to the product to add
this.quantity[index]++;
this.products[i].quantity--; // minus one from the products list
};
// method to remove from basket
this.removeFromBasket = function(index) {
if (this.quantity[index] > 0)
this.quantity[index]--;
this.products[i].quantity++;
};
//displays product
this.display = function () {
for (var i=0; i < this.quantity.length; i++) {
if (this.quantity[i] > 0) {
var tbl = this.container
var row = tbl.insertRow(tbl.rows.length); // create a row element to append cells to
var total_price = this.quantity[i] * this.products[i].price;
//cell values
var desc = this.products[i].description; //for each value add new cell
var qty = this.quantity[i]
var price = this.products[i].price;
var total = total_price;
var remove = createRemoveBtn();
var cell = tbl.rows[i].insertCell(-1); // add a new cell, inserted at end of each row
//append cells
cell.appendChild(desc);
cell.appendChild(qty);
cell.appendChild(price);
cell.appendChild(total);
cell.appendChild(remove);
tbl.appendChild(row); // finally append the rows to the table
function createRemoveBtn() {
var btn = document.createElement('input');
var buttonName = products[i].name.toUpperCase();
btn.type = 'button';
btn.value = 'Remove';
btn.id = buttonName[i]; //append button names from object name
btn.onclick = function() {removeProduct(i);}; //test
return btn;
};//end function 'createRemoveBtn()'
};//end if 'quantity'
};//end for 'basket'
};//end function 'this.display()'
};//end for 'products'
};//end Object 'Basket'
//create a new instance of the Basket object
basket = new Basket(document.getElementById('basketTable').getElementsByTagName('tbody')[0], productList); // *** need to create a new container for the basket
//button functions
function addProduct(item) { //add to basket function
basket.addToBasket(item);
basket.display();
alert(productList[item].name + ' added to basket');
}
function removeProduct(item) { //remove item from basket
basket.removeFromBasket(item);
basket.display();
alert(productList[item].name + ' removed to basket');
}
//displays product table which is called on the body onload event
function createProductRows(products) { // passing in productList[]
var tbl = document.getElementById('productTable').getElementsByTagName('tbody')[0]; // reference to the table to add rows to in the table body
for (var i=0; i < products.length; i++) { // index the productsList (iterate through 0-9)
var myProduct = products[i]; // keep a reference to each individual product - shorts, bag, blouse, etc...
var myRow = tbl.insertRow(tbl.rows.length); // create a row element to append cells to
var myProperties = ['name', 'description', 'quantity', 'price', 'gender']; //store the property names of the products, references to the object data
for (var j=0; j < myProperties.length; j++) // for each property in myProperties [0-4]
{
var myCell = myRow.insertCell(j); //create table cell element
var data = myProduct[myProperties[j]]; // store property values of products
var node = document.createTextNode(data); //add the data to a text node
myCell.appendChild(node); // append text node to table cell
myRow.appendChild(myCell); // add to end of the row
}
var newCell = tbl.rows[i].insertCell(-1); // create a new cell, inserted at end of each row
newCell.appendChild(createAddBtn()); // add buttons to cells
tbl.appendChild(myRow); // finally append the rows to the table
function createAddBtn() {
var btn = document.createElement('input');
var buttonName = products[i].name.toLowerCase(); // to be added to the button's id value
btn.type = 'button';
btn.value = 'Add';
btn.id = buttonName; //append button names from object name
btn.onclick = function() {addProduct(i);};
return btn;
};
};
};
[update] [更新]
In your case the problem may be in the way you create your closure: 就您而言,问题可能出在您创建封包的方式上:
btn.onclick = function() {addProduct(i);};
You could try to log and check out the console to see what the value of i is: 您可以尝试登录并检出控制台,以查看i的值是什么:
btn.onclick = function() {console.log('and i is:',i);addProduct(i);};
When creating closures in a loop the value of i is not what you think it is, you can probably solve it by using IIFE: 在循环中创建闭包时,i的值不是您想的那样,您可以使用IIFE来解决它:
btn.onclick = (function(index) {
return function(){
console.log('and index is:',index);
addProduct(index);
};
}(i));
Problem with setting event handlers is you get the wrong invoking object. 设置事件处理程序的问题是您得到了错误的调用对象。
Here is a copy from the following answer about the invoking object: 这是以下有关调用对象的答案的副本:
The this variable 这个变量
In all the example code you'll see this referring to the current instance. 在所有示例代码中,您将看到这是指当前实例。
The this variable actually refers to the invoking object, it refers to the object that came before the function. 这个变量实际上是指调用对象,它是指函数之前的对象。
To clarify see the following code: 为了澄清,请参见以下代码:
theInvokingObject.thefunction();
The instances where this would refer to the wrong object are usually when attaching event listeners, callbacks or timeouts and intervals. 通常,当附加事件侦听器,回调或超时和间隔时,此实例将指向错误的对象。 In the next 2 lines of code we pass the function, we don't invoke it.
在接下来的两行代码中,我们传递函数,但不调用它。 Passing the function is: someObject.aFunction and invoking it is: someObject.aFunction().
传递函数是:someObject.aFunction,调用它是:someObject.aFunction()。 The this value does not refer to the object the function was declared on but on the object that invokes it.
此值不引用在其上声明该函数的对象,而是在调用它的对象上。
setTimeout(someObject.aFuncton,100);//this in aFunction is window
somebutton.onclick = someObject.aFunction;//this in aFunction is somebutton
To make this in the above cases refer to someObject you can pass a closure instead of the function directly: 在上述情况下,要引用someObject来实现此目的,您可以传递闭包而不是直接传递函数:
setTimeout(function(){someObject.aFuncton();},100);
somebutton.onclick = function(){someObject.aFunction();};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.