So I am trying to keep all my functions in 1 jQuery file. Still learning jQuery btw
However I'm running into problems where a div id doesn't exist on a different page and it throws and error. I use the Pop Easy modal plugin. I call $('.modalLink').modal() to initialize the plugin. It works on my home page, but will raise error on my FAQ page because there is no div with modalLink class.
I don't want to create separate files, so how would you re-write this?
$(document).ready(function () {
// PopEasy on Home Page
$('.modalLink').modal({
trigger: '.modalLink', // id or class of link or button to trigger modal
olay:'div.overlay', // id or class of overlay
modals:'div.modal', // id or class of modal
animationEffect: 'fadeIn', // overlay effect | slideDown or fadeIn |
videoClass:'video', // class of video element(s)
close:'.closeBtn' // id or class of close button
});
/*... other code for other pages go below ....*/
// Register Page
$('.login-window input').on('click focusin', function() {
this.value = '';
});
// FAQ Page
// FAQ sidebar menu
$('#faq-btn-general').click(function() {
$(this).parent().addClass('faq-blue');
$('#img-general-on').show();
$('#img-general-off').hide();
$('#dl-general').fadeToggle("slow", "linear");
});
});
If there is no method .modal(), then that is probably because you don't have the proper library loaded to support the .modal() method.
For a well behaved jQuery method (which I assume .modal() is), there should be no problem with:
$('.modalLink').modal();
if the .modalLink object doesn't exist. The $('.modalLink') jQuery object will be empty and calling .modal() on it will just do nothing (or that's how jQuery methods are supposed to be written anyway). If the .modal() method is not well behaved, then you can protect it yourself with this:
// makes sure the .modalLink object exists and that the `.modal()` method exists
var modalObj = $('.modalLink');
if (modalObj.length && modalObj.modal) {
modalObj.modal(...);
}
I would recommend checking to see if the objects exist before adding events to them
You can do so with this.
if ( $('#myDiv').length ){}
So to replace some of your code it would look like this
if ( $('.login-window input').length ){
$('.login-window input').on('click focusin', function() {
this.value = '';
});
}
You can test is method exists such as
if ($.fn.modal) {
$('.modalLink').modal({
trigger: '.modalLink', // id or class of link or button to trigger modal
olay:'div.overlay', // id or class of overlay
modals:'div.modal', // id or class of modal
animationEffect: 'fadeIn', // overlay effect | slideDown or fadeIn |
videoClass:'video', // class of video element(s)
close:'.closeBtn' // id or class of close button
});
}
But that can be long.... You can also add an ident class on the body that you check in the javascript file.
if ($('body').hasClass('forum-section')) {
// Include code concerning that section only
}
Hope that helped
try something like:
if ( $('.myClass').length > 0){
$('.myClass').modal(....)
}
Related
I am integrating a front end html theme with a Laravel app and I am running into an issue with turbolinks not allowing Javascript to append div classes. This is causing the background images to only be displayed on refresh.
<div class="intro-banner" data-background-image="/storage/images/hero.jpg">
<div class="container">
custom.js
/*----------------------------------------------------*/
/* Inline CSS replacement for backgrounds
/*----------------------------------------------------*/
function inlineBG() {
// Common Inline CSS
$(".single-page-header, .intro-banner").each(function() {
var attrImageBG = $(this).attr('data-background-image');
if(attrImageBG !== undefined) {
$(this).append('<div class="background-image-container"></div>');
$('.background-image-container').css('background-image', 'url('+attrImageBG+')');
}
});
} inlineBG();
// Fix for intro banner with label
$(".intro-search-field").each(function() {
var bannerLabel = $(this).children("label").length;
if ( bannerLabel > 0 ){
$(this).addClass("with-label");
}
});
// Photo Boxes
$(".photo-box, .photo-section, .video-container").each(function() {
var photoBox = $(this);
var photoBoxBG = $(this).attr('data-background-image');
if(photoBox !== undefined) {
$(this).css('background-image', 'url('+photoBoxBG+')');
}
});
It looks like this code is only run once: on the initial page load. To get it working for every page load, you will need to run it on turbolinks:load. As the script also appends elements to the page, you need to be careful that you don't end up with unnecessary duplicate elements. Turbolinks stores a copy of the page in its final state before a visitor navigates away. This cached copy will include any appended HTML. So be sure your code checks for the presence of the appended elements before appending, or remove the elements before they are cached.
The following takes the latter approach, by removing elements on turbolinks:before-cache:
/*----------------------------------------------------*/
/* Inline CSS replacement for backgrounds
/*----------------------------------------------------*/
$(document).on('turbolinks:load', function () {
$(".single-page-header, .intro-banner").each(function() {
var attrImageBG = $(this).attr('data-background-image');
if(attrImageBG !== undefined) {
$(this).append('<div class="background-image-container"></div>');
$('.background-image-container').css('background-image', 'url('+attrImageBG+')');
}
});
// Fix for intro banner with label
$(".intro-search-field").addClass(function () {
if ($(this).children("label").length) return "with-label";
});
// Photo Boxes
$(".photo-box, .photo-section, .video-container").css('background-image', function () {
return 'url('+$(this).attr('data-background-image')+')'
})
});
$(document).on('turbolinks:before-cache', function () {
$(".single-page-header, .intro-banner").each(function() {
$(this).children(".background-image-container").remove();
});
});
I have also tidied up some of the jQuery code. Many jQuery functions accept functions as arguments, which simplifies things somewhat, and removes the need to iterate over a jquery selection with each.
Finally, wrapping lots of snippets in $(document).on('turbolinks:load', function () {…} is not great practice as creates a dependency on Turbolinks, and if you ever decided to move to something else, you have to update every place where this is called. If you're feeling adventurous, you may want to create a mini-framework like the one I create here: https://stackoverflow.com/a/44057187/783009
I build a small color-picker module. But it only opens up (and then works) when pickColor is called a second time. I also tried to wrap the _openColorPicker into a setTimeout but that didn't work either. In fact, the color-picker didn't show up at all when I did that.
What I found interesting is that the binding to the change event works, so the $ selector must have found the element already.
So I have two questions:
1) why is the picker only showing after the second call to _openColorPicker?
2) why didn't the picker open at all when I wrapper the _openColorPicker call in a setTimeout?
Edit: The _openColorPicker functions gets executed after the user has right-clicked into the document and then clicked on context-menu which is now showing.
Complete Code:
const ColorUtils = {
_initialized: false,
_openColorPicker: function () {
$('#color-picker').click();
},
pickColor: function (onChangeCallback, context) {
if (!this._initialized) {
$('<input/>').attr({
type: 'color',
id: 'color-picker',
display: 'hidden',
value: '#ffffff'
}).appendTo('#centralRow');
this._initialized = true;
$('#color-picker').on('change', onChangeCallback.bind(context));
}
this._openColorPicker();
// version with timeOut
const scope = this;
setTimeout(function () {
scope._openColorPicker();
}, 1000);
}
};
export default ColorUtils;
Above code is used like ColorUtils.pickColor(onColorPicked, this);
Check out this post. Looks like you can't trigger a click on an invisible color picker. That answer suggests giving the element an absolute position and placing it off screen, like so:
position:absolute;
left:-9999px;
top:-9999px;
I tried to replicate your case (for what I understood) : JSFIddle
I made some changes.
I moved the $('<input/>') in a property of the object ColorUtils and appended it to the DOM with absolute position and outside the screen.
(And also commented display:'hidden' because it's either display:none or visibility:hidden and as a CSS property, not Html attribute)
On right clic on the document I instantiate the picker (and register the callback + context) then add a button to the DOM to trigger the picker again.
Does it fulfill your requirements ?
I'm pretty new to jQuery and I'm trying to set a class based on localStorage.getItembut it isn't working. Here is my code:
if (localStorage.getItem("active_layout") == 2) {
$("#laa").addClass("active");
};
The localstorage item has the value of 2 and the class gets added when I click on the element. But when I refresh, it gets removed. Is it possible to keep it there and not get removed on refresh?
Try re-adding the class on document ready:
$(function() {
if (localStorage.getItem("active_layout") == 2) {
$("#laa").addClass("active");
};
});
add Active Class as default and remove it when you not need ...
if (localStorage.getItem("active_layout") !== 2) {
$("#laa").removeClass("active");
};
or add this Class Ready method
$(document).ready(function(){
if (localStorage.getItem("active_layout") == 2) {
$("#laa").addClass("active");
};
});
When the page is refreshed you will get a completely new page. Changes done with javascript will have to be redone.
If you want to use localstorage you will have to re-add the class on every refresh (Like Evan's answer).
You could also add some serverside logic so that the html is served with the class you want. However the server cannot read localstorage - you could use a cookie.
I have a bunch of HTML toggle (two-state) widgets. I declare them in my HTML like this:
<div class='togglewidget'></div>
<div class='togglewidget'></div>
This looks nice because it is clean and simple.
Then I use jQuery to fill in the elements that make the widgets actually look like they are supposed to. I also attach a function to click events:
$(".togglewidget").append("/* stuff to make the widget work */");
$(".togglewidget").click(function() {toggleWidget(this);});
The toggleWidget() function does animation and handles state change. This all works great.
What I want is to add a custom function to each widget that gets called from the toggleWidget() function depending on state. I would like something like this:
<div class='togglewidget' customfunc='clicked1'></div>
<div class='togglewidget' customfunc='clicked2'></div>
function toggleWidget(this) {
var widget = $(s);
if (/* check for toggle state */) {
// state change of widget is animated (I know how to do this)
...
// call custom function for this individual widget (how to do this?)
widget.GetCustomFunc(true);
} else {
// state change of widget is animated (I know how to do this)
...
// call custom function for this individual widget (how to do this?)
widget.GetCustomFunc(false)
}
}
Then I define clicked1() for the first widget and clicked2() for the second widget. Each widget animates correctly based on behavior in toggleWidget, and clicked() and clicked2() define what actually happens when the individual widget is toggled.
What is the best way of doing this?
I think I could add an onClick="" to each togglewidget div, but then I don't have easy access to the state of the widget, and ordering might be an issue. I think the idea of having a "customfunc" property of the tag might work, but I think that would not validate as HTML.
You could check for the customfunc attribute using jquery:
if($(this).attr('customfunc')) =='customfunc1') {
}
else {
}
Try
function toggleWidget(this) {
var widget = $(s);
if ( /* check for toggle state */ ) {
// state change of widget is animated (I know how to do this)
...
// call custom function for this individual widget (how to do this?)
var cufn = widget.attr('customfun');
if ($.isFunction(widget[cufn])) {
widget[cufn]();
}
widget.GetCustomFunc(true);
} else {
// state change of widget is animated (I know how to do this)
...
// call custom function for this individual widget (how to do this?)
var cufn = widget.attr('customfun');
if ($.isFunction(widget[cufn])) {
widget[cufn]();
}
widget.GetCustomFunc(false)
}
}
Try this:
function toggleWidget(this) {
var widget = $(s);
var indexOfWidget = $('.togglewidget').index($(this));
// for example to add custom property
$(this).attr('customFunc', 'onClick' + indexOfWidget);
}
Try this:
var fun=$(this).attr('customfunc');
if(fun){
eval(fun+"()");
}
This will call any function returned by "customfunc" attr
I am trying to display a table (or ul) that will contain a navigation bar on my page, but only displays the tabs that will contain jquery called divs present on the html.
Essentially, it's a single html document that contains all divs, jquery hides all divs but the first, and the nav bar will allow to navigate through each.
Now I am trying to make it easy to use for my client, so that the menu items will only exist if the div for it also exists. I've got most of it done, the only thing is actually knowing if a div exists.
I tried using this:
if(document.getElementById("page1")) {
document.write("<b>Good morning</b>");}
else
{
document.write("<b>Bad morning </b>");
}
When I place the above code within the div page1, it returns true. Is there no way to do it from the top of the page and not within the div?
Thanks!
Update:
As suggested by many, I have used the following:
$j(document).ready(function(){
//Hide the sections we don't need right away
$j("#page2").hide();
$j("#page3").hide();
$j("#page4").hide();
if ($j('#page1').length > 0) {
var page = 'Excellent Morning' ;
}
});
Then when I try to use:
document.write(page);
It displays the following instead:
[object HTMLBodyElement]
Why not use jQuery since you are already?
if ($('#page1').length > 0) {
// do stuff...
}
EDIT: As davin pointed out, your code should be evaluated after the DOM has been rendered. You can do this by placing it in a $(document).ready call:
$(document.ready(function() {
if ($('#page1').length > 0) {
// do stuff...
}
});
EDIT 2: Based on the OP's edits, a better solution would be to add a placeholder element and to set its content (like FishBasketGordo suggested). An example of this:
$(document.ready(function() {
//Hide the sections we don't need right away
$("#page2, #page3, #page4").hide();
if ($('#page1').length) {
$('#myPlaceHolder').html('<b>Good Morning</b>');
}
else
{
$('#myPlaceHolder').html('<b>Bad Morning</b>');
}
});
Somewhere else in the document...
<span id="myPlaceHolder"></span>
If you place it at the top of the page, the page1 div doesn't exist when the code runs. If you are using jQuery, place the code in a $(document).ready event. Then, you can put it where you want it within the markup. Here's an example:
$(document).ready(function() {
if (document.getElementById("page1")) {
document.write("<b>Good morning</b>");
} else {
document.write("<b>Bad morning </b>");
}
});
Although, rather than doing a document.write, I would consider having a placeholder span or div, and setting it's innerHTML property (or use jQuery's html method). I would also use CSS for my style instead of <b> tags, but that's another matter entirely.
You can use
if ($(selector).length > 0) {
// element exists
}
or you can check out this post for a more elegant solution
Is there an "exists" function for jQuery?