There are a lot of things going on here, so I'll try to run the line between being brief and being fully descriptive.
Overall goal: I'm creating a barebones (no CSS) admin panel that interfaces with a Parse.com NoSQL/MongoDB database, using HTML forms and Backbone.js to control the communication and save user-inputted information into the Parse database. I am not performing any validation other than some basic stuff client side.
Background: For one specific task, I am doing two things: 1) Grabbing information from Parse.com's database on "page load" (not EXACTLY at page load, but I am not certain how to render the view correctly without doing this - when the user selects the "add purchase" option, the addPurchase View is generated, and I make form submit once with a 0 value to query the database and append the results to the screen - I think this may be causing the issue) and using jQuery to render the information to the HTML page. 2) Then, I am asking the user to select one of 4 options, upon submission of which I will record this as a transaction and generate an entry in a "purchase log" table also with Parse.com.
The problem: The view renders successfully, and the values are successfully retrieved from the database and placed on the page. However, when the user submits the form indicating which option they choose, the resulting transaction record is being stored in the database at a rate of some function of 'n', where n is the number of times a transaction record has already been saved in the current session. If I refresh the view, the 'n' resets. The more times I save without refreshing the page, the more duplicate entries are saved.
I'm new to BackboneJS, Parse.com, and MV* frameworks in general. So I definitely think my code could use some cleanup, and I also feel like I'm missing a key piece of information about how Backbone/HTML forms/Views/the DOM works. So I apologize in advance for any sloppy code; I'm totally cool with any suggestions for cleanup you have as well =P.
My Code: There are a number of places where something could be going wrong, I'll try to keep it succinct.
In the HTML, I have a set of radio buttons that allows the user to decide what action they want to perform. Depending on which button is selection, different forms will render to the browser. Once a form is submitted, Parse attempts to save the values in the database and upon successful save, calls back to the browser with an alert saying save was successful, and then a new AdminPanelView() is called.
The problem of multiple saves happened with other actions too, but I solved the problem by adding the following two lines immediately after the save function:
this.undelegateEvents();
delete this;
However, when I do that inside the query's success block in the addPurchase function, I get a console error telling me that undelegateEvents() is not a function of 'this', and the debugger tells me that 'this' is assigned to the Window at the time this call is made.
If I try to move those same two lines to just after the query function as well, it appears that nothing gets saved at all. The view just immediately switches back to a fresh AdminPanelView, without saving.
The behavior also changes depending on where I put 'return false' statements throughout the addPurchase function, but I haven't been able to figure out exactly what the returns are doing and I've just been playing whack-a-mole with them without really understanding what is happening in the code.
Please help me figure out what I'm doing wrong here! I feel like I'm misunderstanding a core concept here, so I'm eager to find out what it is and learn more about how Backbone and Parse works.
The behavior of the form is governed by some Backbone code:
var AdminPanelView = Parse.View.extend({
events: {
"click form.manageOperations": "manageOperations",
"submit form#newPurchaseInfo": "addPurchase",
//other stuff too
},
el: ".content",
initialize: function(){
this.render();
_.bindAll(this, "manageOperations", "addPurchase");
this.manageOperations();
},
render: function(){
this.$el.html(_.template($("#admin_panel_template").html()))
this.delegateEvents();
},
manageOperations: function()
{
this.$(".inputInfo").hide();
var v = this.$("input[name=defineOperation]:checked").val();
if (v=="add-purchase") { this.$("#newPurchaseInfo").show();
this.$("#newPurchaseInfo").submit();}
else if //cases for the other options - normally I just
call this.$("#new[Whatever]Info.show();
},
addPurchase: function() {
var Perk = Parse.Object.extend("Perk");
var query = new Parse.Query(Perk);
query.find({
success: function(results)
{
var i = 1;
for (var r in results)
{
this.$("#perk"+i+"co").html(results[r].get("company"));
this.$("#perk"+i+"desc").html(results[r].get("description"));
i++;
}
var purchase = Number(this.$("#newPurchaseInfo .perkChoice").val());
// I think this line may be causing the issue.
if (purchase!=0)
{
alert("you indicated you want to use perk # " + purchase +", "
+ "which indicates " + results[purchase-1].get("description")
+ " from " + results[purchase-1].get("company"));
var Purchase = Parse.Object.extend("PurchaseLog");
var purchaseEntry = new Purchase();
user = Parse.User.current();
purchaseEntry.save(
{
info : info,
}, {
success: function(purchase)
{
alert("purchase saved successfully");
new AdminPanelView();
return false;
},
error: function(purchase, error)
{
alert("purchase NOT saved: code " + error.code + ", " + error.message);
}
});
}
return false;
},
error: function(error)
{
alert("error code " + error.code + ": " + error.message);
}
});
// this.undelegateEvents();
// delete this;
return false;
},