I'm trying to convert one of my plugin written with the jquery plugin pattern with the one provided by jquery-boilerplate. My plugin relies on a $( window ).resize() function to make it responsive, however when I try to use it on the jquery-boilerplate the web console returns a TypeError when I resize the window browser:
function Plugin ( element, options ) {
this.element = element;
this.cfg = $.extend( true, defaults, options );
this._defauls = defaults;
this._name = pluginName;
this.init();
}
// Avoid Plugin.prototype conflicts
$.extend( Plugin.prototype, {
init: function() {
this.windowWidth();
$(window).resize(function(){
this.windowWidth();
});
},
windowWidth: function() {
var w = $( window ).width();
console.log(w);
}
} );
Web console returns:
TypeError: this.windowWidth is not a function.
I tried in this way too:
function Plugin ( element, options ) {
this.element = element;
this.cfg = $.extend( true, defaults, options );
this._defaults = defaults;
this._name = pluginName;
this.init();
$(window).resize(function(){
this.init();
});
}
// Avoid Plugin.prototype conflicts
$.extend( Plugin.prototype, {
init: function() {
this.windowWidth();
},
windowWidth: function() {
var w = $( window ).width();
console.log(w);
}
} );
and the web console returns:
TypeError: this.init is not a function.
Where do I have to put code that have to listen to the jquery resize method according to the jquery-boilerplate?
I basically made it work in this way:
function Plugin ( element, options ) {
var element = $( element ),
cfg = $.extend( true, defaults, options ),
windowWidth = function() {
return $( window ).width();
};
console.log( windowWidth() );
$(window).resize(function(){
console.log( windowWidth() );
});
}
But this isn't the purpose of the jquery-boilerplate team, so how can I do this while using the jquery-boilerplate plugin pattern?
This error has nothing to do with jquery-boilerplate.
You definitely should learn more about "this" keyword in Javascript before writing any plugins.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/this
Related
I have the following jQuery plugin code to do something on window load or scroll:
Note: I simplified the code for the example.
;(function ($, window, document, undefined) {
'use strict';
$.scrollFn = function (el, options) {
var base = this;
// jQuery and DOM of element
base.$el = $(el);
base.el = el;
// Cached
base.$win = $(window);
base.$doc = $(document);
// Initialize
base.init = function () {
base.options = $.extend({}, $.scrollFn.defaultOptions, options);
};
// Scroll handler
base.scrollHandler = function () {
console.log('scrolled or loaded');
console.log(base.options.exampleOption);
};
// On scroll and load
base.$win.on('scroll load', base.scrollHandler);
};
$.scrollFn.defaultOptions = {
exampleOption: "Test"
};
$.fn.scrollFn = function (options) {
return this.each(function () {
(new $.scrollFn(this, options));
});
};
})(jQuery, window, document);
And in another JS I am initializing the scroll function:
$(document).ready(function() {
$('.example').scrollFn({
exampleOption: "Hello world"
});
});
The issue: It is picking up window scroll but not load. When the window loads I do not see the console return scrolled or loaded. It shows only when I scroll.
How can I make load work as well?
I tried (inside scrollFn):
$(window).on('scroll load', base.scrollHandler);
base.$doc.on('scroll load', base.scrollHandler);
$(document).ready(function() {
base.$win.on('scroll load', base.scrollHandler);
});
They do not work.
I had to simply add base.scrollHandler in the init function. I will except any other answer providing more info or a better solution if possible.
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
I'm trying to work with the this keyword in the following jQuery plugin, however I don't want to access the this of the click event, but the this of the plugin.
How do I do that? currently I get the following error in the Plugin.prototype.toggleTranslationMode function:
Cannot read property 'enableTranslationMode' of undefined
;
(function($, window, document, undefined) {
var pluginName = 'translationMode',
defaults = {
//marker: "value"
};
function Plugin(element, options) {
this.element = $(element);
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype.init = function() {
this.getTranslationData();
this.createMarkup();
this.addEvents();
};
Plugin.prototype.getTranslationData = function() {
this.elementIndex = this.element.data('element-index');
this.translationIndex = this.element.data('translation-index');
this.original = this.element.data('translation-original');
this.translation = this.element.data('translation-trans');
this.translationType = this.element.data('translation-type');
}
Plugin.prototype.createMarkup = function() {
this.element.addClass('translation-container');
this.element.wrapInner('<span class="editor"></span>');
this.editor = this.element.find('.editor');
this.addMarker();
}
Plugin.prototype.addMarker = function() {
this.element.append('<div class="translation-marker">' + this.elementIndex + '-' + this.translationIndex + '</div>');
this.marker = this.element.find('.translation-marker');
};
Plugin.prototype.enableTranslationMode = function() {
console.log('translation mode enabled')
this.element.addClass('translation-modal-visible');
this.element.append('<div class="translation-modal">Original String:' + original + '</div>');
}
Plugin.prototype.disableTranslationMode = function() {
console.log('translation mode disabled')
this.element.removeClass('translation-modal-visible');
this.element.find('.translation-modal').remove();
}
Plugin.prototype.addEvents = function() {
this.disableLinksAndButtons();
this.toggleTranslationMode();
}
/*
* EVENTS
*/
Plugin.prototype.toggleTranslationMode = function() {
this.element.on('click', this.marker, function(e) {
if ($(this).hasClass('translation-modal-visible')) {
this.disableTranslationMode();
} else {
this.enableTranslationMode();
}
})
}
Plugin.prototype.disableLinksAndButtons = function() {
$("a, button").on('click', function(e) {
e.preventDefault();
});
}
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new Plugin(this, options));
}
});
}
})(jQuery, window, document);
jQuery(function($) {
$('[data-translation-index]').translationMode();
});
this inside event handler belongs to the element on which the event is called. You are trying to access this.element. enableTranslationMode inside your click event handler and expect it to be the same as outside(the prototype function scope). This will not be the case.
You can save the outside this as another variable and access it inside. But in your case I think you can directly access this.enableTranslitionMode since you are looking for the element itself.
I have form in my react application, which validates via jquery validation plugin.
let validator = $('form').validate({
errorClass: 'has-error',
errorElement:'label',
});
validator.form();
if ($('.has-error').length > 0) {
$('.has-error').each(function (index) {
$.validator().showErrors({prop:$(this).data('error')});
});
} else {
/*work with data*/
}
All errors messages showing fine, but every time when validation triggered, I get error in console:
this.init is not a function
And link me to code in plugin script:
$.validator = function( options, form ) {
this.settings = $.extend( true, {}, $.validator.defaults, options );
this.currentForm = form;
this.init();
};
How can I fix it?
UPD 1: below in the plugin script code i found this code:
$.extend( $.validator, {
//some code
prototype: {
init: function() {
this.labelContainer = $( this.settings.errorLabelContainer );
this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
this.submitted = {};
this.valueCache = {};
this.pendingRequest = 0;
this.pending = {};
this.invalid = {};
this.reset();
//some code
Maybe it fires error exception because of this init function?
I think the problem is in this line:
$.validator().showErrors({prop:$(this).data('error')});
$.validator function is a constructor so it must always be used with new keyword. If you call it as normal function this inside this function points to global window (or is undefined in strict mode) which doesn't have init method
I've run into a strange problem with my jQuery code. I have a setup as follows:
(function($) {
var o = $({});
$.subscribe = function() { o.on.apply(o, arguments); };
$.publish = function() { o.trigger.apply(o, arguments); };
}(jQuery));
(function($) {
var CarrierView = {
subscriptions: function() {
$.subscribe( 'reporting.carrier.model.changed', this.renderModel );
},
renderModel: function( e, data ) {
var self = CarrierView;
}
};
var CarrierModel = {
subscriptions: function() {
$.subscribe( 'reporting.carrier.model.update', this.updateModel );
},
updateModel: function( value ) {
$.getJSON('carriers', function( data ) {
$.publish( 'reporting.carrier.model.changed', data );
});
}
};
window.CarrierView = CarrierView.init();
window.CarrierModel = CarrierModel.init();
})(jQuery);
Running a very basic pub/sub. My issue is the following:
A click event triggers the CarrierModel.updateModel method, which calls $.getJSON. The data returned is an Array[99], which is then published. When CarrierView.renderModel is called, the data there is the first element of the Array[99], an Array[5]. What am I doing incorrectly? How do I pass the whole set of data to the View?
I have written a jQuery plugin below and would like to be able to call it again for the same instance on an element.
The plugin goes...
(function($) {
$.fn.myPlugin = function(options){
var settings = {
color: null
};
if (options) {
$.extend(settings, options);
}
return this.each(function(){
var self = this;
var pics = $('li', self);
function refresh() {
pics = $('li', self);
};
$('a', self).click(function(){
pics.filter(':last').remove();
alert(settings.color);
refresh();
return false;
});
});
}
})(jQuery);
In the page this is called...
$('#test').myPlugin({ color: 'blue' });
Now I want to call the same plugin for the same instance but pass the string refresh as the option whilst all the other variables are the same (so color would still be blue) e.g...
$('#test').myPlugin('refresh');
This would then execute the refresh() function.
How could I achieve that with the above?
Edit: To make it clearer I am thinking of how jQuery UI does their plugins. In the sortable plugin you can do $("#sortable").sortable(); and then $("#sortable").sortable('refresh'); on the same element. This is what I am trying to achieve.
You can store your instance with .data() and check for it when creating an instance.
Something like:
$.fn.doStuff = function () {
var ob = $(this);
var data = ob.data();
if (data.doStuff !== undefined) {
return data.doStuff;
}
doStuff;
});
(function($) {
$.fn.myPlugin = function(options){
var init = function($self, ops){
$self.find("a").click(function(){
pics.filter(':last').remove();
alert(settings.color);
refresh();
return false;
});
};
this.refresh = function(){
//your code here
};
return this.each(function(){
var self = this;
var pics = $('li', self);
var settings = {
color: null
};
var ops = $.extend(true, settings, options);
init($(this), ops);
});
}
})(jQuery);
try something like this. and you can call refresh() like $().myPlugin().refresh();