多个实例上的jQuery插件设置

时间:2011-11-15 10:15:53

标签: javascript jquery plugins settings defaults

我在jquery插件上的多个实例上设置有问题。

如果我多次投射我的插件并在onclick绑定上提醒他们,它总是会提醒相同的参数。

这是我的插件。

    /**
     * Provide user search for input elements.
     * 
     * Call this jQuery plugin on an input element to add a button
     * for searching the active directory on userdata.
     * Returned data are saved in declared target input elements.
     * 
     * Depends:
     *  jQuery UI Dialog
     *
     * @license http://www.opensource.org/licenses/mit-license.php
     * @version 1.0
     */
    ;(function ( $, window, document, undefined ){

        var PROP_NAME = 'userdata';
        var IS_IFRAME = ( self !== top ) ? true : false;
        var rfuuid = new Date().getTime();

        var $jParent = ( self !== top ) ? window.parent.jQuery.noConflict() : $; 

        /**
         * Userdata manager.
         * Use the singleton instance of this class, $.userdata, to interact with the date picker.
         * Settings for (groups of) date pickers are maintained in an instance object,
         * allowing multiple different settings on the same page.
         */
        function Userdata() {
            this.regional = [];
            this.regional[''] = {
                abortText: 'Abbrechen',
                acceptText: 'Hinzufügen',
                errorTitle: 'Fehler beim Suchen',
                errorFilterText: 'Suchkriterien einschränken.',
                errorVoidText: 'Der gesuchte Kontakt konnte nicht gefunden werden.',
                errorScriptText: 'Bei der Suche ist ein Fehler aufgetreten. Falls der Fehler wieder auftritt, wenden Sie sich bitte an Ihren <a href="%s">Webadministrator.</a>',
                searchText: 'Durchsuchen',
                selectionTitle: 'Namen überprüfen',
                selectionInfoText: '"%s" kommt mehrmals vor.',
                selectionDescText: 'Wählen Sie die Adresse aus, die Sie verwenden möchten:'
            };
            this._defaults = {
                ajaxURL: 'userdata.php',
                buttonClass: 'rf-button secondary',
                buttonContainer: '<div>',
                buttonContainerClass: 'grid_2',
                targets: {}
            }
            $.extend(this._defaults, this.regional['']);
        }

        $.extend(Userdata.prototype, {
            /**
             * Override the default settings for all instances of the userdata plugin.
             * 
             * @param object settings The new settings to use as defaults (anonymous object).
             * @return the manager object.
             */
            setDefaults: function( settings ){
                $.extend(this._defaults, settings);
                return this;
            },

            /**
             * 
             * 
             * @param object input DOM input element.
             * @param object settings Settings for attaching new userdata functionality.
             */
            _attachDialog: function( input, settings ){

                var settings = $.extend(this._defaults, settings);

                if ( !document.getElementById('rf-userdata-dialog') ){
                    var inst = $jParent('<div id="rf-userdata-dialog"></div>').appendTo('body');
                    inst.dialog({ autoOpen: false, close: function(){ $jParent('body').css('overflow', 'auto'); input.focus(); }, modal: true, resizable: false }).after('<span class="ui-dialog-footer" /><span class="ui-dialog-footer-edge" />');
                }
                else {
                    var inst = $('#rf-userdata-dialog');
                }

                input.settings = settings;

                $(input).data('settings', settings);

                this._attachButton(input, inst);
            },

            /**
             * 
             *
             * @param object input DOM input element.
             * @param object inst jQuery dialog instance.
             */
            _attachButton: function( input, inst ){

                var manager = this,
                    $input = $(input);

                // Create search button.
                var $button = $('<button>').attr('type', 'button').html(input.settings.searchText).addClass(input.settings.buttonClass);

alert(dump($(input).data('settings'))); // WORKS FINE, everything is unique.

                /**
                 * Bind manager._searchUserdata() function on button click.
                 */
                $button.bind('click', { settings : $(input).data('settings') }, function(e){

                    alert(dump(e.data.settings)); // DOES NOT WORK, always settings from last plugin call...


                    //manager._searchUserdata(input, inst);
                });

                /**
                 * Insert container with search button after input field.
                 */ 
                $input.closest('[class*="grid_"]').after(function(){
                    return $(input.settings.buttonContainer).addClass(input.settings.buttonContainerClass).append($button);
                });

                /**
                 * Change default enterkey behaviour on triggering the userdata button.
                 */
                $input.bind('focusin', function(){
                    $input.bind('keydown.enterOpen', function(e){
                        if ( e.keyCode === 13 ){
                            $button.trigger('click');
                            return false;
                        }
                    });
                });

                /**
                 * Unbind keydown event with enterOpen namespace.
                 */
                $input.bind('focusout', function(){
                    $input.unbind('keydown.enterOpen');
                });
            },

            /**
             * 
             *
             * @param object input DOM input element.
             * @param object inst jQuery dialog instance.
             */
            _searchUserdata: function( input, inst ){

                var manager = this,
                    $input = $(input),
                    value = $input.val();

                /**
                 * Perform an Ajax request to get the userdata of specified user.
                 */
                $.ajax({
                    url: input.settings.ajaxURL,

                    dataType: 'json',

                    data: 'value=' + encodeURIComponent(value),

                    /**
                     * A pre-request callback function.
                     * Returning false in the beforeSend function will cancel the request.
                     */
                    beforeSend: function(){
                        // If value is smaller than two characters is equal space character
                        // call showError and cancel ajax call.
                        if ( value.length <= 2 || value === ' ' || value === '' ){
                            manager._showError(input.settings.errorFilterText, inst, input);
                            return false;
                        }
                    },

                    /**
                     * A function to be called if the request succeeds.
                     * 
                     * @see manager._showError() for error display.
                     * @see manager._checkName() for selecting dialog.
                     *
                     * @param object data LDAP userdata returned from server.
                     */
                    success: function( data ){
                        if ( $.isEmptyObject(data) ){
                            manager._showError(input.settings.errorVoidText, inst, input);
                        }
                        else if ( data.error === 4 ){
                            manager._showError(input.settings.errorFilterText, inst, input);
                        }
                        else {
                            // If request returned more than one user, call checkName() function.
                            if ( data.length > 1 ){
                                manager._checkName(input, inst, data);
                            }
                            else {
                                manager._setUserdata(inst, data[0], input);
                            }
                        }
                    },

                    /**
                     * A function to be called if the request fails.
                     *
                     * @see manager._showError() for more information.
                     *
                     * @param object jqXHR XMLHttpRequest object.
                     * @param string textStatus Description of occurred error.
                     * @param object errorThrown Exception object.
                     */
                    error: function( jqXHR, textStatus, errorThrown ){
                        manager._showError(input.settings.errorScriptText, inst, input);
                    }
                });
            },

            /**
             * 
             *
             * @param string error Error to display.
             * @param object inst jQuery dialog instance.
             * @param object input DOM input element.
             */
            _showError: function( error, inst, input ){
                inst.html('<div class="ui-dialog-container">' + error + '</div>')
                inst.dialog({ title: input.settings.errorTitle, width: 400 });
                inst.dialog('open');
            },

            /**
             * 
             *
             * @param object input DOM input element.
             * @param object inst jQuery dialog instance.
             * @param array data LDAP userdata.
             */
            _checkName: function( input, inst, data ){
                var manager = this,
                    $container = $('<div>').addClass('ui-dialog-container').html('<p>' + sprintf(input.settings.selectionInfoText, $(input).val()) + '</p><p>' + input.settings.selectionDescText + '</p>'),
                    $tableWrapperOuter = $('<div>').addClass('rf-select-list-wrapper-outer'),
                    $tableWrapperInner = $('<div>').addClass('rf-select-list-wrapper-inner').css('height', 240),
                    $table = $('<table>').addClass('rf-select-list'),
                    $thead = $('<thead>').html('<tr><th>Name</th><th>Position</th><th>Telefon</th><th>Ort</th><th>E-Mail</th><th>Alias</th></tr>'),
                    $tbody = $('<tbody>');

                // Loop trough userdata and create a table row for each entry.
                for ( var i = 0, length = data.length; i < length; i++ ){

                    var $row = $('<tr>').html(function(){
                        this.onselectstart = function(){ return false; }
                        //return '<td class="user-icon">' + data[i].sn + ' ' + data[i].givenname + '</td><td>' + data[i].title + '</td><td>' + data[i].telephonenumber + '</td><td>' + data[i].location + '</td><td>' + data[i].mail + '</td><td>' + data[i].cn + '</td>';
                        return '<td class="user-icon">' + data[i].sn + ' ' + data[i].givenname + '</td><td>' + data[i].title + '</td><td>' + data[i].location + '</td><td>' + data[i].cn + '</td>';
                    });

                    $row.bind('click', { obj: data[i] }, function(e){
                        var $this = $(this);

                        // Temp-save data from selection for ok-button.
                        inst.selection = e.data.obj;

                        $this.siblings().removeClass('ui-state-active');
                        $this.addClass('ui-state-active');
                    });

                    $row.bind('dblclick', { obj: data[i] }, function(e){
                        inst.dialog('close');
                        manager._setUserdata(inst, e.data.obj, input);
                    });

                    $row.appendTo($tbody);
                }

                // Trigger first row selection.
                $tbody.find('tr').first().trigger('click');

                // Hide scrollbar on form body to prevent scrolling problem.
                $jParent('body').css('overflow', 'hidden');

                // Create buttons and append them to a container.
                var $buttonAccept = $('<button>').addClass("rf-button primary").html(input.settings.acceptText).bind('click', function(){
                    inst.dialog('close');
                    manager._setUserdata(inst, inst.selection, input);
                });

                var $buttonAbort = $('<button>').addClass("rf-button secondary").html(input.settings.abortText).bind('click', function(){
                    inst.dialog('close');
                });

                // Toggle 'rf-button-hover' class on buttons hover state.
                $buttonAccept.hover(function(){ $buttonAccept.toggleClass('rf-button-hover'); });
                $buttonAbort.hover(function(){ $buttonAbort.toggleClass('rf-button-hover'); });

                var $buttonContainer = $('<div>').addClass('float-right').append($buttonAccept, $buttonAbort);

                // Append dialog html to container.
                $container.append($tableWrapperOuter.append($tableWrapperInner.append($table.append(/*$thead,*/ $tbody))), $buttonContainer);

                inst.html($container);
                inst.dialog({ title: input.settings.selectionTitle, width: 800 });
                inst.dialog('open');
            },

            /**
             * 
             *
             * @param object inst jQuery dialog instance.
             * @param array data LDAP userdata.
             */
            _setUserdata: function( inst, data, input ){

                for ( var target in input.settings.targets ){

                    var values = [];

                    if ( typeof(input.settings.targets[target]) === 'object' ){
                        for ( var i = 0, length = input.settings.targets[target].length; i < length; i++ ){
                            values.push(data[input.settings.targets[target][i]]);
                        }
                    }
                    else {
                        values.push(data[input.settings.targets[target]]);
                    }

                    $(target).val(values.join(' '));
                }
            }
        });

        /**
         * Invoke the userdata functionality.
         *
         * @param object options Settings for attaching new userdata functionality.
         * @return jQuery object.
         */
        $.fn.userdata = function( options ){

            // Verify an empty collection wasn't passed.
            if ( !this.length ){
                return this;
            }

            /**
             * Loop through each plugin object.
             */
            return this.each(function(){
                $.userdata._attachDialog(this, options);
            });
        };

        $.userdata = new Userdata();
        $.userdata.uuid = new Date().getTime();

    })( jQuery, window, document );

我多次在html中调用它:

$('#inputid_1').userdata({ targets: {'#targetid_1': 'cn'} });
$('#inputid_2').userdata({ targets: {'#targetid_2': 'phone'} });

现在,如果您查看_attachButton方法,则会有两个警报。一个在click绑定之外,一个在click绑定之内。在click bind之外,设置是唯一的foreach插件调用。在click bind中,它始终会警告上次调用的设置,即使我使用event.data传递它们。

1 个答案:

答案 0 :(得分:3)

扩展如下设置:

var settings = $.extend(settings, this._defaults); // invert the params

var settings = $.extend({}, this._defaults, settings);

为什么?

$ .extend()将第一个参数作为目标。所以你将this._default的属性与设置合并而不是相反。

第二种形式({})说:忽略目标,让this._default和设置都不变,只返回一个合并对象(希望我很清楚^^)。

请参阅有关.extend()的jQuery文档。