I have a plugin with the following structure:
(function($){
function pluginName(el, options) {
var _this = this;
_this.defaults = {
someOptions: '',
onSlideStart: function() {},
onSlideEnd: function() {},
};
_this.opts = $.extend({}, _this.defaults, options);
$(el).on("slideStart", function() {
_this.opts.onSlideStart.call();
});
$(el).on("slideEnd", function() {
_this.opts.onSlideEnd.call();
});
}
pluginName.prototype = {
someFunctions: function() {
}
};
$.fn.pluginName = function(options) {
if(this.length) {
this.each(function() {
var rev = new pluginName(this, options);
rev.init();
$(this).data('pluginName', rev);
});
}
};
})(jQuery);
If I call it the following way, everything is okay:
$('.element').pluginName({
someOptions: 'full',
onSlideStart: function() {
console.log('slideStart!');
},
onSlideEnd: function() {
console.log('slideEnd!');
},
});
But I want to dynamic load the custom event handler like this:
(function($){
function pluginName(el, options) {
var _this = this;
_this.defaults = {
someOptions: '',
onSlideStart: function() {},
onSlideEnd: function() {},
};
_this.opts = $.extend({}, _this.defaults, options);
for (var optionName in _this.opts) {
var
optionValue = _this.opts[optionName],
optionType = typeof(optionValue)
;
if(optionType == 'function') {
optionNames = optionName.split('on');
eventName = global.lowerFirstLetter(optionNames[1]);
$(el).on(eventName, function() {
eval('_this.opts.' + optionName + '.call();');
});
}
}
}
...
})(jQuery);
But this does not work. When I call the plugin with the "dynamic" part, it always call the slideEnd-function. So am I doing it wrong or is it just impossible with my plugin-pattern to call the custom event-handler dynamically?
Why use eval ? It's usually bad to use eval.
if(optionType == 'function') {
optionNames = optionName.split('on');
eventName = global.lowerFirstLetter(optionNames[1]);
$(el).on(eventName, _this.opts[optionName]);
}
Try it and let me know.
Related
I'm trying to implement widgits the way DevExtreme does it.
When they create a textbox widgit, this is the code:
$("#someContainer").dxTextBox({ options... });
When they get an instance of the widgit, they do this...
$("#someContainer").dxTextBox("instance");
This is my widget code so far ...
(function ($) {
'use strict';
$.myWidget = function (element, options) {
var plugin = this;
var $base = $(element);
var defaultOptions = {
id: null,
};
var opts = $.extend({}, defaultOptions, options);
var me = new function () {
var self = this;
var init = {
widgets: function () {
// Do some stuff
},
};
return {
init: init,
};
};
me.init.widgets();
};
$.fn.myWidget = function (options) {
return this.each(function () {
if (undefined === $(this).data('myWidget')) {
var plugin = new $.myWidget(this, options);
$(this).data('myWidget', plugin);
}
});
};
})(jQuery)
With this I can create a widget like this...
$("#someContainer").myWidget({ id: 1 });
But I would like to be able to get an instance of the widget, so I could do something like this:
$("#someContainer").myWidget("instance").showPopup();
And also:
var w = $("#someContainer").myWidget({ options... }).myWidget("instance");
w.showPopup();
How can I get an instance?
You have to detect the "special call" for when the instance is requested. Here a small example:
(function ($) {
'use strict';
$.myWidget = function (element, options) {
var plugin = this;
var $base = $(element);
var defaultOptions = {
id: null,
};
var opts = $.extend({}, defaultOptions, options);
var me = new function () {
var self = this;
var init = {
widgets: function () {
return {
hello: function(){
alert("it's me!");
}
}
},
};
return {
init: init,
};
};
return me.init.widgets();
};
$.fn.myWidget = function (options) {
if(options === "instance"){
return $(this).data('myWidget');
}
return this.each(function () {
if (undefined === $(this).data('myWidget')) {
var plugin = new $.myWidget(this, options);
$(this).data('myWidget', plugin);
}
});
};
})(jQuery)
$("#someContainer").myWidget({ id: 1 });
$("#someContainer").myWidget("instance").hello()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="someContainer"></div>
I have a base object ProfileDialog which I am extending with Object.assign().
var ProfileDialog = function (containerObj) {
this.init = function () {
this.container = containerObj;
};
this.render = function () {
let content = document.createElement('div');
content.innerText = 'Dialog here';
this.container.appendChild(content);
};
this.init();
this.render();
};
Mixin:
var DialogMixin = function () {
return {
open: function () {
this.container.style.display = 'block';
},
close: function () {
this.container.style.display = 'none';
}
}
};
Now I do the assignment:
Object.assign(ProfileDialog.prototype, DialogMixin());
It works just fine, this context resolves fine in open and close methods.
But, when I put the mixin in a deeper structure, putting it inside actions property:
var DialogMixin = function () {
return {
actions: {
open: function () {
this.container.style.display = 'block';
},
close: function () {
this.container.style.display = 'none';
}
}
}
};
The context becomes actions object so the code breaks.
How do I properly extend the object with new methods when they are put in a deep structure?
The only thing i can think of is using bind to bind this.
So something like
var ProfileDialog = function (containerObj) {
this.containerObj = containerObj;
};
var DialogMixin = function (newThis) {
var obj = {
actions: {
open: function () {
console.log('open', this, this.containerObj.style);
}
}
}
obj.actions.open = obj.actions.open.bind(newThis);
return obj;
};
var container = {
style : 'some style'
};
var dialog = new ProfileDialog(container);
var mixinDialog = Object.assign(dialog, DialogMixin(dialog));
mixinDialog.actions.open();
See https://jsfiddle.net/zqt1me9d/4/
Hey all I am using flexslider in my website for slider the slider is running fine on my server at http://www.reurl.in/31830875a but when checked on local server or made life somewhere else I am getting this error in console "Cannot read property 'wrapup' of undefined" and slider is not working
Here is the function
function FlexsliderManualDirectionControls( element, options ) {
this.element = element;
this.options = $.extend( {}, defaults, options) ;
this._flexslider = $(element).data('flexslider');
this._originalFlexsliderWrapupFunction = this._flexslider.wrapup;
this._defaults = defaults;
this._name = flexsliderManualDirectionControls;
this.init();
}
This is just a single function out of full page code.
the console says error at this._originalFlexsliderWrapupFunction = this._flexslider.wrapup;
If you find something helpful please do reply back.
Incase you need full code
/*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, immed:false, latedef:true, newcap:true, noarg:true, noempty:true, nonew:true, undef:true, strict:false, trailing:true, browser:true, jquery:true */
/*!
* jQuery flexslider extension
* Original author: #markirby
* Licensed under the MIT license
*/
(function ( $, window, document, undefined ) {
var flexsliderManualDirectionControls = 'flexsliderManualDirectionControls',
defaults = {
previousElementSelector: ".previous",
nextElementSelector: ".next",
disabledStateClassName: "disable"
};
function FlexsliderManualDirectionControls( element, options ) {
this.element = element;
this.options = $.extend( {}, defaults, options);
this._flexslider = $(element).data('flexslider');
this._originalFlexsliderWrapupFunction = this._flexslider.wrapup;
this._defaults = defaults;
this._name = flexsliderManualDirectionControls;
this.init();
}
FlexsliderManualDirectionControls.prototype.init = function () {
this.addEventListeners();
var self = this;
this._flexslider.wrapup = function(direction) {
self.onAnimationEnd.call(self, direction);
};
};
FlexsliderManualDirectionControls.prototype.addEventListeners = function() {
$(this.element).find(this.options.previousElementSelector).bind('touchstart.flexsliderPromo click.flexsliderPromo', {self:this}, function(event) {
event.stopPropagation();
event.preventDefault();
if (!event.handled) {
event.data.self.goToTargetInDirection('prev');
event.handled = true;
}
});
$(this.element).find(this.options.nextElementSelector).bind('click.flexsliderPromo', {self:this}, function(event) {
event.stopPropagation();
event.preventDefault();
if (!event.handled) {
event.data.self.goToTargetInDirection('next');
event.handled = true;
}
});
};
FlexsliderManualDirectionControls.prototype.goToTargetInDirection = function(direction) {
var target = this._flexslider.getTarget(direction);
if (this._flexslider.canAdvance(target)) {
this._flexslider.flexAnimate(target);
}
return false;
};
FlexsliderManualDirectionControls.prototype.addOrRemoveDisabledStateForDirection = function(direction, $navElement) {
var target = this._flexslider.getTarget(direction);
if (!this._flexslider.canAdvance(target)) {
$navElement.addClass(this.options.disabledStateClassName);
} else {
$navElement.removeClass(this.options.disabledStateClassName);
}
};
FlexsliderManualDirectionControls.prototype.onAnimationEnd = function(direction) {
var $nextElement = $(this.element).find(this.options.nextElementSelector),
$previousElement = $(this.element).find(this.options.previousElementSelector);
this.addOrRemoveDisabledStateForDirection('next', $nextElement);
this.addOrRemoveDisabledStateForDirection('prev', $previousElement);
this._originalFlexsliderWrapupFunction(direction);
};
$.fn[flexsliderManualDirectionControls] = function ( options ) {
return this.each(function () {
if (!$.data(this, 'plugin_' + flexsliderManualDirectionControls)) {
$.data(this, 'plugin_' + flexsliderManualDirectionControls,
new FlexsliderManualDirectionControls( this, options ));
}
});
};
})( jQuery, window, document );
Te following code is fine:
var Pill = (function() {
var hideCheckPricesPill = function() {
$(HB.pillSearchBar.checkPrices).hide();
};
var hideAnyPill = function(pill) {
$(pill).hide();
};
var displaySearchBar = function() {
$("." + HB.pillSearchBar.hideSearchForm).removeClass(HB.pillSearchBar.hideSearchForm);
};
var isEditSearchPill = function(pill) {
if(pill === HB.pillSearchBar.editSearchText) {
hideCheckPricesPill();
}
else {
hideAnyPill(pill);
}
};
var isMobileSearch = function(pill) {
if(!$(pill).hasClass(HB.pillSearchBar.jsOpenMobileSearch)){
isEditSearchPill(pill);
displaySearchBar();
}
};
var addEventListenerOnPill = function(pill) {
$(pill).on('click', 'a', function() {
isMobileSearch(pill);
});
};
return {
addEventListenerOnPill: addEventListenerOnPill
}
})();
Is there a way to add a prototype functionality to one of the public functions so that it can be returned and initialized with the "new" key word?
In the following function, my objects inside floatShareBar function is undefined. Do I have to init or define a var before the functions? it throws me js error : .float - function undefined.
(function($) {
.
.
.
$("body").on("ab.snap", function(event) {
if (event.snapPoint >= 768) {
floatShareBar.float()
} else {
floatShareBar.unfloat();
}
});
var floatShareBar = function() {
var fShareBar = $('#article-share');
this.float = function() {
console.log(
};
this.unfloat = function() {
console.log("unfloat");
};
};
.
.
.
})(jQuery);
You need to get an instance of that function with a self instantiating call:
var floatShareBar = (function() {
var fShareBar = $('#article-share');
this.float = function() {
console.log('float');
};
this.unfloat = function() {
console.log("unfloat");
};
return this;
})();
UPDATE 1: I modified it to create an object within the function to attach those functions to, since in the previous example this refers to the window object
var floatShareBar = (function() {
var fShareBar = $('#article-share');
var instance = {};
instance.float = function() {
console.log('float');
};
instance.unfloat = function() {
console.log("unfloat");
};
return instance;
})();
UPDATE 2: You can actually just use the new keyword as well, look here for more info
var floatShareBar = new (function() {
var fShareBar = $('#article-share');
this.float = function() {
console.log('float');
};
this.unfloat = function() {
console.log("unfloat");
};
})();
Change you function to this:
$("body").on("ab.snap", function(event) {
if (event.snapPoint >= 768) {
(new floatShareBar()).float()
} else {
(new floatShareBar()).unfloat();
}
});
function floatShareBar () {
var fShareBar = $('#article-share');
this.float = function() {
console.log(
};
this.unfloat = function() {
console.log("unfloat");
};
};
you should declare functions when using var before you call them.