HTML / JS Simplification - javascript

I'm having a hell of a time working on a dropdown menu for a client. I think my code is way too complex for what it is. I need a resolution/alternative way to perform the given objective.
<font id="l1b" size="4" color="black" style="cursor:pointer; color:black;"
onclick="showSubMenu('cat2');
document.getElementById('cat1').style.display = 'none';
document.getElementById('cat3').style.display = 'none';
document.getElementById('cat4').style.display = 'none';
document.getElementById('pa1').style.display = 'none';
document.getElementById('pb1').style.display = 'none';
document.getElementById('pc1').style.display = 'none';
document.getElementById('pd1').style.display = 'none';
document.getElementById('pa2').style.display = 'none';
document.getElementById('pb2').style.display = 'none';
document.getElementById('pc2').style.display = 'none';
document.getElementById('pd2').style.display = 'none';
document.getElementById('da2a').style.display = 'none';
document.getElementById('da2b').style.display = 'none';
document.getElementById('da2c').style.display = 'none';
document.getElementById('da2d').style.display = 'none';
document.getElementById('da2e').style.display = 'none';
document.getElementById('da2f').style.display = 'none';
document.getElementById('da2g').style.display = 'none';
document.getElementById('da2h').style.display = 'none';">Tea Bags<img src="arrow.png" style="position:relative; left:8px; top:3px;"></font>
Here's a pic of the concept: http://robstest.mydnd.com/helppic.php
First person to help gets 10 brownie points! :D

To illustrate the benefits of using a library such as jQuery to make your life easier:
Pure JavaScript
var elementList = ['cat1', 'cat2', 'cat3', 'cat4', 'pa1', ... , 'da2h'];
function showSubMenu(el) {
for (var i = 0; i < elementList.length; i++) {
if (elementList[i] != el) {
document.getElementById(elementList[i]).style.display = 'none';
}
}
}
jQuery
var elementList = ['cat1', 'cat2', 'cat3', 'cat4', 'pa1', ... , 'da2h'];
function showSubMenu(el) {
$.each(elementList, function() {
if (this != el) {
$('#' + this).css({display: "none"});
}
}
}
This tutorial might also be helpful: http://www.html-5-tutorial.com/

Here is a link to a JQuery dropdown tutorial that does something similar to what you want:
http://css-tricks.com/simple-jquery-dropdowns/
... you can also download the files and modify them to your needs.
It would be a good exercise for you to play around with and learn while you are making your project.
(Plus you may want to look at some other implementations of dropdowns to get an idea of best practices - the UI you have mocked up looks a little confusing for an end user)

Get the child elements and loop through them, setting the display for each. Stuff this into a function such as yourfunction(parentDiv), and apply to the on-click event after a semi-colon.
I would type up this code, but right now I don't have enough material to work with.

Use jQuery to do something like this:
$(function() {
$("#l1b").children().each(function() {
$(this).hide();
});
});

Related

How can I simplify my js code for css animation?

I made CSS animations and buttons to play the animations and use add and remove classes to play each motion. I didn't use a toggle because if I use a toggle, it mixes with other buttons.
I've seen many CSS animations that didn't use js at all.
Is there any way to reduce my js code and simplify it?
Here is the code-
playbtn.addEventListener("click", function (e) {
e.preventDefault;
ball.style.display = "block";
bowl.style.display = "none";
ball.classList.remove("ball-move");
ball.offsetWidth = ball.offsetWidth;
ball.classList.add("ball-move");
document.getElementById('dFace').className = '';
dFace.offsetWidth = dFace.offsetWidth;
dFace.classList.add("p-head-move");
document.getElementById('ear').className = '';
ear.offsetWidth = ear.offsetWidth;
ear.classList.add("lean");
document.getElementById("mouthid").className = '';
mouth.offsetWidth = mouth.offsetWidth;
mouth.classList.add("mouth-move");
}, false);
I think you have to read about Animation play state api, that will reduce your code.
Doc Link!
1, From your code, I assume that bowl, ball, dFace, ear and mouth are all HTMElement that have already assigned with a value from document.getElementById. So, you may not have to get the HTMLElement again in this functions.
2, You may not need to assign the value for offsetWidth as it is a read-only property as described in https://www.w3schools.com/jsref/prop_element_offsetwidth.asp. You can remove those lines.
You might be missing () for e.preventDefault
I will suggest the followings:
playbtn.addEventListener("click", function (e) {
e.preventDefault();
ball.style.display = "block";
bowl.style.display = "none";
ball.classList.remove("ball-move");
ball.classList.add("ball-move");
dFace.className = '';
dFace.classList.add("p-head-move");
ear.className = '';
ear.classList.add("lean");
mouth.className = '';
mouth.classList.add("mouth-move");
}, false);
Also, the action on dFace, ear and mouth are similar, so you may wrap it in a function call restartAnimation to further reduce duplications of your code.
const restartAnimation = (ele, className) => {
ele.className = '';
ele.classList.add(className);
}
playbtn.addEventListener("click", function (e) {
e.preventDefault();
ball.style.display = "block";
bowl.style.display = "none";
ball.classList.remove("ball-move");
ball.classList.add("ball-move");
restartAnimation(dFace, "p-head-move")
restartAnimation(ear, "lean")
restartAnimation(mouth, "mouth-move")
}, false);
You should include your CSS in your post as well! But I think you could avoid the restartAnimation instances you have by using animation-iteration-count: infinite; (if you are trying to make your animations loop, for example) in the CSS selector for the animated parts. I would recommend looking into the CSS animation documentation here as it's very clear! Good luck!

Hide or show elements when user change buttons

I'm just going to create a function that allows me to hide some elements (filters on my website), while the other element ( All Categories) is selected. I'm using Sharetribe - marketplace CMS, here's mine https://rentim.sharetribe.com/
Here's piece of code I wrote to make it happen, but it's not working
document.querySelectorAll('a.home-categories-main:first-child.selected'),
function hideFilters() {
document.getElementById('filters').style.display = 'none';
};
Here is a working example on JSFiddle.
This is a simple example to what you are trying to do using the most basic HTML and JS combination.
Nothing fancy, but it works.
HTML:
<div id="first" onclick="hideFilters();">All</div>
<div id="filters">
<div>Price</div>
<div>Model</div>
<div>Date</div>
<div>Color</div>
</div>
Javascript:
var a = true;
function hideFilters(){
let x = document.getElementById("filters");
if(a){
x.style.display = "none";
}else{
x.style.display = "block";
}
a = !a;
}
Here is a working example on JSFiddle.
In Rentim you should add custom scripts with onDocumentReady function. It's executed after HTML is parsed and all elements rendered.
onDocumentReady(function() {
var filters = document.querySelector('#filters');
var allCategories = document.querySelector('.home-categories-main:first-child.selected');
filters.style.display = allCategories ? 'block' : 'none';
});

How can I optimize this snippet?

Being only able to glue pieces together to get some JS working, I came up with the following code.
if (document.getElementById("component_projector_askforproduct")){
document.getElementById("component_projector_askforproduct").style.display = "none";
}
if (document.getElementById("askforproduct_58676")){
document.getElementById("askforproduct_58676").className = "";
}
if (document.getElementById("longdescription_58676")){
document.getElementById("longdescription_58676").className = "";
}
if (document.getElementById("opinions_58676")){
document.getElementById("opinions_58676").className = "activTab";
}
if (document.getElementById("component_projector_opinions")){
document.getElementById("component_projector_opinions").style.display = "block";
}
if (document.getElementById("component_projector_opinions_add")){
document.getElementById("component_projector_opinions_add").style.display = "block";
}
It works, but I know it's a mess. How could I optimize and slim this code down?
What I would do is:
use object to store all your changes like:
var objChecks = {
component_projector_askforproduct: "some_display_none_className",
askforproduct_58676: "",
longdescription_58676: ""
}
then create function to process it (pass objChecks to it):
function processChecks(checks) {
Object.getOwnPropertyNames(objChecks).map(function(check){
var el = document.getElementById(check);
if (el) el.className=objChecks[check];
})
}
change your HTML a bit. I noticed sometimes you change className and sometimes style.display. I'd make a new class that hides an element (same as display=none) which makes everything much neater.
EDIT I removed my last answer, and got an idea from Mirko Vukušićs answer.
if you create css classes for hiding and showing elements you could do it like this.
css
.hide { display: none!important; }
.show { display: block!important; }
javascript
var arr = [
["component_projector_askforproduct", "hide"],
["askforproduct_58676", ""],
["longdescription_58676", ""],
["opinions_58676", "activTab"],
["component_projector_opinions", "show"],
["component_projector_opinions_add", "show"]
]
for (i = 0; i < arr.length -1; i++) {
var elm = document.getElementById(arr[i][0]);
if(elm) {
elm.className = arr[i][1];
}
}
use ternary conditions for code beautification.
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator
or use switch conditions.
suggestion : If i am in this scenario i would make specific function to perform this task and use ternary condition for code beautification.
To avoid constant checking, and avoid errors, you can do this neat trick, to set default values:
function $(elem) {
return document.getElementById(elem) || document.createElement("div");
}
So, this way, if element doesn't exist, it will be created, but not appended to body!
Test:
function $(elem) {
return document.getElementById(elem) || document.createElement("div");
}
$("component_projector_askforproduct").style.display = "none";
$("askforproduct_58676").className='';
$('longdescription_58676').className="";
$('opinions_58676').className="activeTab";
$("component_projector_opinions").style.display = "block";
//etc, etc....
.activeTab {
background:red;
color:white;
}
<div id="component_projector_askforproduct">
6666666666666
</div>
<div id="opinions_58676">
qqqqqqqqqqqqqq
</div>
<div id="component_projector_opinions7">
11111111111111
</div>
After analyse question code I understand it is some kind of menu or tabs with possibility to activate,deactivate, show, hide elements. I created structure for this purposes with builded in methods. It can be used on many elements, it can be use on one element many times, it has also chain methods so it is possible to run many methods in one code line.
Check code of this structure and examples, if there is some questions or something is not clear then ask. I am not using ES6 or jQuery because this question is not about that.
var ME = function(){
//structure represent single menu element
var MenuElement = function(id){
this.el = document.getElementById(id);
};
MenuElement.prototype.hide = function(){
if (this.el)
this.el.style.display = "none";
return this;
};
MenuElement.prototype.show = function(){
if (this.el)
this.el.style.display = "block";
return this;
};
MenuElement.prototype.active = function(){
if (this.el)
this.el.className = "activeTab";
return this;
};
MenuElement.prototype.deActive = function(){
if (this.el)
this.el.className = "";
return this;
};
//return only obj with create method to use it without new keyword
return {
create: function(id){
return new MenuElement(id);
}
};
}();
//USE EXAMPLE - the same like in question snippet
ME.create("component_projector_askforproduct").hide();
ME.create("askforproduct_58676").deActive();
ME.create("longdescription_58676").deActive();
ME.create("opinions_58676").active();
ME.create("component_projector_opinions").show();
ME.create("component_projector_opinions_add").show();
//USE EXAMPLE MANY TIMES ON ONE ELEMENT - ONLY EXAMPLE PURPOSES
var element = ME.create("component_projector_askforproduct");
var toggle = true;
setInterval(function(){
if (toggle)
element.show().active(); //chaining example
else
element.deActive().hide();
toggle = !toggle;
},1000);
div.activeTab {
font-weight: bold;
color: red;
}
<div id="component_projector_askforproduct">
component_projector_askforproduct
</div>
<div id="askforproduct_58676">
askforproduct_58676
</div>
<div id="longdescription_58676">
longdescription_58676
</div>
<div id="opinions_58676">
opinions_58676
</div>
<div id="component_projector_opinions">
component_projector_opinions
</div>
<div id="component_projector_opinions_add">
component_projector_opinions_add
</div>
Do not call getElementById twice for the same ID. Store return value in a variable, and check that before trying to manipulate it.

javascript using a loop to change the display of every element that has a specific class

Yesterday I asked a question about improving efficiency in my code. Today I have another question in the same spirit of trying to write less lines of code to accomplish repetitive tasks.
I have the following code:
function myIntroductionText() {
introPos.style.display = 'block';
posOne.style.display = 'none';
posTwo.style.display = 'none';
posThree.style.display = 'none';
posFour.style.display = 'none';
posFive.style.display = 'none';
posSix.style.display = 'none';
posSeven.style.display = 'none';
posEight.style.display = 'none';
posNine.style.display = 'none';
posTen.style.display = 'none';
posEleven.style.display = 'none';
backButton.style.visibility = 'hidden';
}
function myPositionOne() {
introPos.style.display = 'none';
posOne.style.display = 'block';
posTwo.style.display = 'none';
posThree.style.display = 'none';
posFour.style.display = 'none';
posFive.style.display = 'none';
posSix.style.display = 'none';
posSeven.style.display = 'none';
posEight.style.display = 'none';
posNine.style.display = 'none';
posTen.style.display = 'none';
posEleven.style.display = 'none';
backButton.style.visibility = 'visible';
}
function myPositionTwo() {
introPos.style.display = 'none';
posOne.style.display = 'none';
posTwo.style.display = 'block';
posThree.style.display = 'none';
posFour.style.display = 'none';
posFive.style.display = 'none';
posSix.style.display = 'none';
posSeven.style.display = 'none';
posEight.style.display = 'none';
posNine.style.display = 'none';
posTen.style.display = 'none';
posEleven.style.display = 'none';
}
The HTML looks something like this:
<p class="textContent" id="introductionText">Introduction Text Goes Here</p>
<p class="textContent" id="position1">content1</p>
<p class="textContent" id="position2">content2</p>
<p class="textContent" id="position3">content3</p>
Each position (i.e. introPos, posOne, posTwo) also has a corresponding function that looks essentially the same as the function above, except it changes the display based on which position it is in.
I'm thinking that I could use a loop and/or an if/else statement to make this task more efficient. I tried by using getElementsByClassName('textContent'), which (I think) produced an array containing all of the elements with that class. According to the console.log is contains [p#introductionText.textContent, p#position1.textContent, so on and so on...]. So, I wrote the following code to try to loop through it:
var blanks = document.getElementsByClassName("textContent") // this creates the array that I mentioned
for (item in blanks) {
if (blanks[0] === introductionText.textContent) {
blanks[0].style.display = 'block';
} else {
blanks[item].style.display = 'block';
}
}
I tried using p#introductionText.textContent but that returned an error. I'm very new to JavaScript so I fully recognize that I could be doing something very silly here, but any help would be appreciated.
EDIT:
The error message says Uncaught SyntaxError: Unexpected tocken ILLEGAL
I should also add that my goal is to have only one position be visible at each time. I have a "Back" and "Next" button that allows users to go from posOne to posTwo, to posThree, and so on. So, in addition to making posTwo visible, I also need to make posOne and/or posThree not visible.
Thanks!
The first thing is moving all those Javascript style expressions to CSS:
#introPos,
#posOne,
#posTwo,
#posThree,
#posFour,
#posFive,
#posSix,
#posSeven,
#posEight,
#posNine,
#posTen,
#posEleven {
display: none;
}
Or even shorter
#introductionText>.textContent {
display: none;
}
This would enable you to shorten each function considerably:
function myPositionOne() {
posOne.style.display = 'block';
backButton.style.visibility = 'visible';
}
Instead of setting each style via JS again and again, you'd simply set those that change.
The next step would be to rewrite all those functions into one that accepts a parameter which element you are targeting:
function myPosition(pos) {
var parent = document.getElementById("text-container");
var children = parent.getElementsByClassName("textContent");
var element;
// first hide all <p class="textContent"> children
for (var i = 0; i < children.length; i++) {
children[i].style.display = 'none';
if (i == pos) {
element = children[i];
}
}
// then show the right one
if (element) {
element.style.display = 'block';
}
// show or hide the back button depending on which child we are dealing with
if (pos > 0) {
document.getElementById("backButton").style.visibility = 'visible';
} else {
document.getElementById("backButton").style.visibility = 'hidden';
}
if (pos >= children.length-1) {
document.getElementById("nextButton").style.visibility = 'hidden';
} else {
document.getElementById("nextButton").style.visibility = 'visible';
}
}
This sets only the child number #pos visible and adjusts the visibility of the back button (assuming the back button has the ID "backButton").
Maybe this:
All paragraphs also have the class "textContent". Make this display none and display the correct paragraph via given paragraph-id:
function myFunction(classDisplay) {
var elems = document.getElementsByClassName('textContent');
for (var i=0;i<elems.length;i+=1){
elems[i].style.display = 'none';
}
document.getElementById(classDisplay).style.display = "block";
}
The following will hide all but position 2:
myFunction("position2");
I don't know about the back-button, this is always be visible?
EDIT: I've tested this and corrected the code.
If you use JQuery, you can also use the following instead of the for loop:
$('.textContent').css('display'​​​​​​​​​​​​​​​​​​​​​​​​​​​,'none');​​​​​​
In newer versions of JavaScript you can use:
Array.from(document.getElementsByClassName('myclass')).forEach((item) => {
item.style.backgroundColor = "blue";
})

How can I show/hide div using Java Script on click of button

I am trying to write a PHP Java Script, but struggling to write in this section of coding.
I am trying to make a buttom in form in that opens
The code I have written so far is
function display(e){
if (e.clicked)
document.getElementById('2').style.display = 'none';
else
document.getElementById('2').style.display = 'block';
and the FORM CODE is;
<input type="button" value=" Book Now " onClick="display(this)"/></input>
any help to point out my clear mistakes would be great, the live code can be seen at
http://affordablecleaners.co.uk/quote/
Thanks,
Henry
Try something similar to the following
var i = 0;
var display = function() {
document.getElementById('2').style.display = (i++ % 2) ? "none" : "block";
};
Essentially, we're creating a variable i and increasing it by one every time the function is called. If, when the function is called, i is an even number, then we set it to display: block. Otherwise, set it to display: none.
The biggest downside to this solution is cluttering the global scope. If this is an issue, you can also do the following.
var display = function() {
document.getElementById('2').style.display = (document.getElementById('2').style.display == "none") ? "block" : "none";
};
Here's the (untested) logic...
function display(state, which){
if (state==1) {document.getElementById(which).style.display ='none';}
else
{document.getElementById(which).style.display = 'block';}
}
and then in your button...
to turn ON
onclick="display('1',someDIV)"
to turn OFF
onclick="display('0',someDIV)"

Categories

Resources