Cannot read property 'wrapup' of undefined console - javascript

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 );

Related

When creating js widgets, how do I get an instance of my widget?

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>

Create two jQuery plugins that can talk to each other

My head is a mess right now. I want to create two jQuery plugins :
A tab plugin
A slider plugin.
This plugins has to talk to each other, for example, if I click on a tab, this tab will activate the correct index in the associated slider.
If i click on a slide, this will activate the correct tab too.
I started to create events listeners and triggers for that, when my tab was clicked, an event tabChanged is triggered, and in my slider plugin I'm listening to it.
But here is the trouble, my sliders can be loaded before my tabs, so the listeners is not attached correctly...
I tried to trigger another event on the document this time, called tabsLoaded and waiting for that response, it works but it start to be a bit confusing.
I was wondering if someone has a better solution for this ?
Tabs and sliders can work as standalone too, it might be possible to have only tabs without slider associated.
This is my tab plugin:
(function($) {
let pluginName = 'Tabs';
function Tabs(element, options) {
let settings = {};
this.element = element;
this.$element = $(this.element);
this.settings = $.extend({}, settings, options);
this.children = null;
this.activeTabIndex = 0;
this.nbTabs = 0;
this.init();
}
$.extend(Tabs.prototype, {
init: function() {
this.children = this.$element.children();
this.nbTabs = this.children.length;
// Listeners
this.children.on('click', {
tabs: this
}, this.onTabChange); // Click on a tab
$(this).on('tabChange', this.setActive);
// On Init, active the first tab
if (this.children && this.nbTabs > 0) {
$(this).trigger({
type: 'tabChange',
tab: this.children.first().index(),
});
}
$(document).trigger({
type: 'tabLoaded',
tabs: this,
});
},
setActive: function(event) {
this.activeTabIndex = event.tab;
this.children.eq(this.activeTabIndex).addClass('is-active');
},
onTabChange: function(event) {
event.preventDefault();
const tabs = event.data.tabs;
// Reset active classes
tabs.children.removeClass('is-active');
// Launch changeTab
$(tabs).trigger({
type: 'tabChange',
tab: tabs.children.index(event.currentTarget),
});
}
});
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$.data(this, pluginName)) {
$.data(this, pluginName, new Tabs(this, options));
}
});
};
})(jQuery);
jQuery(document).ready(function($) {
$('.js-tabs').Tabs();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
And this is my slider plugin listening to tabs :
(function($) {
let pluginName = 'Slider';
function Slider(element, options) {
let settings = {};
this.element = element;
this.$element = $(this.element);
this.settings = $.extend({}, settings, options);
this.id = null;
this.tabs = null;
this.children = null;
this.activeSlideIndex = 0;
this.nbSlides = 0;
this.init();
}
$.extend(Slider.prototype, {
init: function() {
this.id = this.$element.attr('id');
this.children = this.$element.children();
this.nbSlides = this.children.length;
// Listeners
// Click on slide
this.children.on('click', {
slider: this
}, this.onSlideChange);
// On slide change
$(this).on('slideChange', {
slider: this
}, this.onSlideChange);
$(this).on('change', this.update);
// On Init, active the first tab
if (this.children && this.nbSlides > 0) {
$(this).trigger({
type: 'slideChange',
slide: this.children.first().index(),
});
}
$(document).trigger({
type: 'sliderLoaded',
slider: this,
});
},
update: function() {
// if Slider has an associated Tabs
if (this.tabs) {
$(this.tabs).on('tabChange', {
slider: this
}, this.onTabChange);
}
},
onSlideChange: function(event) {
event.preventDefault();
const slider = event.data.slider;
const slide = event.slide;
// Reset active classes
slider.children.removeClass('is-active');
slider.activeSlideIndex = slide ? slide : event.currentTarget;
console.log(slider.activeSlideIndex);
slider.children.eq(slider.activeSlideIndex).addClass('is-active');
},
// TABS
onTabChange: function(event) {
const slider = event.data.slider;
const tabIndex = event.tab;
if ($(slider.children).eq(tabIndex).length >= 0) {
$(slider).trigger({
type: 'slideChange',
slide: tabIndex,
});
}
}
});
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$.data(this, pluginName)) {
$.data(this, pluginName, new Slider(this, options));
}
});
};
})(jQuery);
jQuery(document).ready(function($) {
$('.js-slider').Slider();
});
// On Tabs loaded, insert it into slider
jQuery(document).on('tabLoaded', function(event) {
const tabs = event.tabs;
const sliderId = jQuery(tabs.element).data('slider-id');
if (jQuery('#' + sliderId).first().data('Slider')) {
const slider = jQuery('#' + sliderId).first().data('Slider');
slider.tabs = tabs;
slider.update();
}
});
I followed #Anton's advices and i split my tabs and sliders and it's working nice :)
First, i removed my plugins' inits from plugins' files.
Then i put every inits into another file that i called "app.js"
My App.js looks like this :
jQuery(document).ready(function ($) {
let $sliders = $('.js-slider').Slider();
let $tabs = $('.js-tabs').Tabs();
$sliders.on('slideChanged', function (event) {
const sliderId = $(this).attr('id');
const slide = event.slide;
$tabs.filter('[data-slider-id=' + sliderId + ']').data('Tabs').select(slide);
});
$tabs.on('tabChanged', function (event) {
const sliderId = $(this).data('slider-id');
const tab = event.tab;
$sliders.filter('#' + sliderId).data('Slider').select(tab);
});
});
I'm listening every events sent like 'slideChanged', or 'tabChanged' then i get the right tabs or slider instance by their matching IDs.
Here my code for tabs :
(function($) {
let pluginName = 'Tabs';
function Tabs(element, options) {
let settings = {};
this.element = element;
this.$element = $(this.element);
this.settings = $.extend({}, settings, options);
this.children = null;
this.activeTabIndex = 0;
this.nbTabs = 0;
this.init();
}
$.extend(Tabs.prototype, {
init: function() {
this.children = this.$element.children();
this.nbTabs = this.children.length;
// Listeners
this.children.on('click', {
tabs: this
}, this.onTabClick); // Click on a tab
$(this).on('tabChanged', this.onTabClick);
// On Init, active the first tab
if (this.children && this.nbTabs > 0) {
this.children.first().click();
}
},
select: function(tab) {
// Reset active classes
this.children.removeClass('is-active');
this.activeTabIndex = tab;
this.children.eq(tab).addClass('is-active');
},
onTabClick: function(event) {
event.preventDefault();
const tabs = event.data.tabs;
const tab = tabs.children.index(event.currentTarget);
tabs.select(tab);
// Launch changeTab
$(tabs.element).trigger({
type: 'tabChanged',
tab: tab,
});
}
});
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$.data(this, pluginName)) {
$.data(this, pluginName, new Tabs(this, options));
}
});
};
})(jQuery);
and slider :
(function($) {
let pluginName = 'Slider';
function Slider(element, options) {
let settings = {};
this.element = element;
this.$element = $(this.element);
this.settings = $.extend({}, settings, options);
this.id = null;
this.tabs = null;
this.children = null;
this.activeSlideIndex = 0;
this.nbSlides = 0;
this.init();
}
$.extend(Slider.prototype, {
init: function() {
this.id = this.$element.attr('id');
this.children = this.$element.children();
this.nbSlides = this.children.length;
// Listeners
// Click on slide
this.children.on('click', {
slider: this
}, this.onSlideClick);
// On slide change
$(this).on('slideChanged', this.onSlideClick);
// On Init, active the first tab
if (this.children && this.nbSlides > 0) {
this.children.first().click();
}
},
select: function(slide) {
// Reset active classes
this.children.removeClass('is-active');
this.activeSlideIndex = slide;
this.children.eq(this.activeSlideIndex).addClass('is-active');
},
onSlideClick: function(event) {
event.preventDefault();
const slider = event.data.slider;
const slide = slider.children.index(event.currentTarget);
slider.select(slide);
// Launch changeTab
$(slider.element).trigger({
type: 'slideChanged',
slide: slide,
});
},
});
$.fn[pluginName] = function(options) {
return this.each(function() {
if (!$.data(this, pluginName)) {
$.data(this, pluginName, new Slider(this, options));
}
});
};
})(jQuery);

Horizontal accordion plugin: working with each container individially

I am trying to create a jQuery plugin, here is the complete code. The question is: what I need to change in the plugin to work for each container as individual?
;(function ( $, window, document, undefined ) {
// Create the defaults once
var pluginName = 'accordion',
defaults = {
propertyName: "value"
};
// The actual plugin constructor
function Plugin( element, options ) {
this.element = element;
this.options = $.extend( {}, defaults, options) ;
this._defaults = defaults;
this._name = pluginName;
this.init();
}
Plugin.prototype.init = function () {
activeItem = $("li").first();
$(activeItem).addClass('active');
$(".tab").click(function(){
$(activeItem).animate({width: "41px"}, 500);
$(activeItem).removeClass('active');
$(this).parent().animate({width: "640px"}, 500);
activeItem = $(this).parent();
$(activeItem).addClass('active');
});
};
$.fn[pluginName] = function ( options ) {
return this.each(function () {
if (!$.data(this, 'plugin_' + pluginName)) {
$.data(this, 'plugin_' + pluginName,
new Plugin( this, options ));
}
});
}
})( jQuery, window, document );
$(document).ready(function(){
$("#acor_1").accordion();
$("#acor_2").accordion();
});

call custom event dynamically on jquery plugin

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.

Slickgrid, column with a drop down select list?

Hi I was wondering if anyone knows if it's possible to define a column in slickgrid as being a drop down select list. If not does anyone with some experience with slickgrid know how I should go about adding this option?
Thanks
You probably dont want to make a new select editor for each range of options. Also you may not know that range of all option value beforehand.
In that case you want a flexible range of options in a select type editor. In order to do this you can add an extra option to your column definitions (e.g. called options) like this:
var columns = [
{id:"color", name:"Color", field:"color", options: "Red,Green,Blue,Black,White", editor: SelectCellEditor},
{id:"lock", name:"Lock", field:"lock", options: "Locked,Unlocked", editor: SelectCellEditor}
]
and access that using args.column.options in the init method of your own SelectEditor object like this:
SelectCellEditor : function(args) {
var $select;
var defaultValue;
var scope = this;
this.init = function() {
if(args.column.options){
opt_values = args.column.options.split(',');
}else{
opt_values ="yes,no".split(',');
}
option_str = ""
for( i in opt_values ){
v = opt_values[i];
option_str += "<OPTION value='"+v+"'>"+v+"</OPTION>";
}
$select = $("<SELECT tabIndex='0' class='editor-select'>"+ option_str +"</SELECT>");
$select.appendTo(args.container);
$select.focus();
};
this.destroy = function() {
$select.remove();
};
this.focus = function() {
$select.focus();
};
this.loadValue = function(item) {
defaultValue = item[args.column.field];
$select.val(defaultValue);
};
this.serializeValue = function() {
if(args.column.options){
return $select.val();
}else{
return ($select.val() == "yes");
}
};
this.applyValue = function(item,state) {
item[args.column.field] = state;
};
this.isValueChanged = function() {
return ($select.val() != defaultValue);
};
this.validate = function() {
return {
valid: true,
msg: null
};
};
this.init();
}
I assume you mean a custom cell editor.
Here's a sample select-based boolean cell editor from slick.editors.js. You could easily modify it to work with an arbitrary set of possible values.
function YesNoSelectCellEditor($container, columnDef, value, dataContext) {
var $select;
var defaultValue = value;
var scope = this;
this.init = function() {
$select = $("<SELECT tabIndex='0' class='editor-yesno'><OPTION value='yes'>Yes</OPTION><OPTION value='no'>No</OPTION></SELECT>");
if (defaultValue)
$select.val('yes');
else
$select.val('no');
$select.appendTo($container);
$select.focus();
};
this.destroy = function() {
$select.remove();
};
this.focus = function() {
$select.focus();
};
this.setValue = function(value) {
$select.val(value);
defaultValue = value;
};
this.getValue = function() {
return ($select.val() == 'yes');
};
this.isValueChanged = function() {
return ($select.val() != defaultValue);
};
this.validate = function() {
return {
valid: true,
msg: null
};
};
this.init();
};
If your cell already contains a "select"-tag with multiple options, you can extract this html from the args. The approach differs from the previous answers, but I was personally troubled with these solutions, course my cell already contained a select-tag. I'd like to reuse this cell instead of reconstructing it completely in the this.init. Likewise, I'd like to keep using the same options, as my existing select already have, instead of parsing them to the var column = { ...
The $( args.item[ args.column.field ] ) return the active cells content, which basically just get re-appended to the the container (the cell-object). From if ( document.createEvent ) and down, is just a functionality which automatically opens the dropdown on activation; etc. when you use tabulator to navigate to the cell.
function SelectCellEditor( args ) {
var $select;
var defaultValue;
var scope = this;
this.init = function () {
$select = $( args.item[ args.column.field ] );
$select.appendTo( args.container );
$select.focus();
// Force the select to open upon user-activation
var element = $select[ 0 ];
if ( document.createEvent ) { // all browsers
var e = new MouseEvent( "mousedown", {
bubbles: true,
cancelable: true,
view: window
});
element.dispatchEvent( e );
} else if ( element.fireEvent ) { // ie
element.fireEvent( "onmousedown" );
}
};
}
Complet editor for Dropdown html-input -> Dropdown html-output
function SelectCellEditor( args ) {
var $select = $( args.item[ args.column.field ] );
var defaultValue;
var scope = this;
this.init = function () {
//$select
$select.appendTo( args.container );
// Force the select to open upon user-activation
var element = $select[ 0 ];
if ( document.createEvent ) { // all browsers
var e = new MouseEvent( "mousedown", {
bubbles: true,
cancelable: true,
view: window
});
element.dispatchEvent( e );
} else if ( element.fireEvent ) { // ie
element.fireEvent( "onmousedown" );
}
$select.on("click", function( e ) {
var selected = $( e.target ).val();
$select.find( "option" ).removeAttr( "selected" );
$select.find( "option[value='" + selected + "']" ).attr( "selected", "selected" );
});
};
this.destroy = function () {
$select.remove();
};
this.focus = function () { };
this.loadValue = function ( item ) { };
this.serializeValue = function () { };
// Only runs if isValueChanged returns true
this.applyValue = function ( item, state ) {
item[ args.column.field ] = $select[ 0 ].outerHTML;
};
this.isValueChanged = function () {
return true;
};
this.validate = function () {
return {
valid: true,
msg: null
};
};
this.init();
}
Without jq, and inline injected elements, packed in module:
'use strict';
class SelectCellWidget {
constructor(args) {
this._args = args;
this._$select = undefined;
this._defaultValue = undefined;
this._init();
}
_init () {
let selects, container, divend, opt_values;
const args = this._args;
if(args.column.options){
opt_values = args.column.options.split(',');
}else{
opt_values = ["yes","no"];
}
container = document.createElement("div");
container.classList.add('select-editable');
divend = document.createElement('input');
divend.setAttribute("type", "text");
divend.setAttribute("name", "format");
divend.setAttribute("value", "");
selects = document.createElement("select");//"<select id='Mobility' tabIndex='0' class='editor-select'>"+ option_str +"</select>";
selects.setAttribute("id", "Mobility");
selects.setAttribute("tabIndex", 0);
selects.setAttribute("class", "editor-select");
for(let i = 0; i < opt_values.length; i++) {
let v = opt_values[i];
let option = document.createElement("option");
option.setAttribute("value", v);
option.innerText = v;
selects.appendChild(option);
}
container.appendChild(divend);
container.appendChild(selects);
this._$select = container;
args.container[0].appendChild(this._$select);
this._$select.focus();
document.getElementById("Mobility").selectedIndex = args.item[args.column.field] ? opt_values.indexOf(args.item[args.column.field]) : 0;
}
destroy () {
this._$select.remove();
}
focus () {
this._$select.focus();
}
loadValue (item) {
this._defaultValue = item[this._args.column.field];
this._$select.value = this._defaultValue;
}
serializeValue () {
if(this._args.column.options){
return this._$select.lastElementChild.value;
}else{
return (this._$select.lastElementChild.value === "yes");
}
}
applyValue (item,state) {
item[this._args.column.field] = state;
}
isValueChanged () {
return (this._$select.lastElementChild.value !== this._defaultValue);
}
validate () {
return {
valid: true,
msg: null
};
}
}
module.exports=SelectCellWidget;
https://github.com/YaAlfred/SlickgridSelectDropdownWidget

Categories

Resources