I want to make a common function that can be call in html so I can update the value from variable.
function getActivityPoint(activityName) {
document.getElementsByClassName('share_points')[0].innerHTML = activityName;
}
my variable
var ap = {
'movie_review':'20',
}
And in HTML I would like to do this.
<div class="share_points" onload="getActivityPoint(ap.movie_review)">-</div>
<div class="share_points" onload="getActivityPoint(ap.game_review)">-</div>
.............
The inline onload event does not work for a div.
You may change your code in order to change your divs, using data attributes, like:
<div class="share_points" data-load="movie_review">-</div>
and on window load you can do your work:
window.addEventListener("load", function(event) {
document.querySelectorAll('.share_points').forEach(ele => getActivityPoint(ele, ap[ele.dataset.load]));
});
function getActivityPoint(ele, activityName) {
ele.textContent = activityName;
}
var ap = {
'movie_review':'20',
'game_review': 10
}
/****************
For Compatibility issue you may write:
window.addEventListener("load", function (event) {
Array.prototype.slice.call(document.querySelectorAll('.share_points')).forEach(function (ele) {
getActivityPoint(ele, ap[ele.dataset.load]);
});
});
For IE < 9 the solution is:
window.addEventListener("load", function (event) {
var divs = document.querySelectorAll('.share_points');
for (i = 0; i < divs.length; i++) {
getActivityPoint(divs[i], ap[divs[i].dataset.load]);
}
});
*/
<div class="share_points" data-load="movie_review">-</div>
<div class="share_points" data-load="game_review">-</div>
You can do:
var ap = {
'movie_review': '20',
'game_review': '100'
},
share_points = document.getElementsByClassName('share_points');
window.addEventListener('load', function() {
Array.prototype.forEach.call(share_points, function(el) {
el.innerHTML = ap[el.dataset.review];
});
});
<div class="share_points" data-review="movie_review">-</div>
<div class="share_points" data-review="game_review">-</div>
Related
I have a map with multiple cities on it. I also have a loop showing the details of each city. I would like to completely stop the loop once I click on one of the cities.
I tried with: clearTimeout(loopIdx) but it didn't work. Could you please help me?! Cheers.
LOOP:
$(function() {
var $mapCol = $('.map-col');
var $mapBtn = $('.map-btn');
var $mapLoops = $('.map-loop');
var $btnLoops = $('.btn-loop');
loopIdx = (function _loop(idx) {
$mapCol.removeClass('active-map');
$mapBtn.removeClass('active-btn');
$mapLoops.removeClass('active-map').eq(idx).addClass('active-map');
$btnLoops.removeClass('active-btn').eq(idx).addClass('active-btn');
setTimeout(function() {
_loop((idx + 1) % $mapLoops.length);
}, 6000);
}(0));
});
BTN:
<div class="btn-loop">City</div>
Assign the result of setInterval() to a variable, and use that in the clearTimeout() call.
$(function() {
var $mapCol = $('.map-col');
var $mapBtn = $('.map-btn');
var $mapLoops = $('.map-loop');
var $btnLoops = $('.btn-loop');
var timer;
loopIdx = (function _loop(idx) {
$mapCol.removeClass('active-map');
$mapBtn.removeClass('active-btn');
$mapLoops.removeClass('active-map').eq(idx).addClass('active-map');
$btnLoops.removeClass('active-btn').eq(idx).addClass('active-btn');
timer = setTimeout(function() {
_loop((idx + 1) % $mapLoops.length);
}, 2000);
}(0));
$btnLoops.click(function() {
clearTimeout(timer);
});
});
.map-loop.active-map {
background-color: yellow;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="btn-loop">City</div>
<div class="map-loop">1</div>
<div class="map-loop">2</div>
<div class="map-loop">3</div>
<div class="map-loop">4</div>
<div class="map-loop">5</div>
<div class="map-loop">6</div>
<div class="map-loop">7</div>
You need to access the timeoutID by name or identifier to clear it. (See https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/clearTimeout.)
If you want loopIdx to be the identifier, you can use something like:
let needToClear = false;
let loopIdx = setTimeout(function(){}, 6000);
// ...state changes here...
if(needToClear){ clearTimeout(loopIdx); }
Is there a way to get all javascript associated with an html element by class name returned in an array? Any suggestion as to how one would achieve doing this? Are there any node packages that would allow me to do something like this?
For example:
HTML
<div class="click_me">Click Me</div>
JS
$('.click_me').on('click', function() { alert ('hi') });
I would want something like (psuedo-code either on the client or server side):
function meta() {
let js = [];
js = getAllJavascriptByClassName('click_me');
console.log(js[0]);
}
Output of meta()
$('.click_me').on('click', function() { alert ('hi') });
This will pull out all event handlers of all elements of given class.
But these handlers must be attached using jquery.
function getAllEventHandlersByClassName(className) {
var elements = $('.' + className);
var results = [];
for (var i = 0; i < elements.length; i++) {
var eventHandlers = $._data(elements[i], "events");
for (var j in eventHandlers) {
var handlers = [];
var event = j;
eventHandlers[event].forEach(function(handlerObj) {
handlers.push(handlerObj.handler.toString());
});
var result = {};
result[event] = handlers;
results.push(result);
}
}
return results;
}
// demo
$('.target').on('click',function(event){
alert('firstClick handler')
});
$('.target').on('click',function(event){
alert('secondClick handler')
});
$('.target').on('mousedown',function(event){
alert('firstClick handler')
});
console.log(getAllEventHandlersByClassName('target'));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class='target'> </div>
You can use getEventListeners() which is part of the chrome devtools but for employing client side, there's an possible-duplicate question that partially answers this: How to find event listeners on a DOM node when debugging or from the JavaScript code? which basically shows (in the second voted answer) that depending on how the events are set (javascript attribute, eventListener, jquery, other lib) there are different ways to retrieve the functions.
The Visual Event 2 program mentioned in the first question seems to be more of a library doing what the second answer is suggesting so maybe this will solve your problem.
If you are interested only in jQuery solution I may suggest you (I assume there is only one event per type, but you need to cycle on all instances):
function getAllJavascriptByClassName(className) {
var elem = $('.' + className);
var result = [];
$('.' + className).each(function(index, element) {
var resultObjs = jQuery._data(element, "events");
var partialResult = [];
var x = Object.keys(resultObjs).forEach(function(currentValue, index, array) {
partialResult.push(resultObjs[currentValue][0].handler.toString());
});
result.push(partialResult);
});
return result;
}
function meta() {
let js = [];
js = getAllJavascriptByClassName('click_me');
console.log(JSON.stringify(js, null, 4));
}
$(function () {
$('.click_me').on('click', function (e) {
alert('Click event: hi')
});
$('.click_me:last').on('keypress', function (e) {
alert('Keypress event: hi')
});
meta();
});
<script src="https://code.jquery.com/jquery-1.12.3.min.js"></script>
<div class="click_me">Click Me</div>
<div class="click_me">Click Me</div>
I would personally override addEventListener at the right places (meaning at the very top) with some safe guards.
UNfortunately jquery event handlers appear to be quite hard to read...
var element = document.getElementById("zou");
element.addEventListener("click", function(e) {
console.log("clicked from addevent");
});
element.addEventListener("mouseup", function(e) {
console.log("mouseup from addevent");
});
$(element).on("mousedown", function(e) {
console.log("mousedown from $")
});
console.log(element.getListeners());
<script>
window.eventStorage = {};
(function() {
var old = HTMLElement.prototype.addEventListener;
HTMLElement.prototype.addEventListener = function(a, b, c) {
if (!window.eventStorage[this]) {
window.eventStorage[this] = [];
}
var val = {
"event": a,
"callback": b
};
var alreadyRegistered = false;
var arr = window.eventStorage[this];
for (var i = 0; i < arr.length; ++i) {
if (arr.event == a && arr.callback == b) {
alreadyRegistered = true;
break;
}
}
if (!alreadyRegistered) {
arr.push(val);
}
old.call(this, a, b, c);
}
HTMLElement.prototype.getListeners = function() {
return window.eventStorage[this] || {};
}
}());
</script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="zou">click on me</div>
I am attempting to use Bootstrap's Collapse feature with custom icons from font-awesome. I am able to get the collapse to work but the problem I am having is that all of the icons are being triggered with Jquery's click, I want to scale this because at any given time the amount of "containers" can change. Any suggestions are appreciated.
$(document).ready(function () {
$faChevronDown = $('.fa-chevron-down');
var z = 0;
$faChevronDown.click(function () {
if (z == 0) {
turnUp();
z++;
} else {
turnDown();
z = 0;
}
});
});
function turnUp() {
$faChevronDown.removeClass('fa-chevron-down');
$faChevronDown.addClass('fa-chevron-up');
};
function turnDown() {
$faChevronDown.removeClass('fa-chevron-up');
$faChevronDown.addClass('fa-chevron-down');
};
JS Fiddle
Thank you
Edit : Thank you for the great answers!
You are clicking only one element, but your function is changing all icons, you have use $(this) instead in order to only change the icon you are clicking:
function toggleClass() {
$(this).toggleClass('fa-chevron-down fa-chevron-up');
};
and then use only one function:
$faChevronDown.click(toggleClass);
With this you avoid the use of Ifs and elses and the code is much simplier and small.
Set click handler on the parent element of a .fa-chevron-down element or if the parent element is not known on body element:
$(document).ready(function () {
var z = 0;
$("body").on("click", ".fa-chevron-down", function () {
if (z == 0) {
turnUp.call(this);
z++;
} else {
turnDown.call(this);
z = 0;
}
});
});
function turnUp() {
$(this).removeClass('fa-chevron-down');
$(this).addClass('fa-chevron-up');
};
function turnDown() {
$(this).removeClass('fa-chevron-up');
$(this).addClass('fa-chevron-down');
};
If you are using z variable only for switching classes fa-chevron-down and fa-chevron-up, the code could be simplified to:
$(document).ready(function () {
$("body").on("click", ".fa-chevron-down", function () {
$(this).toggleClass('fa-chevron-down fa-chevron-up');
});
});
You can pass in the element to perform granular toggling,
$(document).ready(function () {
$fa= $('.fa');
var z = 0;
$fa.click(function () {
if (z == 0) {
turnUp($(this));
z++;
} else {
turnDown($(this));
z = 0;
}
});
});
function turnUp(el) {
el.removeClass('fa-chevron-down');
el.addClass('fa-chevron-up');
};
function turnDown(el) {
el.removeClass('fa-chevron-up');
el.addClass('fa-chevron-down');
};
I'm not sure what the point of your z variable is, but you can reduce what you have, and fix the problem of not referencing the element by using this, by using just:
$(document).ready(function () {
$('.fa-chevron-down').click(function () {
$(this).toggleClass('fa-chevron-down fa-chevron-up')
});
});
jsFiddle example
I have a list of divs containing images/videos/galleries etc.
The structure is as follows:
<div class="item image">image content</div>
<div class="item video">video content</div>
<div class="item gallery">gallery content</div>
<div class="item image">image content</div>
<div class="item image">image content</div>
<div class="item video">video content</div>
As you can see, there can be more than one div with the same content type.
What I want to achieve is scan the list of divs with class=item and generate a button for each content type.
This is what I have so far, using jQuery EACH function
$(document).ready(function () {
$(".item").each(function () {
if ($(this).hasClass("image")) {
alert('image found');
};
if ($(this).hasClass("video")) {
alert('video found');
};
});
});
Problem is the alert get executed multiple times, for each div with the class equal to my condition. As I am planning to generate buttons for each content type this current code will add duplicate buttons as more than one div can have a class of video/image.
I have tried using "return false" inside the IF condition but that breaks my whole EACH function, stopping it at the first reference.
You can create a temporary variable that keeps track of which item types you have already traversed
(function() {
var types = {},
type_re = /\b(?:audio|video|quote|link|image|gallery|status|chat)\b/g;
$('.item').each(function() {
var m = this.className.match(type_re);
if (m !== null && !types.hasOwnProperty(m[0])) {
// code to add button
console.log('add button for type ' + m[0]);
types[m[0]] = true;
}
});
}());
Demo
Previous answers
You can create an array first that will contain all the types found in the document:
var types = [],
type_re = /audio|video|quote|link|image|gallery|status|chat/g;
$('.item').each(function() {
var m;
while ((m = type_re.exec(this.className)) !== null) {
if (!$.inArray(types, t[0])) {
types.push(t[0]);
}
}
});
// types is an array with all types found
Alternatively, iterate over all possible types and filter the items based on each type:
var $items = $('.item'),
types = ['audio', 'video', 'quote', 'link', 'image', 'gallery', 'status', 'chat'];
$.each(types, function(_, type) {
var $itemsOfType = $items.filter(function() {
return (' ' + this.className + ' ').indexOf(type) != -1;
});
if ($itemsOfType.length) {
}
});
Some really easy approach would be to add a status variable for each possible content type and check it:
$( document ).ready(function() {
var _image = true,
_video = true;
$( ".item" ).each(function() {
if ($(this).hasClass( "image" ) && _image) {
_image = false;
alert('image found');
};
if ($(this).hasClass( "video" ) && _video) {
_video = false;
alert('video found');
};
});
});
You can do this.
if($(".image").length>0)
{
alert("image Found")
//generate button
}
JSFIDDLE http://jsfiddle.net/rWrCA/
You can easily use an array for the types and another array for whether or not those exist. That looks something like:
$(document).ready(function () {
// a list of all types and a list of types that were found
var allTypes = ["image", "video", "gallery"];
var typesFound = [];
// loop over all items and add types to the list of found types
$(".item").each(function () {
for (var idx = 0; idx < allTypes.length; idx++) {
if ($(this).hasClass(allTypes[idx])) {
if (typesFound.indexOf(allTypes[idx]) < 0) {
typesFound.push(allTypes[idx]);
}
}
}
});
// as in the original code - prove this worked by displaying alerts!
for (var idx = 0; idx < typesFound.length; idx++) {
alert(typesFound[idx] + ' found');
}
});
I think that should do it!
Make an object in your jQuery ready function. When finished looping, write your buttons using the buttons object.
$(document).ready(function () {
var buttons = {};
$(".item").each(function () {
if ($(this).hasClass("image")) {
buttons.image = 1;
};
if ($(this).hasClass("video")) {
buttons.video = 1;
};
});
// write buttons
for (var type in buttons) {
$('<button/>', {
text: type,
id: 'btn_'+ type,
click: function () { alert('hi'); }
}).appendTo('body');
}
})
I wrote this code for create menu with div tag
HTML:
<div id="firstMenuList">
<div id="firstMenu">chooseâ–¼</div>
<div id="menulist" class="menulist"></div>
</div>
JavaScript:
<script>
function ccc() {
var id="firstMenu";
var ar=new Array("hi","there","hello","world");
var node=document.createElement("div");
var parent=document.getElementById("menulist");
var nodeData="";
for (var i=0;i<ar.length;i++)
{
var node=document.createElement("div");
node.setAttribute("id",id+""+i);
node.setAttribute("class","menulist");
node.setAttribute("onclick","select("+id+""+i+")");
node.style.top=((i+1)*100)+3+"%";
node.innerHTML=ar[i];
parent.appendChild(node);
}
}
function select(id)
{
var p=document.getElementById(id);<-this doesn't work on elements that created dynamically
p.style.backgroundColor="red";
var t = p.innerHTML;
}
</script>
This code creates the menu, but when I click on the menu items code breaks.
The error is:
"parent is null"
To pass the id to the function you need to ensure that you put quotes around the id:
node.setAttribute("onclick","select('"+id+i+"')");
// note the single quotes ----------^--------^
Demo: http://jsfiddle.net/QK5Wh/1/
But you don't need to use the id to get the element when you can pass a direct reference to the element itself:
node.setAttribute("onclick","select(this)");
And then:
function select(p) {
p.style.backgroundColor="red";
var t = p.innerHTML;
}
Demo: http://jsfiddle.net/QK5Wh/
I'll suggest to avoid the inline event binding. Here is a working example:
http://jsfiddle.net/H4S2f/1/
function ccc() {
var id="firstMenu";
var cls="firstMenuList";
var ar=new Array("hi","there","hello","world");
var node=document.createElement("div");
var parent=document.getElementById("menulist");
var nodeData="";
for (var i=0;i<ar.length;i++)
{
var node=document.createElement("div");
node.setAttribute("id",id+""+i);
node.setAttribute("class","menulist");
(function(i) {
node.addEventListener("click", function() {
select(id+""+i)
});
})(i);
node.style.top=((i+1)*100)+3+"%";
node.innerHTML=ar[i];
parent.appendChild(node);
}
}
function select(id)
{
var p=document.getElementById(id);
p.style.backgroundColor="red";
var t = p.innerHTML;
}
ccc();