多个实例上的 jQuery 插件设置
Posted
技术标签:
【中文标题】多个实例上的 jQuery 插件设置【英文标题】:jQuery Plugin settings on multiple instances 【发布时间】:2011-12-29 09:34:56 【问题描述】:我在一个 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 方法,则有两个警报。一个在点击绑定之外,一个在点击绑定内部。在点击绑定之外,设置是唯一的 foreach 插件调用。在点击绑定中,它总是提醒上次调用的设置,即使我使用 event.data 传递它们。
【问题讨论】:
【参考方案1】:像这样扩展设置:
var settings = $.extend(settings, this._defaults); // invert the params
或
var settings = $.extend(, this._defaults, settings);
为什么?
$.extend() 将目标作为第一个参数。因此,您将 this._default 的属性与设置合并,而不是相反。
第二种形式()说:忽略目标,让 this._default 和设置都保持不变,只需返回一个合并的对象(希望我很清楚 ^^)。
请参阅有关 .extend() 的 jQuery 文档。
【讨论】:
不起作用,我有问题的设置在此代码部分中传递:return this.each(function() $.userdata._attachDialog(this, options); );
var settings = $.extend(, this._defaults, settings);
工作!!非常感谢。你能解释一下这个问题吗?
编辑了答案。很高兴它有帮助:-)以上是关于多个实例上的 jQuery 插件设置的主要内容,如果未能解决你的问题,请参考以下文章