Am trying to create a simple jquery plugin for my web page the problem am facing here here is handling the click even for dynamic content.
I have tried using document on click selector but it doesn't work and but using select on click works fine when page load but on dynamic content it doesn't. When i use $(document).on("click", clickedElement, function(event) for the click event consoling $(this).data("object-id") will show undefined.
<span class="openModalTemplate" data-object-id="item100">Open 1</span>
<span class="openModalTemplate" data-object-id="item101">Open 2</span>
<span class="openModalTemplate" data-object-id="item103">Open 3</span>
<script>
$(function(){
$(".openModalTemplate").Template({
element: "#newOpen"
type: "product"
});
});
</script>
My function
(function($){
$.fn.Template = function(options) {
var clickedElement = $(this);
if(typeof options === "object") {
options = $.extend(true, options, {
/*Locals*/
element: '#createObjectElement',
type: "product",
action: null,
apiURL: null,
object: null,
categoryType: "ITEM"
});
}
$(document).on("click", clickedElement, function(event){
//clickedElement.on("click", function(event){
var currentElemnt = $(this);
var action_id = $(this).data("object-id");
//if(action_id === undefined){action_id = options.action;}
if(options.type =="close"){
}
console.log("action_id", action_id);
console.log("element", options.element);
if (options.onAfterOpen !== undefined) {
options.onAfterOpen(event);
}
if (options.onAfterClose !== undefined) {
options.onAfterClose(event);
}
if (options.onError !== undefined) {
options.onError(event);
}
event.preventDefault();
});
};
})(jQuery);
unfortunately from searching there is no way to do this from inside the plugin .. the plugin set for the present elements not the new one .. so you need to run the plugin again for the new created elements
And when you refresh the plugin the events fires multiple times and to avoid that You can add class to the elements then remove the class inside the plugin ..
see changes below
(function($){
$.fn.Template = function(settings) { //<<< here
var clickedElement = $(this);
clickedElement.removeClass('ToPlugin'); //<<<< remove ToPlugin class
if(typeof settings === "object") { //<<<<<< here
var options = $.extend({
/*Locals*/
element: '#createObjectElement',
type: "product",
action: null,
apiURL: null,
object: null,
categoryType: "ITEM"
} , settings); //<<<<< here
}
clickedElement.on("click", function(event){
var currentElemnt = $(this);
var action_id = $(this).data("object-id");
//if(action_id === undefined){action_id = options.action;}
if(options.type =="close"){
}
console.log("action_id", action_id);
console.log("element", options.element);
if (options.onAfterOpen !== undefined) {
options.onAfterOpen(event);
}
if (options.onAfterClose !== undefined) {
options.onAfterClose(event);
}
if (options.onError !== undefined) {
options.onError(event);
}
event.preventDefault();
});
};
})(jQuery);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button>Add Span</button>
<span class="openModalTemplate ToPlugin" data-object-id="item100">Open 1</span>
<span class="openModalTemplate ToPlugin" data-object-id="item101">Open 2</span>
<span class="openModalTemplate ToPlugin" data-object-id="item103">Open 3</span>
<script>
$(function(){
refresh_Template(); // use the function onload
var i = 4;
$('button').on('click' , function(){
$('body').append('<span class="openModalTemplate ToPlugin" data-object-id="item10'+i+'">Open '+i+'</span>');
i++;
refresh_Template(); // use the function on click
});
});
// create a function to refresh the plugin instead of repeat it every time
function refresh_Template(){
$(".openModalTemplate.ToPlugin").Template({
element: "#newOpen",
type: "product"
});
}
</script>
Note: don't forget to add the class ToPlugin to any element you need to use the plugin with (both static and dynamic elements)
Related
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.
I am using "VMenu" as a jQuery plugin to show a huge accordion on a HTML site, because it supports a very simple structure with only <u> and <li> tags.
Now, I want to close all the open accordion tabs with an event/button/...
The plugin creator didn't answer questions so I need your help.
I put the whole code in jsfiddle but it didn't work: https://jsfiddle.net/ekbLLcLd/3/
(function($) {
$.fn.vmenuModule = function(option) {
var obj,
item;
var options = $.extend({
Speed: 220,
autostart: true,
autohide: 1
},
option);
obj = $(this);
item = obj.find("ul").parent("li").children("a");
item.attr("data-option", "off");
item.unbind('click').on("click", function() {
var a = $(this);
if (options.autohide) {
a.parent().parent().find("a[data-option='on']").parent("li").children("ul").slideUp(options.Speed / 1.2,
function() {
$(this).parent("li").children("a").attr("data-option", "off");
})
}
if (a.attr("data-option") == "off") {
a.parent("li").children("ul").slideDown(options.Speed,
function() {
a.attr("data-option", "on");
});
}
if (a.attr("data-option") == "on") {
a.attr("data-option", "off");
a.parent("li").children("ul").slideUp(options.Speed)
}
});
if (options.autostart) {
obj.find("a").each(function() {
$(this).parent("li").parent("ul").slideDown(options.Speed,
function() {
$(this).parent("li").children("a").attr("data-option", "on");
})
})
}
}
})(window.jQuery || window.Zepto);
I think it's a simple task but I'm not sure how to do it.
Add this function and trigger it on any button click :
function closeAll()
{
// obj will be your div(wrapper) within your all accordion is exist;
var item2 = $(".u-vmenu").find("ul").parent("li").children("a");
item2.attr("data-option", "off");
item2.each(function(){
$(this).attr("data-option", "off");
$(this).parent("li").children("ul").slideUp(200);
});
}
This function will close all the opened accordion.
I am trying to change this demo:
http://maxwells.github.io/bootstrap-tags.html
into a responsive version in which I can set it to readOnly and remove it from readOnly as I like. This code:
var alltags = ["new tag", "testtag", "tets", "wawa", "wtf", "wtf2"];
$(document).ready(function() {
var tagbox = $('#my-tag-list').tags({
suggestions: alltags
});
var tagenable = true;
$('#my-tag-list').focusout(function() {
if (tagenable) {
tagbox.readOnly = true;
$('#my-tag-list').empty();
tagbox.init();
tagenable = false;
}
});
$('#my-tag-list').click(function() {
if(!tagenable) {
tagbox.readOnly = false;
$('#my-tag-list').empty();
tagbox.init();
tagenable = true;
}
});
});
seems to work fairly well, it makes everything readonly after focusout and editable when I click it. However, the editing does not work since I cannot insert new tags nor delete them (seems to be like event handling was lost or something like that).
I am guessing that emptying the #my-tag-list div is causing this, but I cannot yet find a way to use for instance "detach" instead that removes everything inside (not the element itself) and putting it back in again.
I tried to make a JS Fiddle, but it isn't really working so well yet:
http://jsfiddle.net/tomzooi/cLxz0L06/
The thing that does work is a save of the entire website, which is here:
https://www.dropbox.com/sh/ldbfqjol3pppu2k/AABhuJA4A6j9XTxUKBEzoH6za?dl=0
this link has the unminimized JS of the bootstrap-tags stuff I am using:
https://github.com/maxwells/bootstrap-tags/blob/master/dist/js/bootstrap-tags.js
So far I managed to do this with some modifications of the bootstrap javascript code. I use two different tagbox which I hide and unhide with some click events.
var tagbox = $('#my-tag-list').tags({
suggestions: alltags,
tagData: tmp_tags,
afterAddingTag: function(tag) { tagboxro.addTag(tag); },
afterDeletingTag: function(tag) {tagboxro.removeTag(tag); }
});
var tagboxro = $('#my-tag-listro').tags({
suggestions: alltags,
tagData: tmp_tags,
readOnly: 'true',
tagSize: 'sm',
tagClass: 'btn-info pull-right'
});
$(document).mouseup(function (e) {
var container = $("#my-tag-list");
if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) { // ... nor a descendant of the container
if (tagsave) {
$("#my-tag-listro").show();
$("#my-tag-list").hide();
var tags = tagbox.getTags();
$.post("%basedir%/save.php", {
editorID:"new_tags",
tags:tags
}, function(data,status){
//alert("Data: " + data + "\nStatus: " + status);
});
tagsave = false;
}
}
});
$('#my-tag-listro').click(function() {
tagsave = true;
//$(".tag-list").toggle();
$("#my-tag-list").show();
$("#my-tag-listro").hide();
});
I had to modify the code of bootstrap-tags.js to allow for this since it normally deletes all of the usefull functions when it is considered readonly in the init function:
if (this.readOnly) {
this.renderReadOnly();
this.removeTag = function(tag) {
if (_this.tagsArray.indexOf(tag) > -1) {
_this.tagsArray.splice(_this.tagsArray.indexOf(tag), 1);
_this.renderReadOnly();
}
return _this;
};
this.removeTagClicked = function() {};
this.removeLastTag = function() {};
this.addTag = function(tag) {
_this.tagsArray.push(tag);
_this.renderReadOnly();
return _this;
};
this.addTagWithContent = function() {};
this.renameTag = function() {};
return this.setPopover = function() {};
}
would be awesome if this feature was incorporated in a somewhat less hacky way though :)
I am having strange issues with jQuery and adding and removing classes. I'm trying to see on success of a json request, that for the particular hyper link, it should call addClass and removeClass to add/remove particular css properties. When I click on it, it NEVER works, but when I try the css classes independently, they work fine. Is there something I'm missing here? Thanks for the input.
$(document).ready(function() {
$('.add_link').bind("click", function(e) {
$.getJSON("/add/", function(json) {
if (json.SUCCESS != null) {
$(this).removeClass('blue_button_link').addClass('gray_out_button_link');
}
});
});
});
$(document).ready(function() {
$('.add_link').bind("click", function(e) {
// cache it in a local variable.
var $this = $(this);
$.getJSON("/add/", function(json) {
if (json.SUCCESS != null) {
$this.removeClass('blue_button_link').addClass('gray_out_button_link');
}
});
});
});
In event handler you have another context, so you cannot use this how you want. Try:
$(document).ready(function() {
var link = $('.add_link');
link.bind("click", function(e) {
$.getJSON("/add/", function (json) {
if (json.SUCCESS != null) {
link.removeClass('blue_button_link').addClass('gray_out_button_link');
}
});
});
});
Or:
$(document).ready(function() {
$('.add_link').bind("click", function(e) {
var link = $(this);
$.getJSON("/add/", function (json) {
if (json.SUCCESS != null) {
link.removeClass('blue_button_link').addClass('gray_out_button_link');
}
});
});
});
I'm using the following placeholder plugin
(function($){
var ph = "PLACEHOLDER-INPUT";
var phl = "PLACEHOLDER-LABEL";
var boundEvents = false;
var default_options = {
labelClass: 'placeholder'
};
//check for native support for placeholder attribute, if so stub methods and return
var input = document.createElement("input");
if ('placeholder' in input) {
$.fn.placeholder = $.fn.unplaceholder = function(){}; //empty function
delete input; //cleanup IE memory
return;
};
delete input;
//bind to resize to fix placeholders when the page resizes (fields are hidden/displayed, which can change positioning).
$(window).resize(checkResize);
$.fn.placeholder = function(options) {
bindEvents();
var opts = $.extend(default_options, options)
this.each(function(){
var rnd=Math.random().toString(32).replace(/\./,'')
,input=$(this)
,label=$('<label style="position:absolute;display:none;top:0;left:0;"></label>');
if (!input.attr('placeholder') || input.data(ph) === ph) return; //already watermarked
//make sure the input tag has an ID assigned, if not, assign one.
if (!input.attr('id')) input.attr('id', 'input_' + rnd);
label .attr('id',input.attr('id') + "_placeholder")
.data(ph, '#' + input.attr('id')) //reference to the input tag
.attr('for',input.attr('id'))
.addClass(opts.labelClass)
.addClass(opts.labelClass + '-for-' + this.tagName.toLowerCase()) //ex: watermark-for-textarea
.addClass(phl)
.text(input.attr('placeholder'));
input
.data(phl, '#' + label.attr('id')) //set a reference to the label
.data(ph,ph) //set that the field is watermarked
.addClass(ph) //add the watermark class
.after(label) //add the label field to the page
//setup overlay
itemFocus.call(this);
itemBlur.call(this);
});
};
$.fn.unplaceholder = function(){
this.each(function(){
var input=$(this),
label=$(input.data(phl));
if (input.data(ph) !== ph) return;
label.remove();
input.removeData(ph).removeData(phl).removeClass(ph).unbind('change',itemChange);
});
};
function bindEvents() {
if (boundEvents) return;
//prepare live bindings if not already done.
$("form").live('reset', function(){
$(this).find('.' + ph).each(itemBlur);
});
$('.' + ph)
.live('keydown',itemFocus)
.live('mousedown',itemFocus)
.live('mouseup',itemFocus)
.live('mouseclick',itemFocus)
.live('focus',itemFocus)
.live('focusin',itemFocus)
.live('blur',itemBlur)
.live('focusout',itemBlur)
.live('change',itemChange);
;
$('.' + phl)
.live('click', function() { $($(this).data(ph)).focus(); })
.live('mouseup', function() { $($(this).data(ph)).focus(); });
bound = true;
boundEvents = true;
};
function itemChange() {
var input = $(this);
if (!!input.val()) {
$(input.data(phl)).hide();
return;
}
if (input.data(ph+'FOCUSED') != 1) {
showPHL(input);
}
}
function itemFocus() {
$($(this).data(ph+'FOCUSED',1).data(phl)).hide();
};
function itemBlur() {
var that = this;
showPHL($(this).removeData(ph+'FOCUSED'));
//use timeout to let other validators/formatters directly bound to blur/focusout work
setTimeout(function(){
var input = $(that);
//if the item wasn't refocused, test the item
if (input.data(ph+'FOCUSED') != 1) {
showPHL(input);
}
}, 200);
};
function showPHL(input, forced) {
var label = $(input.data(phl));
//if not already shown, and needs to be, show it.
if ((forced || label.css('display') == 'none') && !input.val())
label
.text(input.attr('placeholder'))
.css('top', input.position().top + 'px')
.css('left', input.position().left + 'px')
.css('display', 'block');
//console.dir({ 'input': { 'id':input.attr('id'), 'pos': input.position() }});
}
var cr;
function checkResize() {
if (cr) window.clearTimeout(cr);
cr = window.setTimeout(checkResize2, 50);
}
function checkResize2() {
$('.' + ph).each(function(){
var input = $(this);
var focused = $(this).data(ph+'FOCUSED');
if (!focused) showPHL(input, true);
});
}
}(jQuery));
It applies the placeholder attribute to form fields in browsers that do not natively support the placeholder attribute (ex. IE9). It works for statically loaded text fields, however for text fields that are loaded via ajax, the placeholder does not appear.
Is it possible to achieve this 'watermark' effect on text fields that are loaded via ajax?
What happens if you trigger the window resize function after adding in new inputs?
$(window).trigger('resize')
You could apply the plugin to newly created controls after the AJAX call completes. Forgive the pseudo-code as I'm not really sure about how your AJAX calls are working:
$.ajax({
url: "test.html",
cache: false
}).done(function( result ) {
field = $('<input>').html(result);
$("#results").append(field);
field.placeholder();
});
Another option is that you could use jQuery's .on() method to bind dynamically created controls to the function--but it wants an event (like click). I'm not sure how you would do that. Maybe something like this:
$( 'body' ).on('click','input.addField', function(e){
$(this).placeholder();
});
I know this won't work, but maybe it helps get you brainstorm solutions.