jQuery插件仅使用最后一个元素的值

时间:2015-09-24 20:06:21

标签: javascript jquery

我构建了一个插件,它应该将任何按钮转换为模式样式,给定一个可以获取表单的URL。

只有一个元素可以正常工作,但是当选择器返回多个元素时,所有按钮都使用最后一个元素的数据,当get&在插件中调用post方法。

我已经在SO中尝试了几个已回答的问题,但是我们无法找到并修复错误。看起来我错过了什么。

这里是完整的代码。您会看到一些{% django tags %}{{ django context variables }}但只是忽略它们。

谢谢!

一个。

编辑:错字; EDIT2:添加了html; EDIT3:删除了django标签和上下文变量。

<div class="modal fade" id="modal-1234" data-uuid="1234">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                <h4 class="modal-title" id="title-1234">Title</h4>
            </div>
            <div class="modal-body" id="body-1234">Body</div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal" id="cancel-1234">Close</button>
                <button type="button" class="btn btn-primary" id="confirm-1234">Save changes</button>
            </div>
        </div>
    </div>
</div>

<script type="text/javascript">
(function($){
    // define the modalform class
    function ModalForm($button){
        /*
        You can use ModalForm to automate the ajax-form-modal process with TB3.

        Usage:

        var mf = new ModaForm($('#my-button'));  // that's it
        */
        self = this;
        self.$button = $button;
        self.$modal = $('#modal-1234');
        // get vars
        self.target = self.$button.attr('data-target');
        self.uuid = self.$modal.attr('data-uuid');
        self.$modal_title = $('#title-' + self.uuid);
        self.$modal_body = $('#body-' + self.uuid);
        self.$modal_confirm = $('#confirm-' + self.uuid);
        self.modal_confirm_original_text = self.$modal_confirm.html()
        self.$modal_cancel = $('#cancel-' + self.uuid);
        self.$alerts = $('[data-exsutils=push-alerts]').first();
        self.$spinner = $('<p class="center"><i class="ace-icon fa fa-spinner fa-spin orange bigger-300"></i></p>');
        // bind button click to _get
        self.$button.on('click', function(e){
            e.preventDefault();
            self._get();
        });
    }

    ModalForm.prototype._get = function(){
        /*
        Issue a get request to fetch form and either render form or push alert when complete.
        */
        var self = this;
        // show modal, push spinner and change title
        self.$modal.modal('show');
        self.$modal_body.html(self.$spinner);
        self.title = typeof(
            self.$button.attr('data-title')) !== 'undefined' ? 
            self.$button.attr('data-title') : 'Modal form';
        self.$modal_title.html(self.title);
        // get content
        $.ajax({
            type: 'GET',
            url: self.target,
            statusCode: {
                403: function(data){
                    // close modal
                    // forbidden => close modal & push alert
                    setTimeout(function(){
                        self.$modal.modal('hide');
                        self.$alerts.html(data.responseText);
                    }, 500);
                },
                200: function(data){
                    // success => push form
                    // note that we will assign self.$form
                    var $response = $(data);
                    self.$form = $response.filter('form').first();
                    self.$modal_body.html($response);
                    self.$modal_confirm.click(function(e){
                        e.preventDefault();
                        self._submit(self.$form);
                    });
                }
            },
            error: function(data){
                console.log(data);
            }
        });
    }

    ModalForm.prototype._submit = function(){
        /*
        Post this.$form data and rerender form or push alert when complete.
        */
        var self = this;
        // change submit button to loading state
        self.$modal_confirm.addClass('disabled').html('Loading...');
        // issue pot request
        // cleanup
        // rebind if rerender or push alerts
        $.ajax({
            type: 'POST',
            url: self.$form.attr('action'),
            data: self.$form.serialize(),
            statusCode: {
                200: function(data){
                    // this is a form error
                    // so we must rerender and rebind form
                    // else we need to rerender and rebind
                    self.$form.remove();
                    var $response = $(data);
                    self.$form = $response.filter('form').first();
                    self.$modal_body.html($response);
                    self.$modal_confirm.on('click', function(e){
                        e.preventDefault();
                        self._submit(self.$form);
                    });
                },
                201: function(data){
                    // this means object was created
                    // so we must push an alert and clean up
                    self.$form.remove();
                    delete self.$form;
                    self.$modal.modal('hide');
                    self.$modal_body.html('');
                    // we will push alerts only if there is no 201 callback
                    var callback_201 = self.$button.attr('data-callback-201');
                    if (typeof(window[callback_201]) !== 'undefined') {
                        window[callback_201](data);
                    } else {
                        self.$alerts.prepend(data);
                    };
                },
                403: function(data){
                    // this means request was forbidden => clean up and push alert
                    self.$form.remove();
                    delete self.$form;
                    self.$modal.modal('hide');
                    self.$modal_body.html('');
                    self.$alerts.prepend(data.responseText);
                }
            },
            complete: function(){
                // reset button
                self.$modal_confirm.removeClass('disabled').html(
                    self.modal_confirm_original_text);
            }
        });
    }
    window.ModalForm = ModalForm;

    // define plugin
    $.fn.modalForm = function(){
        var self = this;
        return self.each(function(){
            var el = this;
            var _ = new window.ModalForm($(el));
            $.data(el, 'modalform', _);
        });
    }

    // run plugin
    $('[data-exsutils=modal-form]').modalForm();
})(jQuery);
</script>

@Daniel Arant编辑:

可以找到带有简化工作版插件代码的jsFiddle here

我请注意:请阅读所选答案。这个jsfiddle +添加var self = this将为您提供问题的完整画面和周围的好方法。

1 个答案:

答案 0 :(得分:1)

问题的根源是self = this构造函数中的行ModalForm。由于您未在var之前使用关键字self,因此JavaScripts解释器认为self是全局window对象的属性,并将其声明为此类。因此,每次调用ModalForm构造函数时,self都会接受一个新值,并且构造函数为先前按钮创建的事件处理程序中对self的所有引用都指向新的,大多数最近的ModalForm实例已分配给全局self属性。

要解决此特定问题,只需在var之前添加关键字self = this即可。这使得self成为局部变量而不是全局变量,click事件回调函数将指向它们自己的ModalForm实例,而不是指向self的最后一个实例。

我根据您的代码创建了一个有效的jsFiddle,可以找到here

为了简单起见,我删除了插件代码以消除ajax调用。我也删除了所有的uuid引用。一旦获得对作为jQuery对象的模态的引用,就可以使用jQuery的.find()方法来获取对模态的各个组件的引用。

如果您对我的插件的快速和脏修改有任何疑问