简体   繁体   English

按钮onClick无法正常工作

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM