为什么我的客户端保存功能多次触发

Why is my client-side save function firing multiple times?

本文关键字:功能 我的 客户端 保存 为什么      更新时间:2023-09-26

这里有很多事情要做,所以我将尽量在简短和完全描述之间划清界限。

总体目标:我正在创建一个与Parse.com NoSQL/MongoDB数据库接口的barebones(没有CSS)管理面板,使用HTML表单和Backbone.js来控制通信并将用户输入的信息保存到Parse数据库中。我不执行任何验证,除了一些基本的东西客户端。

背景:对于一个特定的任务,我正在做两件事:1)从Parse.com抓取信息的数据库"页面加载"(不是在页面加载,但我不确定如何正确渲染视图没有这样做,当用户选择"添加购买"选项,addPurchase视图生成,和我让表单提交一次0值查询数据库并将结果附加到屏幕-我认为这可能是导致问题)和使用jQuery来呈现信息的HTML页面。2)然后,我要求用户从4个选项中选择一个,提交后我会将其记录为交易,并在Parse.com的"购买日志"表中生成一个条目。

问题:视图成功呈现,并且值成功地从数据库中检索并放置在页面上。但是,当用户提交指示他们选择哪个选项的表单时,生成的事务记录将以某个函数'n'的速率存储在数据库中,其中n是事务记录在当前会话中已经保存的次数。如果我刷新视图,n会重置。在不刷新页面的情况下保存的次数越多,保存的重复条目就越多。

我是BackboneJS, Parse.com和MV*框架的新手。所以我绝对认为我的代码可以使用一些清理,我也觉得我错过了一个关键的信息,关于骨干/HTML表单/视图/DOM是如何工作的。所以我提前为任何草率的代码道歉;我完全不介意你提出的任何清理建议= p

我的代码:有很多地方可能会出错,我会尽量保持简洁。

在HTML中,我有一组单选按钮,允许用户决定他们想要执行的操作。根据所选择的按钮,不同的表单将呈现给浏览器。提交表单后,Parse会尝试将值保存在数据库中,保存成功后,会回调浏览器并提示保存成功,然后调用新的AdminPanelView()。

其他操作也会出现多次保存的问题,但我通过在保存函数之后立即添加以下两行来解决这个问题:

this.undelegateEvents();
delete this;

然而,当我在addPurchase函数的查询成功块内这样做时,我得到一个控制台错误告诉我undelegateEvents()不是'this'的函数,并且调试器告诉我'this'在此调用时分配给窗口。

如果我尝试将相同的两行移动到查询函数之后,似乎根本没有保存任何内容。视图会立即切换回新的AdminPanelView,不需要保存。

行为也会根据我在整个addPurchase函数中放置'return false'语句的位置而变化,但我还不能确切地弄清楚返回是做什么的,我只是在玩打地鼠,而没有真正理解代码中发生的事情。

请帮我找出我在这里做错了什么!我觉得我在这里误解了一个核心概念,所以我渴望找出它是什么,并了解更多关于Backbone和Parse是如何工作的。

表单的行为是由一些主干代码控制的:

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;
},

事实上,我刚刚弄明白了。我喜欢stackoverflow,有时候只写问题描述就足够找到解决方案了!如果我不经常回答自己的问题,我会有更多的声望=P

所以,问题确实是在我的addPurchase函数(下面突出显示的代码)。发生的事情是,为了呈现屏幕,addPurchase视图总是被实例化,初始值为0。然而,正如我之前所做的那样,无论如何,在初始提交时都会调用'this. undelegateevents()'和'delete this'。因此,我基本上删除了视图功能,而没有完全删除视图,直到我试图再次提交表单,此时我会得到一个全新的AdminPanelView()和没有保存消息(值从未保存,因为提交值为0,这意味着save()函数从未被调用)。

我只是使'this. undelegateevents()'和'delete this'方法只有在输入值不为0时才被调用。因为在我的程序逻辑中(不管它多么愚蠢=P), 0只会在呈现addPurchase视图时输入,以便将Perk信息呈现给DOM。

我仍然觉得我的代码很复杂,我愿意听取关于更好的算法、逻辑和结构的建议。这在一定程度上是困难的,因为数据库返回值只在Parse和Backbone函数的success()块的作用域中,所以很难避免一定数量的"厄运之墙"。

query.find({
success: function(results) 
{
var purchase = Number(this.$("#newPurchaseInfo .perkChoice").val());
if (purchase!=0) {
  // attempt to save user in database
        purchaseEntry.save(
        {
            //definition of the object goes here
        }, {
            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);
    // return false;
}
});
//This is the solution:
if (Number(this.$("#newPurchaseInfo .perkChoice").val()) != 0) 
{
    this.undelegateEvents();
    delete this;
}
return false;