How do I grab this variable in a separate function? (jQuery) - javascript

I'm trying to use TsearchResultID in the last function but don't know how to access it... In this function ( $(document).on('click', '.slideYThumbnail', function(event) { )
function QueryGetta0() {
var TTsearchQuery = 'x';
return TTsearchQuery;
}
function QueryGetta1() {
return $.get(
"https://www.googleapis.com/youtube/v3/search",{
part: 'snippet',
maxResults: 1,
q: YTSearchQueryText,
type: 'video',
key: ''}
);
}
$(document).on('click', '.lister ul span', function(event) {
QueryGetta1()
.done(function(data) {
var TsearchResultID = data.items[0].id.videoId;
var target = '<div class="slideYThumbnail"><img class="slideYThumbnailInside" src="http://img.youtube.com/vi/' + TsearchResultID + '/0.jpg"></img></div>';
});
});
$(document).on('click', '.slideYThumbnail', function(event) {
alert(TsearchResultID);
});

You can manage it with creation of an object outside in the global scope:
var obj = {
TsearchResultID : "" // <---declare it here.
};
function QueryGetta0() {
// other code as is.
}
function QueryGetta1() {
// other code as is.
}
$(document).on('click', '.lister ul span', function(event) {
QueryGetta1()
.done(function(data) {
obj.TsearchResultID = data.items[0].id.videoId; // <---put value here.
var target = '<div class="slideYThumbnail"><img class="slideYThumbnailInside" src="http://img.youtube.com/vi/' + TsearchResultID + '/0.jpg"></img></div>';
});
});
$(document).on('click', '.slideYThumbnail', function(event) {
alert(obj.TsearchResultID); // now access it here.
});

If you want to share variables across functions, you will have to define them outside functions. This usually involve Global Variables, but its not a good practice to contaminate global scope.
Alternate is, encapsulate all event bindings inside a function registerEvents() and here if you define a variable outside event handlers, you can access them across handlers but it will still be a part of function hence preventing contamination. Also this helps in keeping all bindings together, making debug easier.
Example
function registerEvents() {
var sharableVar = null;
$("#btnInit").on("click", function() {
sharableVar = Math.floor(Math.random() * 10);
});
$("#btnNotify").on("click", function() {
console.log(sharableVar);
})
}
registerEvents()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<button id="btnInit">Initialize</button>
<button id="btnNotify">Notify</button>

Try using an array declared in the global scope.
var TsearchResultIDArray = []; //declaration of array
$(document).on('click', '.lister ul span', function(event) {
QueryGetta1()
.done(function(data) {
TsearchResultIDArray.push = data.items[0].id.videoId;//push the value to the array
var target = '<div class="slideYThumbnail"><img class="slideYThumbnailInside" src="http://img.youtube.com/vi/' + TsearchResultID + '/0.jpg"></img></div>';
});
});
$(document).on('click', '.slideYThumbnail', function(event) {
alert(TsearchResultIDArray[0]); // access the first element of the array.
});
OR
Use session storage to SET/GET the value.
$(document).on('click', '.lister ul span', function(event) {
QueryGetta1()
.done(function(data) {
sessionStorage.setItem('TsearchResultID',data.items[0].id.videoId); //set the value in session
var target = '<div class="slideYThumbnail"><img class="slideYThumbnailInside" src="http://img.youtube.com/vi/' + TsearchResultID + '/0.jpg"></img></div>';
});
});
$(document).on('click', '.slideYThumbnail', function(event) {
alert(sessionStorage.getItem('TsearchResultID')); //get the value from session
});

Related

Item soft rejected due to Proper Event Binding issue

An item I've submitted to themeforest.net got soft rejected with the following message:
PROPER EVENT BINDING: Consider using the preferred .on() method rather than .click(), .bind(), .hover(), etc. For best performance and concise code use event delegation whenever possible
I have no idea what to do actually and would appreciate some help.
This is my code (it’s quite long sorry):
jQuery(document).ready(function($) {
"use strict";
// PRELOADER
$(window).load(function() {
$('#preloader').fadeOut('slow', function() {
$(this).remove();
});
});
// NAV BR RESIZING
$(document).on("scroll", function() {
if ($(document).scrollTop() > 50) {
$("header").removeClass("large").addClass("small");
} else {
$("header").removeClass("small").addClass("large");
}
});
// MOBILE MENU TRIGGER
$('.menu-item').addClass('menu-trigger');
$('.menu-trigger').click(function() {
$('#menu-trigger').toggleClass('clicked');
$('.container').toggleClass('push');
$('.pushmenu').toggleClass('open');
});
// SEARCH
$('.search').click(function(e) {
$(".search-overlay").addClass("visible");
e.preventDefault();
});
$('.close-search').click(function(e) {
$(".search-overlay").removeClass("visible");
e.preventDefault();
});
// FOUNDATION INITIALIZER
$(document).foundation();
// LIGHTCASE
$('a[data-rel^=lightcase]').lightcase({
showSequenceInfo: false,
});
// CONTDOWN
$('[data-countdown]').each(function() {
var $this = $(this),
finalDate = $(this).data('countdown');
$this.countdown(finalDate, function(event) {
$this.html(event.strftime('' +
'<span class="time">%D <span>days</span></span> ' +
'<span class="time">%H <span>hr</span></span> ' +
'<span class="time">%M <span>min</span></span> ' +
'<span class="time">%S <span>sec</span></span>'));
});
});
// SCROLLDOWN BUTTON
$(".show-scrolldown-btn").append("<div class='scrolldown-btn reveal-from-bottom'></div>")
$('.scrolldown-btn').on('click', function() {
var ele = $(this).closest("div");
// this will search within the section
$("html, body").animate({
scrollTop: $(ele).offset().top + 70
}, 500);
return false;
});
// ISOTOPE MASONRY
$(window).load(function() {
var $container = $('.grid');
$container.isotope({
itemSelector: '.grid-item',
columnWidth: '.grid-sizer',
});
var $optionSets = $('.filter'),
$optionLinks = $optionSets.find('a');
$optionLinks.click(function() {
var $this = $(this);
if ($this.hasClass('active')) {
return false;
}
var $optionSet = $this.parents('.filter');
$optionSet.find('.active').removeClass('active');
$this.addClass('active');
// make option object dynamically, i.e. { filter: '.my-filter-class' }
var options = {},
key = $optionSet.attr('data-option-key'),
value = $this.attr('data-option-value');
value = value === 'false' ? false : value;
options[key] = value;
if (key === 'layoutMode' && typeof changeLayoutMode === 'function') {
changeLayoutMode($this, options);
} else {
$container.isotope(options);
}
return false;
});
});
//BACK TO TOP
var offset = 300,
offset_opacity = 1200,
scroll_top_duration = 700,
$back_to_top = $('.backtotop');
$(window).scroll(function() {
($(this).scrollTop() > offset) ? $back_to_top.addClass('is-visible'): $back_to_top.removeClass('is-visible fade-out');
if ($(this).scrollTop() > offset_opacity) {
$back_to_top.addClass('fade-out');
}
});
$back_to_top.on('click', function(event) {
event.preventDefault();
$('body,html').animate({
scrollTop: 0,
}, scroll_top_duration);
});
});
So you would change event listener assignments like the following:
$('.search').click(function(e) {
$(".search-overlay").addClass("visible");
e.preventDefault();
});
...to use the corresponding on method instead, passing the event name as an argument:
$('.search').on("click", function(e) {
$(".search-overlay").addClass("visible");
e.preventDefault();
});
Event delegation is avoiding adding several event listeners to specific nodes and instead adding a single event listener to a common parent element, which then looks to see which child element was clicked on.
There's a good article here:
https://www.google.co.uk/amp/s/davidwalsh.name/event-delegate/amp

Adding event handler to non-existent class?

I've seen questions that relate to non-existent elements, but not non-existent classes. Here's what I want to do. When a button of class "see_answer" is clicked, I want to remove the class and replace it with "see_question". However, my click function for a button, once its class is "see_question", is not running. I have tried $(document).on("click", ".see_question", function(event ) and I have tried $(".see_question").on("click", function(event) {etc.... Thanks for the help! My code is below:
$(document).ready(function() {
// initialize variables
var lang = "javascript";
var qno = 1;
var prevText; // holds question/answer
var language = lang + ".html";
// set up tabs, and keep track of which one is clicked
$("#myTabs").tabs({
activate: function (event, ui) {
var active = $("#myTabs").tabs("option", "active");
lang = $("#myTabs ul > li a").eq(active).attr("href");
lang = lang.replace("#", "");
}
});
/* REMINDERS
actual qa part: blah_language
*/
// set up question
$.ajax({
url: language,
dataType: "html",
success: function(data) {
$("#blah_"+lang)
.text($(data).find("#1").text());
},
error: function(r) {
alert("whoops, error in initialization");
}
});
$(".next_question").on("click", function(event) {
event.preventDefault();
var id = $(this).attr("id").replace("next_question_", "");
var language = id + ".html";
var doc = "#blah_" + id;
$.ajax({
url: language,
dataType: "html",
success: function(data) {
var num = "#" + qno;
$(doc)
.text($(data).find(num).text());
qno = qno + 1;
},
error: function(r) {
alert("whoops");
}
});
prevText = "";
});
// SHOW ANSWER
$(".see_answer").on("click", function(event) {
event.preventDefault();
var id = $(this).attr("id").replace("see_answer_", "");
var prev = "#blah_" + id;
var answers = id + "_answers.html";
// Save the question
prevText = $(prev).text();
var obj = $(this);
$.ajax({
url: answers,
dataType: "html",
success: function(data) {
var num = "#" + 3;
$(prev)
.text($(data).find(num).text());
},
error: function(r) {
alert("whoops");
}
});
obj.val("See Question");
obj.removeClass("see_answer");
obj.addClass("see_question");
event.stopPropagation();
});
$(document).on("click",".see_question", function(event) {
event.preventDefault();
obj = $(this);
event.preventDefault();
var id = $(this).attr("id").replace("see_answer_", "");
var prev = "#blah_" + id;
$(prev).text(prevText);
obj.val("See Answer");
obj.removeClass("see_question");
obj.addClass("see_answer");
});
})
Click handling for .see_question elements is delegated to document. For .see_answer elements, a click handler is attached directly. Therefore, swapping the class names will have an undesirable effect.
when see_answer is in force, a click will trigger the "see_answer" handler.
when see_question is in force, a click will trigger the "see_question" handler AND the "see_answer" handler, which is still attached.
There's a number of ways to do this properly. From where you currently are, the simplest solution is to delegate click handling of .see_question and .see_answer elements to document.
$(document).on("click", ".see_answer", function(event) {
...
});
$(document).on("click", ".see_question", function(event) {
...
});
Combine the 2 handlers and figure out which version it is by hasClass() before you change the classes around
$(document).on("click", ".see_question, .see-answer", function(event ){
var $btn =$(this), isAnswer = $btn.hasClass('see_answer');
// we know which one it is so can switch classes now
$btn.toggleClass('see_answer see_question');
if(isAnswer){
/* run code for answer version */
}else{
/* run code for question version */
}
});

One mouseleave event logs $(this) as element; another logs it as delegated object

I have attached to mouseleave events to two HTML elements. I'm confused why in one printing $(this) to the console shows the div element the event is attached to, and the other prints out the entire window.
$(function () {
$(document).on({
mouseenter: function (evt) {
$(evt.target).data('hovering', true);
},
mouseleave: function (evt) {
$(evt.target).data('hovering', false);
}
}, "*");
$.expr[":"].hovering = function (elem) {
return $(elem).data('hovering') ? true : false;
};
$(document).on({
mouseenter: function () {
var $menu = $(".menu[data-a='" + $(this).attr("data-a") + "']");
//console.log($menu)
$menu.addClass("menu_vis");
$(".menu").hide();
$menu.show();
},
mouseleave: function () {
console.log($(this)) //the div
var s = setTimeout(function () {
var $menu = $(".menu[data-a='" + $(this).attr("data-a") + "']");
var over_menu = $menu.is(":hovering");
if (!over_menu) {
$menu.hide();
}
}, 100);
}
}, ".activate");
$(document).on({
mouseleave: function () {
var s = setTimeout(function(){
var $activate = $(".activate[data-a='" + $(this).attr("data-a") + "']");
var over_activate = $activate.is(":hovering");
console.log($(this)); //the window ??
if (!over_activate){
$(this).hide();
}
}, 100)
}
}, ".menu");
});
Inside the nested function the this keyword refers to the window. (you're using setTimeout i.e. nested inside mouseleave)
To solve: use a variable before using nested function
var that = $(this);
//now when you use function, use like this:
setTimeout(function(){
console.log(that);//logs the Div
},100)
Or use bind method:
setTimeout(function(){
console.log($(this));//logs the Div
}.bind(this),100)

Javascript function only works after page refresh

I have a forum that has a "subscribe" and "unsubscribe" button. When you hit it once, it changes but then doesn't switch back again until the page is refreshed.
http://jsfiddle.net/7QPyL/
Here's my code:
$(document).ready(function () {
// Subscribe to topic subscribedtotopic
$(".notsubscribedtotopic").click(function () {
var topicid = $(this).attr('rel');
$(this).slideUp('fast');
$(this).html('Unsubscribe From Topic');
$(this).removeClass('notsubscribedtotopic').addClass('subscribedtotopic');
$(this).slideDown();
$.get("/base/Solution/SubScribeToTopic/" + topicid + ".aspx",
function (data) {
var result = $('value', data).text();
});
return false;
});
// UnSubscribe to topic subscribedtotopic
$(".subscribedtotopic").click(function () {
var topicid = $(this).attr('rel');
$(this).slideUp('fast');
$(this).html('Subscribe To Topic');
$(this).removeClass('subscribedtotopic').addClass('notsubscribedtotopic');
$(this).slideDown();
$.get("/base/Solution/UnSubScribeToTopic/" + topicid + ".aspx",
function (data) {
var result = $('value', data).text();
});
return false;
});
});
It does not work because the class is not there when you add the event handler, so it can not find the element.
$(".notsubscribedtotopic") and $(".subscribedtotopic") do not magically select new elements as they are added to the page.
You should write one function and just toggle the state.
$(".subscribe").click(function () {
var link = $(this);
var isSubscribbed = link.hasClass("subscribedtotopic");
link.toggleClass("subscribedtotopic notsubscribedtotopic");
...
});
I would set up your code to be something like this:
$(document).ready(function () {
// Subscribe to topic subscribedtotopic
function subscribetotopic() {
var topicid = $(this).attr('rel');
$(this).slideUp('fast');
$(this).html('Unsubscribe From Topic');
$(this).removeClass('notsubscribedtotopic').addClass('subscribedtotopic');
$(this).slideDown();
$.get("/base/Solution/SubScribeToTopic/" + topicid + ".aspx",
function (data) {
var result = $('value', data).text();
});
return false;
}
// UnSubscribe to topic subscribedtotopic
function unsubscribetotopic() {
var topicid = $(this).attr('rel');
$(this).slideUp('fast');
$(this).html('Subscribe To Topic');
$(this).removeClass('subscribedtotopic').addClass('notsubscribedtotopic');
$(this).slideDown();
$.get("/base/Solution/UnSubScribeToTopic/" + topicid + ".aspx",
function (data) {
var result = $('value', data).text();
});
return false;
}
});
And then make a simple onclick call in your HTML element, like so:
<button onclick="subscribetotopic()">Subscribe</button>
If you'd prefer to keep your code the way it is, then clarify which element you want to have active.
Example (simply set a div w/ id mymainelement and button w/ id subscribebutton):
$(#mymainelement .subscribebutton).click(function() { ... });
If you'd prefer to toggle the button instead of having two separate elements, check out #epsacarello's answer.

Calling function inside javascript class

I have the following javascript class (really don't know if it is the best solution) and I wan't to call a function that is definded in this class, insinde another function defined in the same class.
step1 = {
init: function(){
this.events();
},
events: function(){
fct = this; // i stored this in a variable so that i don't lose it
$(document).on('click', '.form-line li', function(e) {
e.preventDefault();
fct.changeCategoryValue($(this));
});
$(document).on('click', '.alert-form .confirm', function(e) {
e.preventDefault();
$.fancybox.close(true);
});
},
changeCategoryValue: function(el) {
cat = el.hasClass('has-sub') ? '' : el.data('id');
title = el.hasClass('has-sub') ? '' : el.data('title');
$('#cat-title').val(title);
$("input[name='category']").val(cat);
}
As you an see I wan't to call the changeCategoryValue function but if I call it with this.changeCategoryValue it won't work. Any suggestions on how to improve the code?
Alternatively, you may change the scope of the function callback:
$(document).on('click', '.form-line li', function(e) {
e.preventDefault();
this.changeCategoryValue($(e.currentTarget));
}.bind(this));
Use .bind(this) so the scope of function(e){...} will be the instance of step1 instead of $('.form-line li',document). Now, to still target the clicked/selected .form-line li, you can access the object via e.currentTarget.
try to use:
step1.changeCategoryValue($(this));
you have added property to the class why don't you call it using class name like this :
step1.changeCategoryValue('any_element_ref');
You could create a proper object. This even allows you call init in the constructor if you wan't.
function Step() { this.init(); }
Step.prototype.init = function() { this.events(); };
Step.prototype.events = function() {
var self = this;
$(document).on('click', '.form-line li', function(e) {
e.preventDefault();
self.changeCategoryValue($(this));
});
$(document).on('click', '.alert-form .confirm', function(e) {
e.preventDefault();
$.fancybox.close(true);
});
};
Step.prototype.changeCategoryValue = function(el) {
cat = el.hasClass('has-sub') ? '' : el.data('id');
title = el.hasClass('has-sub') ? '' : el.data('title');
$('#cat-title').val(title);
$("input[name='category']").val(cat);
};
var step1 = new Step();
you can try use clojure like this:
step1 = (function(){
function events(){
$(document).on('click', '.form-line li', function(e) {
e.preventDefault();
changeCategoryValue($(this));
});
$(document).on('click', '.alert-form .confirm', function(e) {
e.preventDefault();
$.fancybox.close(true);
});
}
function changeCategoryValue(el) {
cat = el.hasClass('has-sub') ? '' : el.data('id');
title = el.hasClass('has-sub') ? '' : el.data('title');
$('#cat-title').val(title);
$("input[name='category']").val(cat);
}
function init(){
events();
}
return {
init:init,
changeCategoryValue: changeCategoryValue
}
})()

Categories

Resources