Flickity won't initialising when switching Tab - javascript

I installed flickity in multiple vanilla js tabs and it is correctly initialized in the first tab. while the content of the first tab is loaded, the content of the second isn't correct initialized.
<div class="outer-wrap">
<ul class="simple-tabs" id="demo-tabs">
<li class="tab-1 active">tab-1</li>
<li class="tab-2">tab-2</li>
<li class="tab-3">tab-3</li>
</ul>
<div class="clear-float"></div>
<div id="tab-1" class="tab-page active-page"><div class="carousel" data-flickity><div class="carousel-cell"></div><div class="carousel-cell"></div><div class="carousel-cell"></div></div></div>
<div id="tab-2" class="tab-page">
<div class="carousel" data-flickity><div class="carousel-cell"></div><div class="carousel-cell"></div><div class="carousel-cell"></div></div></div>
<div id="tab-3" class="tab-page">
<div class="carousel" data-flickity><div class="carousel-cell"></div><div class="carousel-cell"></div><div class="carousel-cell"></div></div></div></div>
JS
<script src="https://cdnjs.cloudflare.com/ajax/libs/flickity/2.2.1/flickity.pkgd.min.js"></script><script>var SimpleTabs = function (elem) {
var activeTabObject;
var TabObject = function () {
var self = this;
this.tab; //element
this.pane; //element
this.setClick = function () {
self.tab.addEventListener('click', self.showThisTab)
};
this.showThisTab = function () {
if (self !== activeTabObject) {
//change the tab page and update the active tab
activeTabObject.pane.className = activeTabObject.pane.className.replace('active-page', '');
activeTabObject.tab.className = activeTabObject.tab.className.replace('active', '');
self.pane.className = self.pane.className + ' active-page';
self.tab.className = self.tab.className + ' active';
activeTabObject = self;
}
};
};
var ul = elem;
var i;
var items = ul.getElementsByTagName("li");
for (i = 0; i < items.length; ++i) {
var tab = new TabObject();
tab.tab = items[i];
var classString = items[i].className;
var className = classString.split(' ')[0];
tab.pane = document.getElementById(className);
tab.setClick();
if (classString.indexOf('active') > -1) {
activeTabObject = tab;
}
}
};</script><script>
window.onload = function() {
var demoTabs = new SimpleTabs(document.getElementById('demo-tabs'));
};
</script>
content of the second isn't correct initialized.
codepen : https://codepen.io/himalayanath/pen/xvgyoO
Thank You!

According to the Flickity document,
you should call resize() after switch tabs.

Related

How can I execute a function without an event?

Solved by # epascarello
Have to execute function without event so that discount can be displayed along with prices at the start without clicking or any other event
You can see in below snippet that 1st one is running automatic while 2nd one is running on click . Can it possible to run 2nd one as automatic because it solves my most of issues using this keyword
Let me know if you need clarification . Any suggestion or comments will be helpful.
function discount1() {
var sendTotal = document.getElementsByClassName("TotalPrice1")[0].innerHTML;
var send1 = sendTotal.replace(/₹/gi, "");
var send2 = send1.replace(/,/gi, "");
var send3 = Number(send2)
var send = document.getElementsByClassName("DiscPrice1")[0].innerHTML;
var send4 = send.replace(/₹/gi, "");
var send5 = send4.replace(/,/gi, "");
var send6 = Number(send5)
var rest = ((send3 - send6) / send3) * 100
document.getElementsByClassName("demo1")[0].innerHTML = rest.toFixed(0) + "% off";
}
discount1();
function discount(rest) {
var sendTotal = rest.parentElement.getElementsByClassName("TotalPrice")[0].innerHTML;
var send1 = sendTotal.replace(/₹/gi, "");
var send2 = send1.replace(/,/gi, "");
var send3 = Number(send2)
var send = rest.parentElement.getElementsByClassName("DiscPrice")[0].innerHTML;
var send4 = send.replace(/₹/gi, "");
var send5 = send4.replace(/,/gi, "");
var send6 = Number(send5)
var rent = ((send3 - send6) / send3) * 100
rest.getElementsByClassName("demo")[0].innerHTML = rent.toFixed(0) + "% off";
}
<div>
<div class="seen" onclick="discount1()">
<div class="TotalPrice1">₹9,728</div>
<div class="DiscPrice1">₹5,435</div>
<div class="demo1"></div>
</div>
</div>
<br>
<div>
<div class="seen" onclick="discount(this)">
<div class="TotalPrice">₹15,670</div>
<div class="DiscPrice">₹13,785</div>
<div class="demo"></div>
</div>
</div>
So you need to call your function with the element.
How you get the elements is up to you. querySelectorAll, getElementsByClassName, ids, etc.
function discount () { /*...*/ }
document.querySelectorAll(".daad").forEach(discount);
you can do it inside of the function
function discount () {
document.querySelectorAll(".daad").forEach(function (reed) {
var saadTotal = reed.parentElement.getElementsByClassName("Total")[0].innerHTML;
console.log('saadTotal', saadTotal);
var saadTotal2 = reed.querySelector(".Total").textContent;
console.log('saadTotal2', saadTotal2);
}
}
discount();
This is answer for previous question you can see in question edits
This is what I needed to do show discount percentage without any event (like onclick or onload) . You can see in below snippet .
function discount(rest) {
var sendTotal = rest.parentElement.getElementsByClassName("TotalPrice")[0].innerHTML;
var send1 = sendTotal.replace(/₹/gi, "");
var send2 = send1.replace(/,/gi, "");
var send3 = Number(send2)
var send = rest.parentElement.getElementsByClassName("DiscPrice")[0].innerHTML;
var send4 = send.replace(/₹/gi, "");
var send5 = send4.replace(/,/gi, "");
var send6 = Number(send5)
var rent = ((send3 - send6) / send3) * 100
rest.getElementsByClassName("demo")[0].innerHTML = rent.toFixed(0) + "% off";
}
document.querySelectorAll(".seen").forEach(discount);;
<div>
<div class="seen" onclick="discount(this)">
<div class="TotalPrice">₹9,728</div>
<div class="DiscPrice">₹5,435</div>
<div class="demo"></div>
</div>
</div>
<br>
<div>
<div class="seen" onclick="discount(this)">
<div class="TotalPrice">₹15,670</div>
<div class="DiscPrice">₹13,785</div>
<div class="demo"></div>
</div>
</div>

Attaching Event to dynamically created element

I am working at my 'To Do List'. My goal is to create an 'delete' button inside previously created div, which contains note written by user.
The problem is that I can't use Jquery - click() because it doesn't work with dynamically created elements.
I tried to use on(), but it causes that 'delete' button appears in every note I made.
var ammleng;
var amount = [];
function ammcheck() {
if (amount.length == 0) {
return amount.length;
} else {
return amount.length++;
}
}
function Start() {
var start = document.getElementsByClassName('start')[0];
start.style.display = 'none';
var textarea = document.getElementsByClassName('textarea')[0];
textarea.classList.remove('locked');
var btn = document.getElementsByClassName('btn__container')[0];
btn.classList.remove('locked');
var text = document.getElementsByClassName('text')[0];
text.classList.add('after');
$('.notes').slideDown(2000);
}
function add() {
var txtarea = document.getElementsByClassName('textarea')[0];
ammleng = amount.length;
if (ammleng >= 13) {
alert('Za dużo notatek!')
} else if (txtarea.innerText.length < 1) {
alert('Nic nie napisałeś :(');
} else {
amount[ammcheck()] = document.getElementsByClassName('note');
var text = $('.textarea').html();
var cont = document.getElementsByClassName('notes')[0];
var ad = document.createElement('div');
var adding = cont.appendChild(ad);
adding.classList.add('note');
adding.innerText = text;
txtarea.innerText = '';
}
}
function reset() {
var els = document.getElementsByClassName('notes')[0];
els.innerHTML = '';
amount = [];
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='content'>
<div class='logo'>
To Do List
</div>
<div class='text'>
<button class='start' onclick='Start()'>Zaczynajmy</button>
<div class='textarea locked' contenteditable='true' data-text='Wpisz notkę...'></div>
<div class='btn__container locked'>
<button class='dodaj' onclick='add()'>Dodaj</button>
<button class='resetuj' onclick='reset()'>resetuj</button>
</div>
</div>
<div class='notes'></div>
</div>
I tried to make it this way, but it return an error (...'appendChild() is not a function...')
var del = document.createElement('div');
del.classList.add('del');
$('.notes').on('click', '.note', function(){
$(this).appendChild(del);
})
use already existing document to bind click on
$(document).on('click', '.note', function(){
$(this).appendChild(del);
})

Why am I getting the error "button.addEventListener is not a function"

Can somebody tell me why I am receiving the above error message with the following code?
It works fine on jsfiddle, though doesn't seem to want to run in the browser.
var bladeRunnerButton = document.querySelector("ul.bladeRunner").innerHTML;
var bladeRunnerContent = document.querySelector("div.bladeRunner").innerHTML;
var detroitButton = document.querySelector("ul.detroit").innerHTML;
var detroitContent = document.querySelector("div.detroit").innerHTML;
var mammejongButton = document.querySelector("ul.mammejong").innerHTML;
var mammejongContent = document.querySelector("div.mammejong").innerHTML;
var buttonArray = [bladeRunnerButton, detroitButton, mammejongButton];
var articleArray = [bladeRunnerContent, detroitContent, mammejongContent];
function createfunc(i) {
return function() { document.getElementById("fillPane").innerHTML = articleArray[i];};
}
for (let i=0; i < articleArray.length; i++) {
let button = buttonArray[i];
button.addEventListener("click", createfunc(i));
}
#content {
display: none;
}
<li>
<ul class="bladeRunner">Blade Runner 2049</ul>
<ul class="detroit">Detroit</ul>
<ul class="mammejong">Mammejong</ul>
</li>
<div class="contentPanel bladeRunner">
</div>
<div class="contentPanel detroit">
</div>
<div class="contentPanel mammejong">
</div>
You should target the Element not the innerHTML to attach the event. So remove innerHTML from the following:
var bladeRunnerButton = document.querySelector("ul.bladeRunner");
var detroitButton = document.querySelector("ul.detroit");
var mammejongButton = document.querySelector("ul.mammejong");
Working Code Example with few modifications in the code:
var bladeRunnerButton = document.querySelector("ul.bladeRunner");
var bladeRunnerContent = document.querySelector("div.bladeRunner").innerHTML;
var detroitButton = document.querySelector("ul.detroit");
var detroitContent = document.querySelector("div.detroit").innerHTML;
var mammejongButton = document.querySelector("ul.mammejong");
var mammejongContent = document.querySelector("div.mammejong").innerHTML;
var buttonArray = [bladeRunnerButton, detroitButton, mammejongButton];
var articleArray = [bladeRunnerContent, detroitContent, mammejongContent];
function createfunc(i) {
document.getElementById("fillPane").innerHTML = articleArray[i];
}
for (let i=0; i < articleArray.length; i++) {
let button = buttonArray[i];
button.addEventListener("click", function(){createfunc(i)});
}
.contentPanel {
display: none;
}
<li>
<ul class="bladeRunner">Blade Runner 2049</ul>
<ul class="detroit">Detroit</ul>
<ul class="mammejong">Mammejong</ul>
</li>
<div class="contentPanel bladeRunner">Blade Runner</div>
<div class="contentPanel detroit">Detroit</div>
<div class="contentPanel mammejong">Mammejong</div>
<div id="fillPane"></div>

How to add styles to a dynamically-generated list item in an initially empty list

I am making a simple todo app, in which the todos, with respective dates are to be shown in a list form below the text input area. I have made an empty list for that and keep on appending todos, along with date. But I want that a strike through should occur across a todo(not across the date), on clicking on the todo. My code can list the todos with date but fails in causing strike-through. What should I change in function struck(ele) and correspondingly in function changeText()?
<div class="container">
<h1>
Your todos
</h1>
<input type="text" id="todo" placeholder="Add a new todo and hit enter" onkeydown="store(this)">
<div class="todos">
<ul id="demo"></ul>
</div>
</div>
<script>
var list = document.getElementById('demo');
function store(ele){
if(event.keyCode==13){
changeText();
}
}
function changeText() {
var data = document.getElementById('todo').value;
var d = new Date();
if(data!='')
{
var entry = document.createElement('li');
var dates = document.createElement("div");
dates.appendChild(document.createTextNode(d.toDateString()));
dates.className = "myClass";
entry.appendChild(document.createTextNode(data));
entry.onclick=struck(this);
entry.appendChild((dates));
list.appendChild(entry);
}
}
function struck(ele) {
ele.style = "text-decoration:line-through; list-style-type:none";
}
</script>
The main problem is that you're calling the onclick function instead of assigning it as a handler.
Change
entry.onclick = struck(this);
to
entry.onclick = () => struck(entry);
Then separate the description into its own element, so it alone can get the strikethrough.
<body>
<div class="container">
<h1>
Your todos
</h1>
<input type="text" id="todo" placeholder="Add a new todo and hit enter" onkeydown="store(this)">
<div class="todos">
<ul id="demo"></ul>
</div>
</div>
<script>
var list = document.getElementById('demo');
function store(ele){
if(event.keyCode==13){
changeText();
}
}
function changeText() {
var data = document.getElementById('todo').value;
var d = new Date();
if(data!='')
{
var entry = document.createElement('li');
entry.description = document.createElement('span');
entry.appendChild(entry.description);
entry.description.appendChild(document.createTextNode(data));
entry.appendChild(document.createTextNode(' ' + d.toDateString()));
entry.onclick = () => struck(entry);
list.appendChild(entry);
}
}
function struck(ele) {
ele.description.style = "text-decoration:line-through; list-style-type:none";
}
</script>
</body>
The solution that Eric has given works great but if I may suggest a minor change, your store() function doesn't function on firefox but it does on chrome, thus I made a few changes of my own to it and you could use it as I find it a better approach towards it.
var enterPressed = function(){
document.getElementById("todo").onkeyup = function(event) {
if(event.which == 13)
changeText();
};
};
enterPressed();
instead of
function store(ele){
if(event.keyCode==13){
changeText();
}
}
a
and onkeydown in input.
var list = document.getElementById('demo');
var enterPressed = function(){
document.getElementById("todo").onkeyup = function(event) {
if(event.which == 13)
changeText();
};
};
function changeText() {
var data = document.getElementById('todo').value;
var d = new Date();
if (data != '') {
var entry = document.createElement('li');
entry.description = document.createElement('span');
entry.appendChild(entry.description);
entry.description.appendChild(document.createTextNode(data));
entry.appendChild(document.createTextNode(" " + d.toDateString()));
entry.onclick = () => struck(entry);
list.appendChild(entry);
}
}
function struck(ele) {
ele.description.style = "text-decoration:line-through; list-style-type:none";
}
enterPressed();
<div class="container">
<h1>
Your todos
</h1>
<input type="text" id="todo" placeholder="Add a new todo and hit enter">
<div class="todos">
<ul id="demo">
</ul>
</div>
</div>
var $ = function (selector) {
return document.querySelector(selector);
};
var list = $("#demo");
function store(ele) {
if (event.keyCode == 13) {
changeText();
}
}
function dynamicEvent() {
this.description.style = "text-decoration:line-through; list-style-type:none";
}
function changeText() {
var data = $("#todo").value;
var date = new Date();
if (data) {
var li = document.createElement("li");
li.description = document.createElement('span');
li.className = 'todo'; // Class name
li.innerHTML = data; // Text inside
li.appendChild(li.description);
li.description.appendChild(document.createTextNode(data));
li.appendChild(document.createTextNode(' ' + date.toDateString()));
li.onclick = dynamicEvent; // Attach the event!
$('#demo').appendChild(li); // Append it
}
}
<div class="container">
<h1>
Your todos
</h1>
<input type="text" id="todo" placeholder="Add a new todo and hit enter" onkeydown="store(this)">
<div class="todos">
<ul id="demo"></ul>
</div>
</div>
This is how I would go about it.
var list = document.getElementById('demo');
const items = [];
const item = e => {
const el = document.createElement('li');
el.insertAdjacentHTML('beforeend', `<span class="title">${ e.t }</span><div class="time">${e.d}</div>`);
const title = el.querySelector('.title');
const time = el.querySelector('.time' );
let strike = 0;
el.addEventListener('click', _ => el.querySelector('span').style.textDecoration = !!(++strike % 2) ? 'line-through' : '');
list.appendChild(el);
return { el, title, time };
};
function store(ele) {
if (event.keyCode == 13) {
items.push(item({ t: ele.value, d: (new Date()).toDateString() }));
console.log(items);
}
}
<div class="container">
<h1>
Your todos
</h1>
<input type="text" id="todo" placeholder="Add a new todo and hit enter" onkeydown="store(this)">
<div class="todos">
<ul id="demo"></ul>
</div>
</div>

How to add different prefixes to different drop-down list in jQuery

After a user clicks a menu option on my drop-down list, I want the top label to have the original menu title followed by a colon, followed by the option they just clicked.
I am using code from this demo, which achieves this effect nicely:
http://tympanus.net/Tutorials/CustomDropDownListStyling/
However, I want to do this with several drop-downs and am trying to customize the demo's code to do so. Here is what I have tried:
HTML:
<section id="options" class="clearfix combo-filters">
<div class="option-combo size">
<div id="dd" class="wrapper-dropdown-3" tabindex="1">
<span data-key="Size: ">Size</span>
<ul class="dropdown option-set clearfix " data-filter-group="size">
<li>Any
<li>Tiny
<li>Small
<li>Medium
<li>Large
<li>Giant
</ul>
</div>
</div>
<div class="option-combo hair">
<div id="ee" class="wrapper-dropdown-3" tabindex="2">
<span data-key="Hair:">Hair</span>
<ul class="dropdown option-set clearfix " data-filter-group="hair">
<li>Any
<li>Short
<li>Medium
<li>Long
</ul>
</div>
</div>
<div class="option-combo trainability">
<div id="ff" class="wrapper-dropdown-3" tabindex="3">
<span>Trainability</span>
<ul class="dropdown option-set clearfix " data-filter-group="trainability">
<li>Any
<li>Easy
<li>Average
<li>Difficult
<li>Very Difficult
</ul>
</div>
</div>
jQuery:
jQuery(document).ready(function(){
/* my code */
var group="";
if ($(this).find('span').data('key')==="size") {
group="Size: ";
}else if ($(this).find('span').data('key')==="hair") {
group="Hair: ";
}
/* my code end */
function DropDown(el) {
this.dd = el;
this.placeholder = this.dd.children('span');
this.opts = this.dd.find('ul.dropdown > li');
this.val = '';
this.index = -1;
this.initEvents();
}
DropDown.prototype = {
initEvents: function () {
var obj = this;
obj.dd.on('click', function (event) {
jQuery(this).toggleClass('active');
return false;
});
obj.opts.on('click', function () {
var opt = jQuery(this);
obj.val = opt.text();
obj.index = opt.index();
obj.placeholder.text(group + obj.val);
});
},
getValue: function () {
return this.val;
},
getIndex: function () {
return this.index;
}
},
jQuery(function () {
var dd = new DropDown(jQuery('#dd'));
jQuery(document).click(function () {
// all dropdowns
jQuery('.wrapper-dropdown-3').removeClass('active');
});
});
jQuery(function () {
var dd = new DropDown(jQuery('#ee'));
jQuery(document).click(function () {
// all dropdowns
jQuery('.wrapper-dropdown-3').removeClass('active');
});
});
jQuery(function () {
var dd = new DropDown(jQuery('#ff'));
jQuery(document).click(function () {
// all dropdowns
jQuery('.wrapper-dropdown-3').removeClass('active');
});
});
});
Here a JsFiddle that put together for this
jsfiddle
The problem is you are using a closure variable to hold the group. Since each dropdown has its on key value, the group is an instance value(not a shared value - so you should not use closure here).
In the below solution the group is added as an instance property of DropDown and it is used later during the selection
Try this
jQuery(function(){
function DropDown(el) {
this.dd = el;
this.placeholder = this.dd.children('span');
this.opts = this.dd.find('ul.dropdown > li');
this.val = '';
this.index = -1;
this.initEvents();
this.group = this.placeholder.data('key');
this.group = this.group.charAt(0).toUpperCase() + this.group.substring(1) + ':';
}
DropDown.prototype = {
initEvents: function () {
var obj = this;
obj.dd.on('click', function (event) {
jQuery(this).toggleClass('active');
return false;
});
obj.opts.on('click', function () {
var opt = jQuery(this);
obj.val = opt.text();
obj.index = opt.index();
obj.placeholder.text(obj.group + obj.val);
});
},
getValue: function () {
return this.val;
},
getIndex: function () {
return this.index;
}
};
new DropDown(jQuery('#dd'));
new DropDown(jQuery('#ff'));
new DropDown(jQuery('#ee'));
jQuery(document).click(function () {
// all dropdowns
jQuery('.wrapper-dropdown-3').removeClass('active');
});
});
Demo: Fiddle

Categories