Have to use same function with two different variable with querySelector attached to the variable. Following is the javascript.
var productLink = document.querySelector('.products-link');
var productOffcanvas = document.getElementById('offcanvasProducts')
productOffcanvas.addEventListener('show.bs.offcanvas', function () {
element.classList.toggle('active');
})
productOffcanvas.addEventListener('hide.bs.offcanvas', function () {
productLink.classList.toggle('active');
})
var solutionsLink = document.querySelector('.solutions-link');
var solutionsOffcanvas = document.getElementById('offcanvasSolutions')
solutionsOffcanvas.addEventListener('show.bs.offcanvas', function () {
solutionsLink.classList.toggle('active');
})
solutionsOffcanvas.addEventListener('hide.bs.offcanvas', function () {
solutionsLink.classList.toggle('active');
})
Using a function which returns a function:
function func(link) {
return () => link.classList.toggle('active');
}
Then:
productOffcanvas.addEventListener('show.bs.offcanvas', func(element));
productOffcanvas.addEventListener('hide.bs.offcanvas', func(productLink));
solutionsOffcanvas.addEventListener('show.bs.offcanvas', func(solutionsLink));
solutionsOffcanvas.addEventListener('hide.bs.offcanvas', func(solutionsLink));
You can use same listner for both function and differentatie them with their class names.
const productLink = document.querySelector('.products-link');
const productOffcanvas = document.getElementById('offcanvasProducts');
productOffcanvas.addEventListener('show.bs.offcanvas', showOffCanvas);
productOffcanvas.addEventListener('hide.bs.offcanvas', hideOffCanvas);
const solutionsLink = document.querySelector('.solutions-link');
const solutionsOffcanvas = document.getElementById('offcanvasSolutions')
solutionsOffcanvas.addEventListener('show.bs.offcanvas', showOffCanvas);
solutionsOffcanvas.addEventListener('hide.bs.offcanvas', hideOffCanvas);
function showOffCanvas(e) {
const classList = e.target.classList;
if(classList.contains('products-link')) {
productLink.classList.toggle('active');
} else {
solutionsLink.classList.toggle('active');
}
}
function hideOffCanvas(e) {
const classList = e.target.classList;
if(classList.contains('products-link')) {
productLink.classList.toggle('active');
} else {
solutionsLink.classList.toggle('active');
}
}
You can use like:
function toggleCanvasVisibility(targetElement, el) {
targetElement.addEventListener('show.bs.offcanvas', function () {
el.classList.toggle('active');
})
targetElement.addEventListener('hide.bs.offcanvas', function () {
el.classList.toggle('active');
})
}
function findAndRegisterCanvasVisibility(canvasId, targetClass) {
const element = document.querySelector(targetClass);
const canvasElement = document.getElementById(canvasId);
toggleCanvasVisibility(canvasElement, element);
}
// for product link
findAndRegisterCanvasVisibility('offcanvasProducts', '.products-link');
// for solutions
findAndRegisterCanvasVisibility('offcanvasSolutions', '.solutions-link');
Related
I need to callback. a. function after setting a state within a nested function which triggers on click, How can I approach this, I know that calling hooks in nested functions doesn't work but it's necessary in my case. I tried using useEffect and useCallback but as expected it wont work The code looks like this in a nutshell:
const App = () => {
const [elements, setElements] = useState(true);
function UseEffectSkipFirst(fn, arr) {
const isFirst = useRef(true);
useCallback(() => {
if (isFirst.current) {
isFirst.current = false;
return;
}
fn();
}, arr);
}
const Shape = (g) => {
// let colorMatrix = new PIXI.filters.ColorMatrixFilter();
// let color = 0xffffff
// let tint = 0xffffff;
function onClick(event) {
setElements(false);
UseEffectSkipFirst(
() => {
if (elements === true) {
this.data = event.data;
this.dragging = true;
this.offX = this.x - this.data.getLocalPosition(this.parent).x;
this.offY = this.y - this.data.getLocalPosition(this.parent).y;
} else {
g.clear();
}
},
[elements]
);
}
// ...
};
return (
//...
);
};
can anyone help please, thanks
I installed Shuffle.js from a codepen demo with some customizations to style and figure cards. I've added in recommended js code but the shuffle function doesn't seem work.
Getting several errors:
console errors
I've tried updating script based on some past answers to this problem. I've also downloaded and added the actual js file on my site and referenced it in the script. Here's what my script looks like right now:
<script src="/v/vspfiles/assets/js/shuffle.js"></script>
<script>
'use strict';
var Shuffle = window.shuffle;
var Demo = function (element) {
this.element = element;
// Log out events.
this.addShuffleEventListeners();
this.shuffle = new Shuffle(element, {
itemSelector: '.picture-item',
sizer: element.querySelector('.my-sizer-element'),
});
this._activeFilters = [];
this.addFilterButtons();
this.addSorting();
this.addSearchFilter();
this.mode = 'exclusive';
};
Demo.prototype.toArray = function (arrayLike) {
return Array.prototype.slice.call(arrayLike);
};
Demo.prototype.toggleMode = function () {
if (this.mode === 'additive') {
this.mode = 'exclusive';
} else {
this.mode = 'additive';
}
};
/**
* Shuffle uses the CustomEvent constructor to dispatch events. You can listen
* for them like you normally would (with jQuery for example). The extra event
* data is in the `detail` property.
*/
Demo.prototype.addShuffleEventListeners = function () {
var handler = function (event) {
console.log('type: %s', event.type, 'detail:', event.detail);
};
this.element.addEventListener(Shuffle.EventType.LAYOUT, handler, false);
this.element.addEventListener(Shuffle.EventType.REMOVED, handler, false);
};
Demo.prototype.addFilterButtons = function () {
var options = document.querySelector('.filter-options');
if (!options) {
return;
}
var filterButtons = this.toArray(
options.children
);
filterButtons.forEach(function (button) {
button.addEventListener('click', this._handleFilterClick.bind(this), false);
}, this);
};
Demo.prototype._handleFilterClick = function (evt) {
var btn = evt.currentTarget;
var isActive = btn.classList.contains('active');
var btnGroup = btn.getAttribute('data-group');
// You don't need _both_ of these modes. This is only for the demo.
// For this custom 'additive' mode in the demo, clicking on filter buttons
// doesn't remove any other filters.
if (this.mode === 'additive') {
// If this button is already active, remove it from the list of filters.
if (isActive) {
this._activeFilters.splice(this._activeFilters.indexOf(btnGroup));
} else {
this._activeFilters.push(btnGroup);
}
btn.classList.toggle('active');
// Filter elements
this.shuffle.filter(this._activeFilters);
// 'exclusive' mode lets only one filter button be active at a time.
} else {
this._removeActiveClassFromChildren(btn.parentNode);
var filterGroup;
if (isActive) {
btn.classList.remove('active');
filterGroup = Shuffle.ALL_ITEMS;
} else {
btn.classList.add('active');
filterGroup = btnGroup;
}
this.shuffle.filter(filterGroup);
}
};
Demo.prototype._removeActiveClassFromChildren = function (parent) {
var children = parent.children;
for (var i = children.length - 1; i >= 0; i--) {
children[i].classList.remove('active');
}
};
Demo.prototype.addSorting = function () {
var menu = document.querySelector('.sort-options');
if (!menu) {
return;
}
menu.addEventListener('change', this._handleSortChange.bind(this));
};
Demo.prototype._handleSortChange = function (evt) {
var value = evt.target.value;
var options = {};
function sortByDate(element) {
return element.getAttribute('data-created');
}
function sortByTitle(element) {
return element.getAttribute('data-title').toLowerCase();
}
if (value === 'date-created') {
options = {
reverse: true,
by: sortByDate,
};
} else if (value === 'title') {
options = {
by: sortByTitle,
};
}
this.shuffle.sort(options);
};
// Advanced filtering
Demo.prototype.addSearchFilter = function () {
var searchInput = document.querySelector('.js-shuffle-search');
if (!searchInput) {
return;
}
searchInput.addEventListener('keyup', this._handleSearchKeyup.bind(this));
};
/**
* Filter the shuffle instance by items with a title that matches the search input.
* #param {Event} evt Event object.
*/
Demo.prototype._handleSearchKeyup = function (evt) {
var searchText = evt.target.value.toLowerCase();
this.shuffle.filter(function (element, shuffle) {
// If there is a current filter applied, ignore elements that don't match it.
if (shuffle.group !== Shuffle.ALL_ITEMS) {
// Get the item's groups.
var groups = JSON.parse(element.getAttribute('data-groups'));
var isElementInCurrentGroup = groups.indexOf(shuffle.group) !== -1;
// Only search elements in the current group
if (!isElementInCurrentGroup) {
return false;
}
}
var titleElement = element.querySelector('.picture-item__title');
var titleText = titleElement.textContent.toLowerCase().trim();
return titleText.indexOf(searchText) !== -1;
});
};
document.addEventListener('DOMContentLoaded', function () {
window.demo = new Demo(document.getElementById('grid'));
});
</script>
Any insight into what I need to remedy to get this working properly would be great. Thanks!
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/
I have a simple JS object which emulates traffic lights:
function TrafficLight(redTime, yellowTime, greenTime) {
var self = this;
this.__timer = null;
this.__state = null;
this.__redTime = redTime;
this.__yellowTime = yellowTime;
this.__greenTime = greenTime;
var setnewtimer = function (delay, func) {
console.log('SET!');
if (self.__timer) {
clearTimeout(this.__timer);
}
self.__timer = setTimeout(delay, func);
};
TrafficLight.prototype.toRed = function () {
this.__state = 'red';
setnewtimer(this.__redTime, function () {
console.log('RED!');
self.toGreen();
});
};
TrafficLight.prototype.toGreen = function () {
this.__state = 'green';
setnewtimer(this.__greenTime, function () {
console.log('GREEN');
self.toYellow();
});
};
TrafficLight.prototype.toYellow = function () {
this.__state = 'yellow';
setnewtimer(this.__yellowTime, function () {
console.log('YELLOW');
self.toRed();
});
};
TrafficLight.prototype.state = function () {
return this.__state;
};
this.toGreen();
}
But when I make a TrafficLight object (like var a = new TrafficLight(1000, 1000, 1000);), every a.state() call returns green (so traffic light doesn't change its state by timer. What's wrong with my code?
You don't call setTimeout correctly.
Change
setTimeout(delay, func);
to
setTimeout(func, delay);
I have a nested function that I want to call from outside.
var _Config = "";
var tourvar;
function runtour() {
if (_Config.length != 0) {
tourvar = $(function () {
var config = _Config,
autoplay = false,
showtime,
step = 0,
total_steps = config.length;
showControls();
$('#activatetour').live('click', startTour);
function startTour() {
}
function showTooltip() {
}
});
}
}
function proceed() {
tourvar.showTooltip();
}
$(document).ready(function () {
runtour();
});
I was hoping to call it by tourvar.showTooltip(); but I seem to be wrong :) How can I make showTooltip() available from outside the function?
since my previous answer was really a hot headed one, I decided to delete it and provide you with another one:
var _Config = "";
var tourvar;
// Module pattern
(function() {
// private variables
var _config, autoplay, showtime, step, total_steps;
var startTour = function() { };
var showTooltip = function() { };
// Tour object constructor
function Tour(config) {
_config = config;
autoplay = false;
step = 0;
total_steps = _config.length;
// Provide the user with the object methods
this.startTour = startTour;
this.showTooltip = showTooltip;
}
// now you create your tour
if (_Config.length != 0) {
tourvar = new Tour(_Config);
}
})();
function proceed() {
tourvar.showTooltip();
}
$(document).ready(function () {
runtour();
});
function outerFunction() {
window.mynestedfunction = function() {
}
}
mynestedfunction();