Create click event in jquery plugin - javascript

I want to make simple plugin to show alert if class is binding by a jquery plugin.
below is my html code
<html>
<head>
<script src="js/modal-load.js"></script>
<script>
$(document).ready(function(){
$('.modal-link').modalLoad();
})
</script>
</head>
....
<body>
<div class="hblock-1 text-4 text__uppercase color-7">
<a class="login btn btn-primary modal-link" href="/login-modal.php" data-toggle="modal" data-target="#login-modal">Log in</a>
Register
</div>
</body>
This is my plugin script
(function($){
$.modalLoad = function(element, options){
var defaults = {
foo: 'bar',
onFoo: function() {}
}
var plugin = this;
plugin.settings = {};
var $element = $(element),
element = element;
plugin.init = function(){
plugin.settings = $.extend({},defaults, options);
plugin.add_bindings();
}
plugin.add_bindings = function(){
this.click(function(){
alert('a');
})
}
plugin.create_modal = function(){
$('body').append('<div class="modal-wrapper"></div>');
}
plugin.init();
}
$.fn.modalLoad = function(options){
return this.each(function(){
if(undefined == $(this).data('modalLoad')){
var plugin = new $.modalLoad(this, options);
$(this).data('modalLoad', plugin);
}
});
}
})(jQuery);
In html code, i've initialized modalLoad plugin. But when particular class that i've bind, it won't be triggered by click event.
What's wrong with my code? is any mistake with my DOM selector in add_bindings part?
Thanks for advance
*edited

You need to attach the click handler to $element not this. Inside add_bindings, this refers to the plugin object not the clicked element so this will not have a method named on(You should get an error like Uncaught TypeError: undefined is not a function in your console)
plugin.add_bindings = function () {
$element.click(function (e) {
alert('a');
e.preventDefault()
})
}
Demo: Fiddle

Related

JavaScript: using THIS inside object function and binding event

I have an Object and I want to bind a function to a button when Object was initialized.
var MyClass = {
Click: function() {
var a = MyClass; // <---------------------- look here
a.Start();
},
Bind: function() {
var a = document.getElementById('MyButton');
a.addEventListener('click', this.Click, false); //<---------- and here
},
Init: function() {
this.Bind();
}
}
So, I'm new at using it and I don't know if object can be declared like this (inside Click() function that should be done after clicking a button):
Is it a bad practise? Which could be the best way in this case when adding an event here?
Edit: fiddle
Firstly you have a syntax error. getElementsById() should be getElementById() - no s. Once you fix that, what you have will work, however note that it's not really a class but an object.
If you did want to create this as a class to maintain scope of the contained methods and variables, and also create new instances, you can do it like this:
var MyClass = function() {
var _this = this;
_this.click = function() {
_this.start();
};
_this.start = function() {
console.log('Start...');
}
_this.bind = function() {
var a = document.getElementById('MyButton');
a.addEventListener('click', this.click, false);
};
_this.init = function() {
_this.bind();
};
return _this;
}
new MyClass().init();
<button id="MyButton">Click me</button>
For event listeners it's easiest and best to use jQuery, for example if you want to have some .js code executed when user clicks on a button, you could use:
https://api.jquery.com/click/
I don't know how new you are to .js, but you should look up to codecademy tutorials on JavaScript and jQuery.
.click() demo:
https://www.w3schools.com/jquery/tryit.asp?filename=tryjquery_event_click

How to initialize a plugin from another javascript file

I have the following fiddle. On click of button 'scroll', is it possible to call the scrollTest function inside the plugin? Right now I am calling the whole test() again and hence it is creating a new test object each time I click on scroll button.
My Code [ fiddle demo ]
(function ($, win, doc) {
'use strict';
$.fn.test = Plugin;
$.fn.test.Constructor = Test;
function Plugin() {
return this.each(function () {
new Test(this);
});
}
// TREE CLASS DEFINITION
// =====================
function Test(el) {
var publ = this,
priv = {};
console.log("start");
$('.test_button').click(function(){
console.log("clicked");
publ.scrollTest
})
publ.scrollTest = function () {
console.log("in scrolltest");
};
publ.bindEvents= function () {
console.log("in bind");
};
publ.fileter= function () {
console.log("in filter");
};
}
}(jQuery, this, this.document));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<h2>Hello</h2>
<button class="test_button">Click me</button>
<button class="test_button2" onclick="$('h2').test()">scroll</button>
</body>
<script>
$('h2').test();
</script>
You need to wrap the use of it inside a $(document).ready(); block to ensure the script has loaded before starting to use it.
If you wish to have your code only run onClick for elements with the class test_button2 you can use :
// include this only ONCE on your page.
$(document).ready(function() {
$(this).test(true); // sends the flag to initialize the click() event once
$('.test_button2').click(function(){
$(this).test(); // action on every .test_button2 click();
});
});
.. and replace ..
<button class="test_button2" onclick="$('h2').test()">scroll</button>
.. with ..
<button class="test_button2">scroll</button>
See the code below for the fix in action :
(function ($, win, doc) {
'use strict';
$.fn.test = Plugin;
var publ, priv;
function Plugin(initialize) {
if(initialize === true) {
console.log("start");
$('.test_button').click(function(){
console.log("clicked");
});
}
console.log("in scrolltest");
}
}(jQuery, this, this.document));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<h2>Hello</h2>
<button class="test_button">Click me</button>
<!-- onClick is handled by jQuery's .click() method -->
<button class="test_button2">scroll</button>
</body>
<script>
// this code should only be placed once on your page.
var $test;
$(document).ready(function() {
$test = $(this).test(true);
$('.test_button2').click(function(){
$(this).test();
});
});
</script>

How to write a jquery plugin in OO way

i have written following jquery plugin. what i am trying to do is, when the user click on a link make the relevant div display: block base on the data attribute. But this plugin does not work. i have bn trying to figure this out for last two days. But i failed.
My HTML
<div class="container1">
asd
<div class="window1" data-window="a">
asd
</div>
</div>
<hr>
<div class="container2">
asdf1
asdf2
asdf3
<div class="window2" data-window="b">
asdf1
</div>
<div class="window2" data-window="c">
asdf2
</div>
<div class="window2" data-window="d">
asdf3
</div>
</div>
<script src="jquery-1.11.0.min.js"></script>
<script src="script.js"></script>
<script>
$('.container1').myPlugin({
link: $('.link1'),
container : $('.window1')
});
$('.container2').myPlugin({
link: $('.link2'),
container : $('.window2')
});
</script>
plugin
(function ($, window, document, undefind) {
MyPlugin = {
init : function (options, element) {
$.fn.myPlugin.config = $.extend({}, $.fn.myPlugin.config, options);
var link = $.fn.myPlugin.config.link;
link.on('click', this.secondFunc);
},
secondFunc : function () {
var dataLinkId = $(this).data('link'),
container = $($.fn.myPlugin.config).filter('[data-section="' + dataLinkId + '"]');
container.show();
}
};
$.fn.myPlugin = function(options) {
return this.each(function () {
var rezG = Object.create(MyPlugin);
rezG.init(options, this);
});
};
$.fn.myPlugin.config = {
link: $('.link'),
container : $('.container')
};
})(jQuery, window, document);
CSS
.window1, .window2 {
display: none;
}
DEMO
You need to use var to make sure your variables are all local and not global.
var MyPlugin = {
// ...
};
Also, in the init function, you are doing this:
$.fn.myPlugin.config = $.extend({}, $.fn.myPlugin.config, options);
This is overwriting $.fn.myPlugin.config which is the default options. This means that all elements that call myPlugin() will use the same config. You need to set the config on just the one instance.
this.config = $.extend({}, $.fn.myPlugin.config, options);
Your secondFunc doesn't have a reference to the object (rezG) instance, so it cannot access the config. You need to pass that to secondFunc(). One way is to use a closure to capture the instance.
secondFunc: function (rezG) {
return function(){
var dataLinkId = $(this).data('link'),
container = $(rezG.config.container).filter(function(){
return $(this).data('window') == dataLinkId;
});
container.show();
};
}
Then you bind it like so:
link.on('click', this.secondFunc(this));
Note that in secondFunc, you need to use config.container(not just config which is the object), and also your attribute is data-window, not data-section.
Updated demo: http://jsfiddle.net/K82gg/7/
Your plugin could be as simple as
(function ($, window, document, undefind) {
$.fn.myPlugin = function(options) {
// When $(stuff).myPlugin(...) is called
// this keyword inside of myPlugin function is referencing a set
// of elements plugin was called upon
// e.g. for call like $('.container1').myPlugin();
// this keyword will reference all elements selected by
// $('.container1') not jquery wrapped,
// in general it can be a any number.
return this.each(function pluginImplementation () {
// Here we iterate over the set, and for each element in the set
// we do some pretty standard click
var container = $(this);
// I use 'click.myPlugin' event instead just 'click' ale to later on
// do $(..).off('click.myPlugin') to remove only handlers that were
// attached by plugin (a good practice)
container.on('click.myPlugin', options.linkSelector, function(){
var dataLinkId = $(this).data('link');
container.find('[data-window="' + dataLinkId + '"]').toggle();
})
});
};
})(jQuery, window, document);
See the jsfiddle
However the code above may have a problem luginImplementation () function is created on each iteration and if the body of that function would be something more complicated it would be a mess. That is why it's better to create pluginImplementation () outside.
(function ($, window, document, undefind) {
// Notice that pluginImplementation () now accepts parameters
// They make it possible for pluginImplementation to know which
// elements it's working with
function pluginImplementation (container, options) {
container.on('click.myPlugin', options.linkSelector, function(){
var dataLinkId = $(this).data('link');
container.find('[data-window="' + dataLinkId + '"]').toggle();
})
}
$.fn.myPlugin = function(options) {
return this.each(function () {
pluginImplementation($(this), options);
});
};
})(jQuery, window, document);
The demo
That separation may be not good enough. You may want your plugin to be more OOP and what not. So you can go all OOPy like that:
(function ($, window, document, undefind) {
// For that purpose we create a class
// That describes behavior that our plugin provides
//
function MyPlugin(container, options) {
this.container = container;
this.options = options;
// To the topic of maintainability
// This could be parametrised as an option at plugin instantiation
this.eventName = 'click.myPlugin';
}
MyPlugin.prototype.attachClickHandlers = function() {
var self = this;
// This gets a little messy with all the thises vs selfs and a
// noname function wrapping the handler.
// The point is to preserve this keyword reference
// inside of clickHandler method.
// If I would have just self.clickHandler as a handler there
// this keyword inside of self.clickHandler would reference to
// whatever $(...).on binds handlers to i.e. triggering element.
// I need this keyword inside of self.clickHandler to point to
// "current" instance of MyPlugin, that's why I have wrapping
// function. It just lets me call clickHandler in the right context.
// clickHandler method also needs to know what link is being clicked
// so we pass that in as parameter.
self.container.on(self.eventName,
self.options.linkSelector,
function() {
self.clickHandler($(this));
})
}
MyPlugin.prototype.clickHandler = function(clickedLink) {
var dataLinkId = clickedLink.data('link');
this.container.find('[data-window="' + dataLinkId + '"]').toggle();
}
$.fn.myPlugin = function(options) {
return this.each(function () {
var pluginInstance = new MyPlugin($(this), options);
pluginInstance.attachClickHandlers();
});
};
})(jQuery, window, document);
In this implementation MyPlugin is a class (in javascript sense of the word class) which enables you to tackle each specific point in the way it behaves. and introduce all sorts of OOP features.
The demo

Javascript simple class scope changes when button is pushed

I am sure this is one of the basic questions. I am creating a custom Javascript class and using Jquery on top to do few things. After checking if document is ready I am calling init() and adding event handler. However, when I click the button, I get inside "turnLightOn" function but when it tries to call another function for this class the scope of this has changed to the "button" so I get
Object #<HTMLButtonElement> has no method 'getDataFromServer'
I know this is a simple question but can anyone point to the right answer for me?
<div id="cp">
<ul>
<li><button id="light_switch">Light On</button></li>
</ul>
</div>
<div id="room">
</div>
<script type="text/javascript">
var CP = function(widget, light_switch){
this.widget_name = widget;
this.light_switch = light_switch;
var self = this;
console.log(this);
};
CP.prototype.init = function(){
$("#"+this.light_switch).on('click', this.turnlighton);
};
CP.prototype.somecallback = function(){
console.log(this);
};
CP.prototype.turnlighton = function(){
this.getDataFromServer(somecallback);
};
CP.prototype.getDataFromServer = function(callback){
$.ajax({url:"/"+fname,
success:function(result){
callback(result);
}
});
};
$( document ).ready(function(){
var c = new CP("control_panel", "light_switch");
c.init();
}
);
</script>
in the click handler this by default will refer the clicked element, you can pass a custom context by using Function.bind() or $.proxy()
$("#" + this.light_switch).on('click', $.proxy(this.turnlighton, this));
Demo: Fiddle
I found the issue:
$("#"+this.light_switch).on('click', this.turnlighton);
In this above code this.turnlighton will taken current this of on() method in jquery. you use CP function this.
<script type="text/javascript">
var _this;
var CP = function(widget, light_switch){
this.widget_name = widget;
this.light_switch = light_switch;
_this = this;
console.log(this);
};
CP.prototype.init = function(){
$("#"+_this.light_switch).on('click', _this.turnlighton);
};
CP.prototype.turnlighton = function(){
console.log(this);
_this.getDataFromServer();
};
CP.prototype.getDataFromServer = function(){
/*$.ajax({url:"/"+fname,success:function(result){
console.log(result);
}});*/
};
$( document ).ready(function(){
var c = new CP("control_panel", "light_switch");
c.init();
}
);
</script>
Fiddle

Knockout not binding submit with JQuery1.10.2

EDIT:
this is actually Knockout, JQuery 1.10.2 and trying to override the jquery.unobtrusivevalidation ErrorPlacement function... stopping the submit binding work on a form element.
If I run the same code with JQuery 1.8.2 then just change my JQuery file to 1.10.2 my submit function stops firing... has anyone seen similar to this?
i'm going to post as much relevant code as I can in case its something unexpected but the main point is that submitForm bound to the form submit event perfectly well with jquery 1.8.2 and without any other changes jquery 1.10.2 doesn't touch submitForm (testing with break points and alert() statements).
All other knockout bindings still seem to work.
please help. thanks.
<html>
<head>
<script src="/Content/Scripts/jquery-1.10.2.js"></script>
<script src="/Content/Scripts/jquery-ui/jquery-ui.js"></script>
<script src="/Content/Scripts/jquery-ui-timepicker-addon.js"></script>
<script src="/Content/Scripts/knockout-2.3.0.js"></script>
<script src="/Content/Scripts/knockout-helpers.js"></script>
<script src="/Content/Scripts/knockout.mapping-latest.js"></script>
<script src="/Content/Scripts/underscore.js"></script>
<script src="/Content/Scripts/date.js"></script>
<script src="/Content/Scripts/global.js"></script>
<script src="/Content/Scripts/jquery.blockUI.js"></script>
<script src="/Content/Scripts/jquery.dirtyform.js"></script>
<script src="/Content/Scripts/bootstrap/bootstrap.js"></script>
<script src="/Content/Scripts/sessionTimer.js"></script>
<script src="/Content/Scripts/jquery.livequery.js"></script>
<script src="/Content/Scripts/Ecdm/myCode.js"></script>
</head>
<form action="/Apply" data-bind="submit: submitForm" id="myApplicationForm" method="post">
<!-- html form stuff -->
</form>
<script>
var view;
$(function() {
view = new ModelView({
formSelector: '#myForm',
});
// Base JS model
var model =
{
someProperty: '#Model.SomeProperty',
};
view.bind(model);
});
</script>
</html>
myCode.js:
function ModelView(params) {
var self = this;
// Default parameters
var args = $.extend({
formSelector: 'form' }, params);
this.bind = function (model) {
// Apply KO bindings
ko.applyBindings(self);
};
this.submitForm = function () {
var form = $(args.formSelector);
form.validate();
if (form.valid()) {
var referenceNumber = $('#ReferenceNumber');
if (a==b) {
showConfirmation();
return false;
}
g_showWait("Please wait...");
return true;
}
return false;
}
}
I solved it by using the validate declaration notation rather than directly setting the validator settings but I don't know why. If anyone could explain I would be grateful (i'm sick of looking at it:))
errorPlacement was successfully overridden and working in both cases. submit knockout binding just didn't work.
Instead of overriding the errorPlacement function like this
$("form").each(function() {
var validator = $(this).data('validator');
if (typeof validator != 'undefined') {
validator.settings.errorPlacement = $.proxy(function(error, inputElement) {
//
// do stuff with the error object
//
}, $(this));
}
});
I changed it to this just try anything and it worked:
$("form").each(function () {
var validator = $(this).data('validator');
if (typeof validator != 'undefined') {
$(this).validate({
errorPlacement: $.proxy(function (error, inputElement) {
//
// do stuff with the error object
//
}, $(this));
}
});

Categories

Resources