Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

UPDATE

Refactored code - see edit section below.


I am practicing using the Prototype pattern and to do so, I am building a simple CRUD app that allows me to view, add, and delete customers.

Here is a JsFiddle for you to see what I've got so far: http://jsfiddle.net/phillipkregg/cfafr/146/

I will post the code here as well, for quick review:

// Create customer 'class' and store state here
var Customer = function(el) {
    this.el = document.getElementById(el);    
    this.first_name = $("#input_first_name").val();
    this.last_name = $("#input_last_name").val();
    this.name = ""

}

var customers = [];

// In the Customer prototype store methods
Customer.prototype = {

    // utility to log customer array
    logCustomers: function() {
        console.log(customers);
    },

    fullName: function() {
        this.name = this.first_name + " " + this.last_name;
        return this.name;

    },

    addCustomer: function() {
        // clear out the current html to make room for the append later
        this.el.innerHTML = "";

        // create new customer instance
        var cust = new Customer();

        // add customer to the array
        customers.push(cust);

        // iterate through the array and add each customer to a row in the table
        $.each(customers, function() {
            $("#el").append("<tr><td>" + this.fullName() + "</td><td><a id='btn_remove_cust'  class='btn btn-mini btn-danger'>delete</a></td></tr>");
        })

        // Clear out the text boxes
        $("#input_first_name").val("");
        $("#input_last_name").val("");

    },

    // Remove customer from array and hide the row that contained them
    removeCustomer: function(e) {        
        $(e.target).closest('tr').hide();
        customers.splice(e.target, 1);

    }
}


// Default customer object has to be created in order for unobtrusive calls to work
var cust = new Customer("el");



// unobtrusive jQuery event handling below
$("#btn_add_customer").click(function() {
    cust.addCustomer();
});

$("#btn_remove_cust").live("click", cust.removeCustomer);

$("#btn_log_customers_array").click(cust.logCustomers)

There are a few things that I'm concerned about:

1) I'm using jQuery to handle events and I'm trying to make everything as unobtrusive as possible. In doing so, I wasn't exactly sure where I needed to place the event-handling code so I created a separate block below the prototype code to contain the button click events. I'm not sure if this is the best way to go.

2) The events are being passed a function from the prototype - so in order for anything to work I have to new-up an instance of the 'Customer' before the user actually creates a new customer. Seems like there might be a better way - but since I'm using a constructor function, I'm not sure if there is any other way around that. If I change the constructor to an object literal, than I've just got a singleton.

3) Am I handling the removal of 'customers' from the array properly? I created a simple utility function that is wired up to a button so that I could check and make sure that objects were being removed - as well as hidden in the DOM.

Advice is greatly appreciated!


EDIT

Ok, after playing with my app above, I realized that the delete functionality was totally jacked-up to say the least.

I refactored my code to make it so that each new 'Customer' instance would get a unique identifier (to simulate objects coming from a server).

I then took this unique identifier and hid it inside of a span tag and passed that id into the customers array element to get the proper customer to destroy.

Here is the new fiddle: http://jsfiddle.net/phillipkregg/cfafr/217/

And the JavaScript code itself:

// Create customer 'class' and store state here
var Customer = function(el) {
    // added the id field to simulate id from server
    this.id = 0;
    this.el = document.getElementById(el);
    this.first_name = $("#input_first_name").val();
    this.last_name = $("#input_last_name").val();
    this.name = ""

}

var customers = [];

// In the Customer prototype store methods
Customer.prototype = {

    // utility to log customer array
    logCustomers: function() {
        console.log(customers);
    },

    fullName: function() {
        this.name = this.first_name + " " + this.last_name;
        return this.name;

    },

    addCustomer: function() {
        // clear out the current html to make room for the append later
        this.el.innerHTML = "";
        // create new customer instance
        var cust = new Customer("el");


        // increment and create unique id for customer
        var cust_id = this.id++;

        cust.id = cust_id;

        // add customer to the array
        customers.push(cust);              

        // iterate through the array and add each customer to a row in the table
        //$.each(customers, function() {
        for (var i = 0; i < customers.length; i++) {

            $("#el").append('<tr><td>' + customers[i].fullName() + '</td><td><a id="btn_remove_cust" class="btn btn-mini btn-danger">delete</a><span class="hidden_id">' + customers[i].id + '</span></td></tr>');

        }
        //})
        // Clear out the text boxes
        $("#input_first_name").val("");
        $("#input_last_name").val("");


    },

    // Remove customer from array and hide the row that contained them
    removeCustomer: function(e) {
        // hide the row
        $(e.target).closest('tr').hide();
        // get the value of the hidden span        
        var target_id = ($(e.target).next('span').text());
        // remove the array element with the unique id        
        customers.splice(target_id, 1);


    }
}


// Default customer object has to be created in order for unobtrusive calls to work
var cust = new Customer("el");



// unobtrusive jQuery event handling below
$("#btn_add_customer").click(function() {
    cust.addCustomer();
});

$("#btn_remove_cust").live("click", cust.removeCustomer);

$("#btn_log_customers_array").click(cust.logCustomers);

$("#input_first_name").bind('keypress', function(e) {
    var cust = new Customer("el");
    var code = (e.keyCode ? e.keyCode : e.which);
    if (code == 13) {
        cust.addCustomer();
    }

});​

Please let me know if I'm overcomplicating this - or if I've jacked up something else.
Thanks! :)

share|improve this question
add comment

1 Answer

Here's are a few things that I noticed.

1

The control and flow of the application needs to be seperated into smaller logical groups. The customers should be a container and controller for the customers, not the otherway around. For example, Customer.prototype.addCustomer should be associated with Customers.prototype.addCustomer, since Customers is a container for customer objects.

2

this.id should be a property inside the Customer constructor. Ideally, the id value should be set to null until it is added to the Customers container.

3

Setting an object's prototype to an object over-writes the entire prototype, which means that you lose the reference to the constructor object. So it's better if you add values and functions to the prototype one at a time like so.

// ok but you lost a few values.
Customer.prototype = {
    method1: function(){
        //...
    }
};

//best
Customer.prototype.method1 = function(){
    //...
};

4

Pass values to the constructor rather than have the constructor go out and find them.

// ok
var Customer = function(el) {
    this.el = document.getElementById(el);    
    this.first_name = $("#input_first_name").val();
    this.last_name = $("#input_last_name").val();
    this.name = ""
}

// best
var Customer = function(el, firstName, lastName ) {
    this.el = document.getElementById(el);    
    this.first_name = firstName;
    this.last_name = lastName;
    this.name = "";
       this.id;
}   

Here's a free online book to help you to understand MVC http://addyosmani.github.com/backbone-fundamentals/

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.