Script Revision for event.target - javascript

I'm kind of a newbie to js, could someone have a look at this code and tell me if it is correct and if it could be improved and how? it is working as intended, but honestly I don`t know if it is well written. Thanks in advance (:
<script>
$(document).ready(function() {
$("button").click(function(event) {
var a = (event.target).classList.item(0);
var b = ".carousel" + "." + a ;
$(b).myfunction;
});
});
</script>
The reason for that script is that I have a Carousel (Bootsrap) inside a Slider ("JQuery lightSlider") inside a custom popup modal and I don`t want the imgs carousel to load at page start only when the carousel would be visible.
What the script does is to "store" the class name of the button element ("custom-n") clicked, then write .carousel.custom-x to be stored in the variable b, and then use the var b as a selector to call the function for that custom-n carousel that replaces data-src with src.
I hope this isn't confusing haha
This is a simplification of the html, the modal opens whenever a <button> is clicked.
The are kind of a "thumbnail" for the main slider (light-slider), so:
<button class="custom-1"> opens the modal and set the "light-slider" to slide n1
<button class="custom-2"> opens the modal and set the "light-slider" to slide n2
and so on.
The carousels inside the lightslider's slides they all have img with data-src and the Idea is to replace the data-src with src of the carousel that should be "related" to the custom
<div class="light-slider-buttons">
<button class="custom-1 myclass"></button>
<button class="custom-2 myclass"></button>
<button class="custom-3 myclass"></button>
</div>
<div class="modal-wrp">
<div class="modal-inner">
<ul id="light-slider">
<li>
<div class="slide-wrapper">
<div class="carousel custom-1">
<div class="carousel-inner">
<div class="carousel-item active">
<img data-src="...">
</div>
<div class="carousel-item">
<img data-src="...">
</div>
<div class="carousel-item">
<img data-src="...">
</div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>

The code looks good.
I have two suggestions.
Firstly, you seem to be using class attribute to store data (custom-1, etc)
Why not set it to data-item-class attribute instead (any name starting with data- will do)?
<div class="light-slider-buttons">
<button class="myclass" data-item-class="custom-1"></button>
<button class="myclass" data-item-class="custom-2"></button>
<button class="myclass" data-item-class="custom-3"></button>
</div>
The value can be read as event.target.dataset.itemClass (item-class becomes itemClass, see docs for more info).
The code for variable a will be replaced with:
var a = event.target.dataset.itemClass;
Secondly, setting click event handler for 'button' selector is too wide.
It will cause errors when new button element with another purpose gets added to your page in the future.
It is much safer to think of <div class="light-slider-buttons"> as a component wrapping your button elements and apply the click handler only to those.
$(".light-slider-buttons button").click(function(event) {
...
}
It does not change much but is important because if you add other buttons outside <div class="light-slider-buttons"> they will not get click event handler.
jQuery uses CSS selectors syntax, you can find more in docs.
Here's the recommended code for script tag
<script>
$(document).ready(function() {
$(".light-slider-buttons button").click(function(event) {
var a = event.target.dataset.itemClass;
var b = ".carousel" + "." + a ;
$(b).myfunction;
});
});
</script>
P.S. jQuery programming style is quite imperative (specifying how page should update on every event).
There are other ways to build UI, for example in React programming is declarative (specifying how UI should look like based on given input/state)

Related

Preload HTML from within Javascript file, into the DOM, but don't execute

Im creating a simple JS game, which will run in the browser and will pull the files directly from the pc. Because of this needed to make a workaround the "Cross-origin" error, which went smoothly, I put all the HTML within a JS and loaded the JS from the tag in the index.html. Everything was going smoothly so far.
You click "press any key to continue" -> but then next you click "New Game" and you get event listener error "can't set property of null". Which i don't understand how it happens, because the element is already in the "DOM" , the css could pick it up, but the event listener could not? So i tried moving all scripts on top, rearranging stuff, nothing worked. Pre-loading all HTML into the index.html, without executing it will definitely work, but how can i achieve this exactly? My Configuration atm is:
index.html (root folder)
/components/main_menu.js
/components/character_creation.js
function MainMenu()
{/*
<div id="mm_wrapper_grid">
<div id="mm_subgrid1">
</div>
<div id="mm_subgrid2">
<div id="mm_subgrid2_image"></div>
<div id="mm_new_game"><p id="mm_new_game_p" class="grow">New Game<p></div>
<div id="mm_load_game"><p id="mm_load_game_p" class="grow">Load Game</p></div>
<div id="mm_options"><p id="mm_options_p" class="grow">Options</p></div>
<div id="mm_credits"><p id="mm_credits_p" class="grow">Credits</p></div>
</div>
</div>
*/}
function CharacterCreation()
{/*
<div> Character Creation test
</div>
*/}
<div id ="game">
<div id="loading_screen">Press Any Key To Continue</div>
</div>
<script type="text/javascript">
document.getElementById("loading_screen").addEventListener("click", function() {callback("game", MainMenu)});
document.getElementById("mm_new_game_p").addEventListener("click", function() {callback("game", CharacterCreation)});
function callback(arg1, func)
{
var html = func.toString();
var htmlstart = html.indexOf('/*');
var htmlend = html.lastIndexOf('*/');
var html = html.substr(htmlstart+2, htmlend-htmlstart-2);
document.getElementById(arg1).innerHTML = html;
}
</script>
You have the problem because you are trying to add the second listener for getElementById("mm_new_game_p") when this element doesn't exist on the page. I suggest you to add the follwing line of code to make sure, that it's true:
<script type="text/javascript">
document.getElementById("loading_screen").addEventListener("click", function() {callback("game", MainMenu)});
console.log('#mm_new_game_p', document.getElementById("mm_new_game_p"));
document.getElementById("mm_new_game_p").addEventListener("click", function() {callback("game", CharacterCreation)});
...
You have to add this listener after this element will be created (after calling of MainMenu() function).
To tell the truth, I can see such storing of html templates in js functions for the first time. It's hard to support your code and I've modified it a little bit below. This is not the best way to implement it, but my goal is show you a solution based on your code. What you can see here:
all the templates for pages are in html (not in JS);
you can add listeners from html code using HTML attribute onclick - and in this case you can be sure, that element exists on the page.
If you want to add listeners from JS, than you have to create own functions for each pages which you have and after HTML template of a page will be added to #game container you will need to create event listeners for the buttons which are on the created page.
openPage("game", "loading_screen");
function openPage(parentDOMElementId, name) {
console.log('openPage:', name);
var pageHtml = document.getElementById("page_" + name).outerHTML;
document.getElementById(parentDOMElementId).innerHTML = pageHtml;
}
<div id="game"></div>
<div class="templates" style="visibility: hidden;">
<div id="page_loading_screen" onclick="openPage('game', 'main_menu')">
Press Any Key To Continue
</div>
<div id="page_main_menu">
<div id="mm_subgrid1">
</div>
<div id="mm_subgrid2">
<div id="mm_subgrid2_image"></div>
<div id="mm_new_game">
<p id="mm_new_game_p" class="grow" onclick="openPage('game', 'character_creation')">New Game
<p>
</div>
<div id="mm_load_game">
<p id="mm_load_game_p" class="grow">Load Game</p>
</div>
<div id="mm_options">
<p id="mm_options_p" class="grow">Options</p>
</div>
<div id="mm_credits">
<p id="mm_credits_p" class="grow">Credits</p>
</div>
</div>
</div>
<div id="page_character_creation">
Character Creation test
</div>
</div>

Javascript modal that displays list that closes and returns to main html

Rather new to javascript, jquery and bootstrap, etc., so bear with me. I have a situation where I want to present a list of errors in a model dialog after the user hits a "validate" button. Got all the working - I am generating a list of objects that indicate to the user they need more work to the exact spot that needs additional data entry. I have the the DIV "id" that represents the field that needs more data (and each item will jump someplace different).I do not want a drop down list since there are be lots and lots of these items.
A few questions:
How do I go about jumping from the modal to the main html. I believe I have seen scrollIntoView mentioned in a few other posts as I was looking but will that hop to the DIV and also close the modal?
What construct should I use for the list? A list of scrolling button? The size of this can be quite large (hundreds) so it will need a scroll capability.
Finally, the app is "paged" with a next and prev buttons. I assume that will not be a problem from the aspect of jumping to a page not already displayed?
Here is the current modal code:
<script id="template-validation-error" type="text/x-handlebars-template">
<div id="validationErrorModal" class="modal">
<div class="message-container">
<div class="header">
Validation Errors
</div>
<div class="message">
The following fields are required:
</div>
<div class="center">
<input type="button" class="btn btn-solid-green btn-sm" onclick="fffdevice.validationErrorOk();" value="Done" />
</div>
</div>
</div>
</script>
and
showValidationError: function (fieldlist) {
settings.focusedField = $(':focus');
$("#validationErrorModal").detach();
$(".device-container").append(templates.validationerror({ fieldlist }));
$(".message-container input").focus();
},
validationErrorOk: function () {
$("#validationErrorModal").detach();
if (settings.focusedField) {
settings.focusedField.focus();
}
},
The field list is a list of objects that contain the id (field.id) of the DIV and also a description (field.fieldName) that I want to display.
Here is something I mocked up in paint...I am not sold on it but it show in a general sense what I am looking for:
I don't need a full solution rather, just want mechanisms I can use.
UPDATE
Just to help out anyone else in the future, using the info provided in the correct answer below I have a new code as follows:
<script id="template-validation-error" type="text/x-handlebars-template">
<div id="validationErrorModal" class="modal">
<div class="validation-container">
<div class="header" align="center">
Validation Errors
</div>
<div class="message">
<div class="scrolling-container" style="background-color: rgb(238, 238, 238); height:660px">
<div class="grid grid-pad">
{{#each fieldlist}}
<div class="row click-row" onclick="fffdevice.validationErrorFix('{{id}}');">
<div class="col-7-8 field-name">{{fieldName}}</div>
<div class="col-1-8">
<img class="pull-right" src="/mysite/Content/device/images/fix.png" style="width: 40px; position:relative; top: -5px;">
</div>
</div>
{{/each}}
</div>
</div>
</div>
<div><br/></div>
<div class="center">
<input type="button" class="btn btn-solid-green btn-sm" onclick="fffdevice.validationErrorOk();" value="Done" />
</div>
</div>
</div>
Then the Javascript for the onClick is:
validationErrorFix: function (id) {
$("#validationErrorModal").detach();
var x = document.getElementById(id);
x.scrollIntoView({
behavior: "smooth", // or "auto" or "instant"
block: "start" // or "end"
});
},
Which closes the dialog and jumps to the field. It looks like (I know this is ugly and I will clean it up later):
Bind the modal event to the validation code and show the modal if error(s) are found.
Display the modal with the list of errors using an html unordered list, inside the li element an anchor tag where the href attribute will have a value with the id that corresponds to the input field, all this done dynamically from your validation code.
Once an error in the list is clicked hide the modal using bootstrap $('#your-error-modal').modal('hide'); so the code would be something like this:
$('#your-error-modal').on('click', 'a.error-item', function(){
$('#your-error-modal').modal('hide');
});
I haven't tested this code, but if you're having issues with scrolling to the section of the input and closing the modal you can probably do something like this too:
$('#your-error-modal').on('click', 'a.error-item', function(e){ // use this method of onclick because your list will be created dynamically
e.preventDefault(); // prevent the default anchor tag action
var href = $(this).attr('href'); // grab the href value
$('#your-error-modal').modal('hide'); // close the modal first
scrollToDiv(href); // then take the user to the div with error with a nice smooth scroll animation
});
function scrollToDiv(location) {
$('html, body').animate({
scrollTop: $(location).offset().top
}, 2000);
}
Again this is untested code, but the idea is there.
For UX reasons you might also want to create a floating div or something where users can click on it and go back to the modal to continue reading your list of errors.

Display a loading animation until a <div> appears?

I'm running an asynchronous 3rd party script that loads an image gallery into my page, but unfortunately their code doesn't provide me with a callback after their image gallery has finished loading.
The modal starts off like this:
<div class="modal-body">
<div class="container-fluid" id="cincopa">
</div>
</div>
After the gallery is loaded, the modal looks like this:
<div class="modal-body">
<div class="container-fluid" id="cincopa">
<div id="ze_galleria">
//gallery stuff
</div>
</div>
</div>
So I need some way to display a loading animation until #ze_galleria appears. The loading animation function I can do myself, but is there something in jQuery that will listen for when a certain DOM element is created? Once the DOM element appears, it'll run the callback to remove the animation.
Based on how that script adds the gallery/gallery items you could use the DOMSubtreeModified event and then check if that particular item were added
document.addEventListener("DOMSubtreeModified", function(e) {
if (document.querySelector("#ze_galleria")) {
// exists
}
});
Here is a DOM tree event list, where you can check other possible events that might could be used.
https://developer.mozilla.org/en-US/docs/Web/Events
Update
Make sure you take a look at the MutationObserver as well, as it has very good browser support nowadays.
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Also, you can set an interval:
var cincopa = $('#cincopa');
var counter = 0;
var intervalCode = setInterval(function(){
if (cincopa.find('#ze_galleria').length){
clearInterval(intervalCode);
yourCallback();
}
counter++;
console.log(counter + ' seconds past till the event loaded.');
}, 1000);
I think the code is intuitive, but if there is any doubt, just ask :)
Presuming that your "3rd party library" is going to totally overwrite the contents of what ever you point it at (as your example code suggests it does). You can solve your problem simply by adding an img:
<div class="modal-body">
<div class="container-fluid" id="cincopa">
<img src="loading.gif"/>
</div>
</div>
When the library has done what it needs to do it will overwrite the contents of the div <div class="container-fluid" id="cincopa"> resulting in:
<div class="modal-body">
<div class="container-fluid" id="cincopa">
<div id="ze_galleria">
//gallery stuff
</div>
</div>
</div>
thus removing your loading image.

Displaying JavaScript Hidden Elements in Other Location on Page

Update: I have changed my JavaScript code, and I am now receiving errors in my iPhone Debug Console.
Disclaimer: I'm new to web development, and I'm not too good with JavaScript.
Scenario: I'm building an event calendar with CodeIgniter, and I'm hiding elements on mobile devices that need to be displayed elsewhere on the page when an event occurs. The elements being hidden are <ul>s, and they need to be displayed on another portion of the page when their cooresponding <span>s with the class .day_listing_mobile are selected. I've been working with different methods, but I haven't been able to find a solution out for hours as I'm not strong in the realm of jQuery/Ajax/JavaScript.
Question: What methods would be required to make the hidden <ul>s be displayed on a different portion of the page when their corresponding <span>s are selected?
JavaScript (Updated):
(function($) {
var isMobile = (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()));
if (isMobile) {
$('.event_list').hide(); // setting display:none; on all .event_list <ul> elements
// attach click event to the <span class="day_listing"> elements
$('.day_listing_mobile').click(function() {
var eventList = $(this).sibling('.event_list').clone();
$(this).sibling('.event_list').remove();
$('#mobile_show_content').append(eventList);
});
}
})(jQuery);
I'm Receiving this error on this line of code var $eventList = $(this).sibling('.event_list').clone(); :
CodeIgniter Calendar Template (Controller):
{cal_cell_content}
<span class="day_listing_mobile">
{day}
</span>
<ul class="event_list">
{content}
</ul>
{/cal_cell_content}
{cal_cell_content_today}
<span class="day_listing_mobile" id="today_listing">
{day}
</span>
<ul class="event_list">
{content}
</ul>
{/cal_cell_content_today}
View:
<div class="row">
<div class="twelve columns">
<?php echo $calendar; ?>
</div>
</div>
<div class="show-on-phones">
<div class="row">
<div class="twelve columns" id="mobile_show_content">
<!--I want the <ul>s to show up here-->
</div>
</div>
</div>
Note that the CodeIgniter calendar class generates above where I want to display the <ul>s.
Just modify your click event to move the data around the dom.
$('.day_listing_mobile').click(function() {
var eventList = $(this).sibling('.event_list').clone();
$(this).sibling('.event_list').remove();
$('.mobile_show_content').append(eventList);
});
You can remove the node from the DOM and re-append it in a different place. (.remove() and .append())
But, rather than trying to solve this in javascript, why not design your page with adaptability in mind using css selectors to reflow the page at certain view port widths.
Check this out:
http://www.alistapart.com/articles/responsive-web-design/

Replace URL parameter values in links using JavaScript/jQuery?

My CMS's lightbox-style photo gallery outputs code like below. I've provided code for two thumbnails.
The parameter values for "m" and "s" will always be "150" and "true." I'd like to change that to m=250 and s=false.
I'm new to JavaScript and jQuery. If you have a suggestion, please help me out with where to put the code on the page. Thank you.
<div class="thumbTight MainContent">
<div class="thumbContents">
<a href="/PhotoGallery/banana.jpg" rel="lightbox[2065379]" title="Banana">
<img src="/ResizeImage.aspx?img=/PhotoGallery/banana.jpg&m=150&s=true" alt="Banana" />
</a>
<div class="description" style="display: none;"></div>
</div>
</div>
<div class="thumbTight">
<div class="thumbContents">
<a href="/PhotoGallery/cantaloupe.jpg" rel="lightbox[2065379]" title="Cantaloupe">
<img src="/ResizeImage.aspx?img=/PhotoGallery/cantaloupe.jpg&m=150&s=true" alt="Cantaloupe" />
</a>
<div class="description" style="display: none;"></div>
</div>
</div>
In your document ready handler, use each to iterate over the thumbnails (images inside divs with the thumbContents class) and assign the src attribute to the original src attribute with the required substitutions.
$(function() {
$('.thumbContents img').each( function() {
var $img = $(this);
$img.attr('src', $img.attr('src').replace(/m=150/,'m=250').replace(/s=true/,'s=false') );
});
});
You can run this jQuery after the page has loaded. The images will start loading with the different URL, your code will run and change the image URLs and then the new one will load and display. There is nothing you can do client-side to prevent the initial display unless you actually use CSS such that they images are initially hidden and only made visible AFTER you've set the desired URL.
$(".thumbTight img").each(function() {
this.src = this.src.replace(/m=150/, "m=250").replace(/s=true/, "s=false");
});
You can see a demo here: http://jsfiddle.net/jfriend00/UdnFE/.

Categories

Resources