Access originally clicked element in jQuery plugin - javascript

I have the following plugin, and while I wish it to be able to be applied to multiple elements, I do not wish to create a new dialog for each element.
But in the dialog.open callback or when the button is clicked, I wish to be able to access the element which was clicked and opened the dialog.
If I wanted to create multiple dialogs, I suppose I could put this.each(function () {...} in the init method and then this would be the individually clicked element, but as stated earlier, I only one one dialog.
EDIT. I revised the code so that it does what I need it to do. It just seems like a bit of a hack using data as I did. Is there a more proper way to do so?
How is this accomplished?
(function($){
var defaults = {};
var methods = {
init : function (options) {
var settings = $.extend({}, defaults, options);
var dialog = $('<div/>').dialog({
open: function( event, ui ) {
console.log(dialog.data('elementThatWasClicked'));
},
buttons: [
{
text: 'click',
click: function() {console.log(dialog.data('elementThatWasClicked'));}
}
]
});
return this.each(function () {
var $this=$(this);
$this.click(function(){dialog.data('elementThatWasClicked',$this).dialog('open')});
});
}
};
$.fn.test = function(method) {
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || ! method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.test');
}
};
}(jQuery));
$(function(){
$('.bla').test();
});

Related

The meaning of this.$pop

The site Read-city uses the function function Popup (pop, name, html, handlers) in the file Read-city - online store of books_files\popup.js.Untitled, which creates a login/registration window (see https://ru.stackoverflow.com/questions/1194356/%d0%9e%d0%b1%d1%8a%d0%b5%d0%ba%d1%82-%d0%ba%d0%bb%d0%b0%d1%81%d1%81-popup )
function Popup (pop, name, html, handlers) {
if (html) {
$(document.body).append(html);
}
handlers = handlers || {};
this.$pop = $(pop);
this.selector = pop;
this.name = name;
this.$pop_wrapper = this.$pop.parent('.js__popup_main_wrapper');
Popup.instances[this.name] = this;
this.$pop.on('click', '.popup__close, .js__popup__close', this.hide.bind(this));
//Закрытие попапа при клике на маску и при нажатии Esc
if (this.$pop_wrapper) {
this.$pop_wrapper.on('click', function(event) {
var mask_wrapper = event.target;
if (mask_wrapper.classList.contains('js__popup_main_wrapper')) {
Popup.hideAll();
}
});
}
$(document).keyup(function(event) {
if (event.keyCode === 27) {
Popup.hideAll();
}
});
this.$body = this.$pop.find('.popup__body_text');
this.onshow = handlers.show || null;
this.onhide= handlers.hide || null;
this.events = {
closePopup: 'closePopup',
openPopup: 'openPopup'
}
}
Popup.instances = {};
Popup.getInstance = function(name, pop, html, handlers) {
if(Popup.instances[name]){
return Popup.instances[name];
}
if (pop){
return new Popup(pop, name, html, handlers);
}
return null;
};
Popup.hideAll = function() {
for (var popupName in Popup.instances) {
if(Popup.instances.hasOwnProperty(popupName)){
Popup.instances[popupName].hide();
}
}
};
Popup.prototype.show = function() {
Popup.hideAll();
//Скрываем скролл
$('body').css('overflow', 'hidden');
// временный костыль
// почему-то не всегда инициализируется dom-элемент попапа
if (!this.$pop.length) this.$pop = $(this.selector);
if (!this.$pop.length) return;
if (this.$pop_wrapper) {
this.$pop_wrapper.css("display", "flex");
}
this.$pop
.removeClass('hidden')
.addClass('shown')
.attr('data-opened', '');
this.onshow ? this.onshow() : null;
if (window.userCity && window.userCity.hideBlock) { //если открыт попап города(актуально для мобильной версии)
//то закрыть блок выбора города
window.userCity.hideBlock();
}
//создадим событие открытия попапа
eventEmitter.dispatch(this.events.openPopup, {
popupName: this.name,
popup: this.$pop
});
};
Popup.prototype.hide = function() {
this.$pop
.removeClass('shown')
.addClass('hidden')
.removeAttr('data-opened');
this.onhide ? this.onhide() : null;
if (this.$pop_wrapper) {
this.$pop_wrapper.fadeOut(50);
}
var opened = $('[data-opened]').length;
if (opened === 0) {
//Возвращаем скролл
$('body').css('overflow', 'auto');
}
eventEmitter.dispatch(this.events.closePopup, {
popupName: this.name,
popup: this.$pop
});
};
Popup.prototype.setBodyText = function (text){
if(!text){
return;
}
this.$body.html(text);
};
Explain
the meaning of the pop property
action of the operator this.$pop = $(pop)
and also the syntax of this.$pop.on ('click', '.popup__close, .js__popup__close', this.hide.bind (this)); is not clear.
1) the meaning of the pop property
It is whatever someone named a property to be. Sounds like it is the short name for pop up. But a variable name can be anything....
2) action of the operator this.$pop = $(pop)
It is taking a jQuery object return and puts it into a property. It is not uncommon for people to use $ in a variable name to denote it is a jQuery object and not a DOM reference.
3) and also the syntax of this.$pop.on ('click', '.popup__close, .js__popup__close', this.hide.bind (this)); is not clear.
It is the basic syntax of jQuery for attaching event listeners https://api.jquery.com/on
Very quickly, here is my take on this just looking at the code you provided.
I would say pop would be a html string selector / HTML element/ jQuery element.
That action should be creating an instance of a jQuery element. This element will help out interacting with pop HTML element under the jQuery "framework". A quick jQuery tutorial: https://www.w3schools.com/jquery/
It is part of the jQuery framework. Instead of addEventListener, it uses an on method to bind events. https://api.jquery.com/on/
Looking at the rest of the code, I'm pretty sure it is using jQuery.

Jquery Dailog not returning the user given value for Confirmation PopUp.

Hi I'm using JQUERY Dialog for a confirmation popup. I have a common javascript file, in which i had a function which used to call window.ShowModalDialog. Now from the same function i am calling the jquery dialog, but as it is an asynchronous call, the calling function returns the value(yes/no) without even accepting Values from dialog. How can i return the proper value(yes/no)
If I have correctly understood the problem ...
and if something is wrong, add the example of your code
Try using this pattern:
(function ($, undefined) {
$.fn.dialog = function (options) {
options = $.extend({}, $.fn.dialog.options, options);
return this.each(function () {
var dialog = $(this);
dialog.children(".ok").click(function (e) {
options.ok.call(this, e);
dialog.close();
});
dialog.children(".close").click(function (e) {
options.close.call(this, e);
dialog.close();
});
});
};
$.fn.open = function () {
this.get(0).showModal();
};
$.fn.close = function () {
this.get(0).close();
};
$.fn.dialog.options = {
ok : function () {},
close : function () {}
};
})(jQuery);
and using callback
var dialog = $(".myDialog").dialog({
ok : function () {
alert("ok!!");
}
});
Do everything you need in callback, but avoid callbackhell.
see example

How to achieve a queue of object instances of jQuery modals, assuring only one instance is on per time?

I've a task of building a modal prompt, that's been simple so far describing its methods like "show", "hide" when it comes down just to DOM manupulation.
Now comes the hardship for me... Imagine we have a page on which there are several immediate calls to construct and show several modals on one page
//on page load:
$("browser-deprecated-modal").modal();
$("change-your-city-modal").modal();
$("promotion-modal").modal();
By default my Modal (and other libraries i tried) construct all of these modals at once and show them overlapping each other in reverse order -
i.e $(promotion-modal) is on the top, while the
$("browser-deprecated-modal") will be below all of them. that's not what i want, let alone overlapping overlays.
I need each modal to show up only when the previous one (if there'are any) has been closed. So, first we should see "browser-deprecated-modal" (no other modals underneath), upon closing it there must pop up the second one and so on.
I've been trying to work it out with this:
$.fn.modal = function(options) {
return this.each(function() {
if (Modal.running) {
Modal.toInstantiateLater.push({this,options});
} else {
var md = new Modal(this, options);
}
});
}
destroy :function () {
....
if (Modal.toInstantiateLater.length)
new Modal (Modal.toInstantiateLater[0][0],Modal.toInstantiateLater[0][1]);
}
keeping a track of all calls to construct a Modal in a array and in the "destroy" method make a check of this array is not empty.
but it seems awkward and buggy me thinks.
i need a robust and clear solution. I've been thinking about $.Callbacks or $.Deferred,
kinda set up a Callback queue
if (Modal.running) { //if one Modal is already running
var cb = $.Callbacks();
cb.add(function(){
new Modal(this, options);
});
} else { //the road is clear
var md = new Modal(this, options);
}
and to trigger firing cb in the destroy method, but i'm new to this stuff and stuck and cannot progress, whether it's right or not, or other approach is more suitable.
Besides, I read that callbacks fire all the functions at once (if we had more than one extra modal in a queue), which is not right, because I need to fire Modal creation one by one and clear the Callback queue one by one.
Please help me in this mess.
My code jsfiddle
I got rid of the counter variable, as you can use toInstantiateLater to keep track of where you are, and only had to make a few changes. Give this a try...
Javscript
function Modal(el, opts){
this.el = $(el);
this.opts = opts;
this.overlay = $("<div class='overlay' id='overlay"+Modal.counter+"'></div>");
this.wrap = $("<div class='wrap' id='wrap"+Modal.counter+"'></div>");
this.replace = $("<div class='replace' id='replace"+Modal.counter+"'></div>");
this.close = $("<span class='close' id='close"+Modal.counter+"'></span>")
if (Modal.running) {
Modal.toInstantiateLater.push(this);
}
else {
Modal.running = true;
this.show();
}
}
Modal.destroyAll = function() {
Modal.prototype.destroyAll();
};
Modal.prototype = {
show: function() {
var s = this;
s.wrap.append(s.close);
s.el.before(s.replace).appendTo(s.wrap).show();
$('body').append(s.overlay).append(s.wrap);
s.bindEvents();
Modal.currentModal = s;
},
bindEvents: function() {
var s = this;
s.close.on("click.modal",function(e){
s.destroy.call(s,e);
});
},
destroy: function(e) {
var s = this;
s.replace.replaceWith(s.el.hide());
s.wrap.remove();
s.overlay.remove();
if (Modal.toInstantiateLater.length > 0) {
Modal.toInstantiateLater.shift().show();
}
else {
Modal.running = false;
}
},
destroyAll: function(e) {
Modal.toInstantiateLater = [];
Modal.currentModal.destroy();
}
}
Modal.running = false;
Modal.toInstantiateLater = [];
Modal.currentModal = {};
$.fn.modal = function(options) {
return this.each(function() {
var md = new Modal(this, options);
});
}
$("document").ready(function(){
$("#browser-deprecated-modal").modal();
$("#change-your-city-modal").modal();
$("#promotion-modal").modal();
$("#destroy-all").on("click", function() {
Modal.destroyAll();
});
});
jsfiddle example
http://jsfiddle.net/zz9ccbLn/4/

JQuery plugin - callback breaks other features

I'm trying to build a basic color picker plugin (mainly as an exercise to learn about plugin development). I have a callback called "onSelected" that fires when you pick a color, but it breaks another feature of the plugin (the ability to toggle the visibility of the swatch list).
I am new to plugin development so I'm sure it's a simple mistake I'm making...
jsfiddle
Plugin:
(function ($) {
$.colorPicker2 = function (el, options) {
// the wrapper around the colors
var $pickerContainer = $("<div>");
// To avoid scope issues, use 'base' instead of 'this'
// to reference this class from internal events and functions.
var base = this;
// Access to jQuery and DOM versions of element
base.$el = $(el);
base.el = el;
// Add a reverse reference to the DOM object
base.$el.data("colorPicker2", base);
base.init = function () {
console.log("base.init");
base.options = $.extend({}, $.colorPicker2.defaultOptions, options);
// Put your initialization code here
// code goes here
$.each(base.options.colors, function (index, value) {
var $item = $('<div class="colorPicker-colorOption">').css({
"background-color": "#" + value
})
$item.click(function () {
console.log("item.click");
base.selectColor(value);
})
$pickerContainer.append($item);
});
//$pickerContainer.hide();
base.$el.append($pickerContainer);
if (base.options.toggleElement != null) {
base.options.toggleElement.click(function (e) {
base.togglePicker();
e.preventDefault();
});
}
};
base.togglePicker = function()
{
$pickerContainer.toggle();
}
base.selectColor = function (color) {
base.togglePicker();
if (typeof base.options.onSelected == 'function') {
base.options.onSelected.call(this, color);
}
}
// Sample Function, Uncomment to use
// base.functionName = function(paramaters){
//
// };
// Run initializer
base.init();
};
$.colorPicker2.defaultOptions = {
colors: [
'000000', '993300', '333300', '000080', '333399', '333333', '800000', 'FF6600',
'808000', '008000', '008080', '0000FF', '666699', '808080', 'FF0000', 'FF9900',
'99CC00', '339966', '33CCCC', '3366FF', '800080', '999999', 'FF00FF', 'FFCC00',
'FFFF00', '00FF00', '00FFFF', '00CCFF', '993366', 'C0C0C0', 'FF99CC', 'FFCC99',
'FFFF99', 'CCFFFF', '99CCFF', 'FFFFFF'
],
toggleElement: null,
onSelected: function (color) { }
};
$.fn.colorPicker2 = function (options) {
return this.each(function () {
(new $.colorPicker2(this, options));
});
};
})(jQuery);
How I hook into the onSelected event:
$(function () {
$('#primaryColorPicker').colorPicker2({
toggleElement: $('#selectPrimaryColor'),
onSelected: function (color) {
$('#selectedPrimaryColor').html("(#" + color + ")");
}
});
});
The HTML:
<a id="selectPrimaryColor">Toggle Color Picker</a>
<span id="selectedPrimaryColor" />
<div id="primaryColorPicker"></div>
You just have to learn how to write valid HTML
replace
<span id="selectedPrimaryColor" />
with
<span id="selectedPrimaryColor"></span>
FIDDLE

Making a method in a plugin accessible globally?

Given the jQuery dropdown plugin below. Is there a way to add a method that would allow for a separate function outside of the dropdown to 'hideMenu'? Thanks
For example, if I applied the plugin to a div with an ID like so:
$('#settings.dropdown').dropDownMenu();
How could I then call to close the dropDownMenu w hideMenu from outside of the plugin? Thanks
jQuery.fn.dropDownMenu = function() {
// Apply the Dropdown
return this.each(function() {
var dropdown = $(this),
menu = dropdown.next('div.dropdown-menu'),
parent = dropdown.parent();
// For keeping track of what's "open"
var activeClass = 'dropdown-active',
showingDropdown = false,
showingMenu,
showingParent,
opening;
// Dropdown Click to Open
dropdown.click(function(e) {
opening = true; // Track opening so that the body click doesn't close. This allows other js views to bind to the click
e.preventDefault();
if (showingDropdown) {
dropdown.removeClass(activeClass);
parent.removeClass(activeClass);
showingMenu.hide();
showingDropdown = false;
} else {
showingDropdown = true;
showingMenu = menu;
showingParent = parent;
menu.show();
dropdown.addClass(activeClass);
parent.addClass(activeClass);
}
});
// When you click anywhere on the page, we detect if we need to blur the Dropdown Menu
$('body').click(function(e) {
if (!opening && showingParent) {
var parentElement = showingParent[0];
if (!$.contains(parentElement, e.target) || !parentElement == e.target) {
hideMenu();
}
}
opening = false;
});
// hides the current menu
var hideMenu = function() {
if(showingDropdown) {
showingDropdown = false;
dropdown.removeClass(activeClass);
parent.removeClass(activeClass);
showingMenu.hide();
}
};
});
};
jQuery advises making multiple methods available through the plugin itself:
jQuery.fn.dropDownMenu = function(method) {
var methods = {
init: function() {
// Put all your init code here
},
hide: function() {
hideMenu();
}
};
if ( methods[method] ) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply( this, arguments );
} else {
$.error( 'Method ' + method + ' does not exist on jQuery.tooltip' );
}
function hideMenu() {
// ...
}
};
See http://docs.jquery.com/Plugins/Authoring#Plugin_Methods
Update: Use like this:
// Use the plugin normally to run the init method
$('#settings.dropdown').dropDownMenu();
// Call the hide method
$('#settings.dropdown').dropDownMenu('hide');
Sure. Give hideMenu to the global window object, like this:
window["hideMenu"] = function() {
if(showingDropdown) {
showingDropdown = false;
dropdown.removeClass(activeClass);
parent.removeClass(activeClass);
showingMenu.hide();
}
};
You can then call it as usual anywhere you need to.

Categories