Dirty HTML or dirty jQuery for passing variables? - javascript

I have to pass variables to jQuery. There are two different approach as I see:
clean HTML, dirty jQuery:
<div class="itemContainer" data-id="1">
Item information
<input type="button" class="rename">
<input type="button" class="delete">
</div>
$('.rename').click(function() {
var id = $(this).parent().attr('data-id');
});
$('.delete').click(function() {
var id = $(this).parent().attr('data-id');
});
PROs:
clean, not redundant HTML,
CONS:
not so clean jQuery,
if the DOM structure changes, its hard to detect the errors, and it has to be fixed at 2 places
clean jQuery, dirty HTML:
<div class="itemContainer">
Item information
<input type="button" class="rename" data-id="1">
<input type="button" class="delete" data-id="1">
</div>
$('.rename').click(function() {
var id = $(this).attr('data-id');
});
$('.delete').click(function() {
var id = $(this).attr('data-id');
});
PROs:
clean jQuery,
works even DOM structure changes
CONS:
not so clean, redundant HTML,
which one would you prefer to use?

Your first HTML structure is the better implementation as it avoids repetition of the same data-id attribute.
With regard to the jQuery, you can use a single event handler by separating the selectors with a comma (,), and you can use closest() to find the required parent element. This is more robust as you can then change the HTML structure within that parent however you require and it will not break the JS logic, so long as the clicked element is still a child node. Finally, note that you should use data() to get/set data attributes where possible, not attr(). Try this:
$('.rename, .delete').click(function() {
var id = $(this).closest('.itemContainer').data('id');
console.log(id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="itemContainer" data-id="1"> Item information
<input type="button" class="rename" value="Rename" />
<input type="button" class="delete" value="Delete" />
</div>
<div class="itemContainer" data-id="99"> Item information
<p>
Extra information...
<div class="another-child">
<input type="button" class="rename" value="Rename" />
<input type="button" class="delete" value="Delete" />
</div>
</p>
</div>

Put the selectors you want to add the listener to together in the selector string you use to add a .click listener to (separated by commas), and you don't need to repeat yourself at all:
$('.rename, .delete').click(function() {
var id = $(this).parent().attr('data-id');
console.log(id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="itemContainer" data-id="1">
Item information
<input type="button" class="rename">
<input type="button" class="delete">
</div>
<div class="itemContainer" data-id="2">
Item information
<input type="button" class="rename">
<input type="button" class="delete">
</div>

You can combine the click event for both the element using Multiple Selector. You can specify any number of selectors to combine into a single result. This multiple expression combinator is an efficient way to select disparate elements.
clean jQuery, Clean HTML:
$('.rename, .delete').click(function() {
var id = $(this).parent().attr('data-id');
console.log(id);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="itemContainer" data-id="1">
Item information
<input type="button" class="rename">
<input type="button" class="delete">
</div>

I would use event delegation and a single data-attribute. You don't need jQuery for it. Added a button for restructuring the DOM to demonstrate that the handler keeps working after it.
(() => {
const evtHandler = evt => {
const origin = evt.target;
console.clear();
if (origin.id === "redoDOM") { return restructure(); }
if (origin.parentNode.classList.contains("itemContainer")) {
console.log(`${origin.classList} data-id: ${origin.parentNode.dataset.id}`);
}
};
document.addEventListener("click", evtHandler);
function restructure() {
if (!document.querySelector("#BttnContainer")) {
let container = document.createElement("div");
container.id = "BttnContainer";
container.innerHTML = `
<p>
div.itemContainer elements are wrapped.
Check if the button handler still works
</p>`;
Array.from(document.querySelectorAll(".itemContainer"))
.forEach(v => container.appendChild(v));
document.body.insertBefore(container, document.body.firstChild);
} else {
console.log("Already wrapped");
}
}
})();
#BttnContainer {
color: green;
}
<p>Click buttons to show data-id value of the surrounding element</p>
<div class="itemContainer" data-id="1">
Item information (1)
<button class="rename">rename</button>
<button class="delete">delete</button>
</div>
<div class="itemContainer" data-id="2">
Item information (2)
<button class="rename">rename</button>
<button class="delete">delete</button>
</div>
<p>
Click to wrap buttons in a new element
<button id="redoDOM">Restructure</button>
</p>

Related

Is there a way to make every bouton using a single code

For a school project, I'm coding a porfolio.
I want to use jQuery hide() and show() to have popups that appear after clicking on buttons.
Is there a way, with a single code, to make every HTML element with the class="vignette" and an id="bouton1" show a div with the same number in id (id=popup1).
I don't know if I'm clear, I'm a student in graphic design, and I'm not having a good time.
As far as I can understand from your question, you want to show a modal whose ID is the same number as the button's ID?
You can use this same logic to work with your modal instead
// This regex just gets the number part from the ID
const re = /bouton(\d+)/
$('button.vignette').click(e => {
const res = re.exec(e.target.id)
if(res) {
// "popup" + res[1] gives the popup id
$('#content').html("popup" + res[1])
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class = "vignette" id = "bouton1">B1</button>
<button class = "vignette" id = "bouton2">B1</button>
<button class = "vignette" id = "bouton3">B1</button>
<button class = "vignette" id = "bouton4">B1</button>
<div id = "content"></div>
You can create a function that will be added via addEventListener. Alternatively you can add an onclick attribute to the HTML elements whose click you want to handle.
let activeDiv;
function myClick() {
if (activeDiv) activeDiv.classList.add("invisible");
(activeDiv = document.getElementById(this.id.replace("bouton", "popup"))).classList.remove("invisible");
}
let buttons = document.getElementsByClassName("vignette");
for (let button of buttons) {
button.addEventListener("click", myClick);
}
.invisible {
display: none;
}
<input type="button" id="bouton1" class="vignette" value="First">
<input type="button" id="bouton2" class="vignette" value="Second">
<input type="button" id="bouton3" class="vignette" value="Third">
<input type="button" id="bouton4" class="vignette" value="Fourth">
<input type="button" id="bouton5" class="vignette" value="Fifth">
<input type="button" id="bouton6" class="vignette" value="Sixth">
<input type="button" id="bouton7" class="vignette" value="Seventh">
<input type="button" id="bouton8" class="vignette" value="Eigth">
<input type="button" id="bouton9" class="vignette" value="Ninth">
<div id="popup1" class="invisible">1</div>
<div id="popup2" class="invisible">2</div>
<div id="popup3" class="invisible">3</div>
<div id="popup4" class="invisible">4</div>
<div id="popup5" class="invisible">5</div>
<div id="popup6" class="invisible">6</div>
<div id="popup7" class="invisible">7</div>
<div id="popup8" class="invisible">8</div>
<div id="popup9" class="invisible">9</div>
suppose you have 10 buttons with class vignette then you code would be:
$.each( "button.vignette", function( i, obj) {
$(obj).attr( "id", i ).on('click',function(){
$('#popup'+i).toggle();
});
});
You can replace toggle() function with your code as desired.

JavaScript More Efficient code to hide all element expect cloest

I have about 20 Forms. When A button the closes form should unhide.
And all the other forms should remain hidden. '
This is the way i was doing it
$(document).ready(function() {
console.log( "ready!" );
$(".toggle-new-form1").click(function() {
$(".new-form1").toggleClass("hidden");
// $("input[name='union_name']").focus();
});
$(".toggle-new-form2").click(function() {
$(".new-form2").toggleClass("hidden");
// $("input[name='union_name']").focus();
});
});
This is sample of html
<div class="form-group" style="">
<label >Email:</label>
<button type="button" id="new" style="margin-top:7px;" class="toggle-new-form pull-right btn btn-primary">Edit</button>
<p> example#gmail.com </p>
</div>
<form id="name-form" class="new-form1 hidden" method="POST" action="">
<input id="email">
<button type="submit"> Submit </button>
</form>
But i am having trouble hiding previously activated forms.
Is there anyway to make this more efficient and hide previously activated forms.
I have tryed this as well
<script type="text/javascript">
$(document).ready(function() {
console.log( "ready!" );
$(".toggle-new-form").click(function() {
$(".new-form").addClass("hidden");
$(this).closest( ".new-form" ).removeClass( "hidden" )
});
});
</script>
I dont know how its working
Js fiddle https://jsfiddle.net/0p2brLww/2/
You can try something like this a single click event for all the buttons+forms
$(document).ready(function() {
$('[class^="toggle-new-form"]').click(function() {
var el = $(this).parent().next();
$('[class^="new-form"]').not(el).addClass('hidden');
el.toggleClass("hidden");
//$(this).parent().next().find("input[name='union_name']").focus();
});
});
This should work...
$(document).ready(function() {
$('button').click(function(e) {
var targetForm = e.target.dataset.buttonFor
$('form').addClass('hidden')
$("."+targetForm).toggleClass('hidden')
})
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<label >Name:</label>
<button type="button" data-button-for="first-name" style="margin-top:7px;" class="toggle-new-form pull-right btn btn-primary">Edit</button>
<p> Example first Name </p>
<form id="name-form" class="new-form first-name hidden" method="POST" enctype="multipart/form-data" action="">
<input>
</form>
<hr>
<div class="form-group" style="">
<label >Shipping & Addresses:</label>
<button type="button" data-button-for="shipping-address" style="margin-top:7px;" class="toggle-new-form pull-right btn btn-primary">Edit</button>
<p> Example Last Name </p>
</div>
<form id="name-form" class="new-form shipping-address hidden" method="POST" enctype="multipart/form-data" action="">
<input>
</form>
<hr>
Adding to answer given by #madalin vascu, I would like to suggest that you should be using event delegation in this case.
Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.
Wrap all the forms in a div and call function like this:
$('.divclass').on('click','[class^= "toggle-new-form"]',function() {});
Check Out the jsfiddle:
Here is the fiddle

Manipulate button properties from a template in a JS node

I have an HTML template consisting of a DIV that contains three buttons.
<template ID="template3buttons">
<div ID="container3buttons" class="boxes">
<div ID= "sunShadeUp" class="boxes">
<input type="button"
id="SunshadeButtonUp"
class="SunshadeSmallButton"
onclick="GenericAction('ENO_ShutterStop($all)', 'all')"
value=""/>
</div>
<div ID= "sunShadeStop" class="boxes">
<input type="button"
id="SunshadeButtonStop"
class="SunshadeSmallButton"
onclick="GenericAction('ENO_ShutterStop($all)', 'all')"
value=""/>
</div>
<div ID= "sunShadeDown" class="boxes">
<input type="button"
id="SunshadeButtonDown"
class="SunshadeSmallButton"
onclick="GenericAction('ENO_ShutterStop($all)', 'all')"
value=""/>
</div>
</div>
</template>
I use JS to generate many copies of the template, which are eventually inserted into appropriate DIVs.
function create3Button(cellButtonId) //create boxes with 3 buttons each
{
var template3buttons = document.querySelector('#template3buttons');
var insertionPoint= document.getElementById(cellButtonId);
var clone = document.importNode(template3buttons.content, true);
insertionPoint.appendChild(clone);
}
Now, i need to manipulate the content of the 'onclick' tag for each copy of the template depending on the insertion point. I understand that getElementById() does not work for DOM nodes. What are the alternatives?
If you use jQuery you can do this:
$("[id*=sunShade]").children().click(function() {
alert( "Handler for .click() called." );
});

Get Checkbox to toggle div based on only the string inside a checkbox's label - jQuery

I'm trying to create a script to hide divs based on just the label of a "checked" checkbox. And do it without having to use a specific value, id or attribute. I was previously shown how to do it using spans/divs, but checkboxes have got me stumped.
My example in jsfiddle:
http://jsfiddle.net/6qLX7/2/
HTML:
<fieldset class="filter-row">
<div class="row-section">
<div class="row-heading">art</div>
<ul>
<li>
<div class="checkbox">
<input type="checkbox" name="studio art" value=".studio_art" id="studio_art" />
<label for="studio_art">studio art</label>
</div>
</li>
<li>
<div class="checkbox">
<input type="checkbox" name="ceramics" value=".ceramics" id="ceramics" />
<label for="ceramics">ceramics</label>
</div>
</li>
</ul>
</div>
</fieldset>
<fieldset class="filter-row">
<div class="row-section">
<div class="row-heading">studio art</div>
<ul>
<li>
<div class="checkbox">
<input type="button" value=".option1" name="option1" id="option1" />
</div>
</li>
<li>
<div class="checkbox">
<input type="button" value=".option2" name="option2" id="option2" />
</div>
</li>
</ul>
</div>
<div class="row-section ">
<div class="row-heading">ceramics</div>
<ul>
<li>
<div class="checkbox">
<input type="button" value=".option1" name="option1" id="option1" />
</div>
</li>
<li>
<div class="checkbox">
<input type="button" value=".option2" name="option2" id="option2" />
</div>
</li>
</ul>
</div>
</fieldset>
JS:
$(document).ready(function () {
$("input:checked").click(function () {
var clickedText = $(this).text();
$(".row-section").filter(function () {
return $(this).find("div").text() === clickedText;
}).toggle();
});
});
Forked fiddle: http://jsfiddle.net/ru8YL/1/
I've created a new selector to get the label text that accords with the checkbox: $(this).siblings('label').text().
Select all checkboxes instead of the buttons you previously used: $("input:checkbox").
Use the change event rather than click.
Use .is(':checked') to see if the checkbox is checked or not.
Send toggle a parameter to tell it to hide or show. This second parameter is specified in the documentation: http://api.jquery.com/toggle/
$("input:checkbox").change(function () {
var clickedText = $(this).siblings('label').text();
console.log(clickedText);
$(".row-section").filter(function () {
return $(this).find("div.row-heading").text() === clickedText;
}).toggle(this.checked);
});
$(document).ready(function () {
$("input").change(function () {
var isChecked = $(this).is(":checked");
});
});
use change event instead of click event
Here's my contribution. It just shows there's a large number of ways you can express the same thing using jQuery.
$(document).ready(function () {
$("input:checkbox").click(function () {
var clickedText = $(this).next('label').text();
$("fieldset:nth-child(2) .row-section").filter(function () {
return $('.row-heading', this).text() === clickedText;
}).toggle($(this).is(':checked'));
});
});
http://jsfiddle.net/LhuT9/1/
Compared this with Joe Frambach's answer, it differs by:
This example uses next instead of siblings
The filter function extracts the text using $('.row-heading', this).text() instead of $(this).find("div.row-heading").text()
Yet another alternative, though it's much the same with only minor differences:
// selects all input elements whose type is 'checkbox':
$('input[type="checkbox"]')
// binds an anonymous function to the 'change' event:
.on('change', function(){
// caching the this variable for later use:
var input = this,
// finding whether node.textContent or node.innerText is supported in the browser:
textProp = 'textContent' in document.body ? 'textContent' : 'innerText';
// selecting the '.row-section' elements,
$('.row-section')
// filtering that collection:
.filter(function(){
// using '$.trim()' to remove leading/trailing white-space
return $.trim($(this)
// finding the 'div.row-heading' elements within the current '.row-section':
.find('div.row-heading')
// retrieving its text:
.text())
// comparing for strict equality:
===
// finding the text of the label attached to the element
// the benefit of this approach is that it's independent
// of the DOM structure:
$.trim(input.labels[0][textProp]);
// showing if the input is checked, hiding if not:
}).toggle(input.checked);
// triggering the change event, so the anonymous function is called on page-load:
}).change();
JS Fiddle demo.
References:
JavaScript:
HTMLInputElement, to see a brief introduction to the labels property
jQuery:
$.trim().
change().
find().
filter().
on().
text().
toggle().

find form id div is in

Bit of a weird question. I have got a form and inside this form the controls are div's with onClick events instead of buttons. I can't use buttons as I can't use page reloads, instead I have to send all data using ajax.
Plus half of the buttons just increase counters, below is my code. How would I go about using JavaScript to find the form ID that the element clicked on is in. So as an example:
<form id="20">
...
<div onClick="doSomething(this)">
...
</form>
The doSomething will then keep moving up levels of parents or something like that until it finds the form, and then a variable will have the form id assigned to it.
<form id="50">
<div class="image_container background">
<div style="text-align:center; font-size:12px;">image1</div>
<input type="hidden" id="imgId" value="50" />
<div class="image" style="background-image:url(images/image3.JPG);"></div>
<div class="selected_product">
<span>KR</span>
</div>
<input type="hidden" id="applied_products" value="KR" />
</div>
<div class="controls_container background">
<div id="selected">KR</div>
<a class="button arrow expandProducts">
<span>
<div class="products">
<span>KR</span>
<span>A5</span>
<span>CC</span>
</div>
</span>
</a>
<hr />
<span class="button plus" onClick="sale(this)"></span>
<input type="text" id="amount" disabled="disabled" value="0"/>
<span class="button minus"></span>
<hr />
<input type="text" id="total" disabled="disabled" value="£0"/>
</div>
</form>
Your doSomething function could continue navigating through it's parents until it finds a form, like so:
function doSomething( elem )
{
var parent = elem.parentNode;
if( parent && parent.tagName != 'FORM' )
{
parent = doSomething(parent);
}
return parent.id;
}
Also, if you use <button type="button">...</button> it won't cause a page refresh, since the default button type is submit.
If you are going straight javascript and not jquery or some other library. Each DOM Element has a parentNode Property
var elm = document.getElementById(yourDivId);
var parent = elm.parentNode;
From there you can cycle through each parent, until you get back to the form element and then pull out the id.
How about something like that:
function handler(target) {
var parent = target.parentNode;
// loop until parent is a form or browser crashes :)
while (parent.tagName != 'FORM') {
parent = parent.parentNode;
}
var formId = parent.id; // the id you wanted
// do stuff
}

Categories