Closest li without span - javascript

I'm trying to create a selector that will grab li element and show the text. The problem is that inside li tag I have span tag and that is also displayed.
How do I grab text of closest element without some of the elements inside?
see here, I don't want the word 'Edit' to be included.
http://jsfiddle.net/ozyf87tb/
<li>This is the story of the Jungle book
<form action="" method="" class="form_edit">
<textarea class="inte" value="" name="inte"></textarea>
</form>
<span class="edit">Edit</span>
</li>
$(".edit").click( function(ev) {
var a = $(this).closest('li').text();
$('.inte').val(a);
});

http://jsfiddle.net/ozyf87tb/7/
Clone it (so you work with the clone, not in the DOM), get children, remove the children, get the text.
$(".edit").click( function(ev) {
var a = $(this).closest('li').clone().children().remove().end().text();
$('.inte').val(a);
});

The most readable way to do what you want to do is surrounding your text with a container like <span class='myText'></span>. So you could select the exact container using its class :
DEMO
<li><span class='myText'>This is the story of the Jungle book</span>
<form action="" method="" class="form_edit">
<textarea class="inte" value="" name="inte"></textarea>
</form>
<span class="edit">Edit</span>
</li>
$(".edit").click( function(ev) {
var a = $(this).prevAll('.myText').text();
$('.inte').val(a);
});

First, get a clone() of the html.
var a = $(this).closest('li').clone();
Then remove the extraneous span.
a.find('span').remove();
Then put that into the textarea.
$('.inte').val( a.text() );
This can also be rewritten into a single string, but takes away from readability.
var a = $(this).closest('li').clone().find('span').remove().end().text();
$('.inte').val( a );
jsfiddle

Use contents() and then filter your selection to return only text nodes. Then all you need to do is to trim any white-space:
var a = $.trim($(this).closest('li').contents().filter(function(){
return this.nodeType == 3;
}).text());
JSFiddle
Documentation
$.trim()
.contents()
.filter()
Node.nodeType

Related

Javascript: Delete a div that contains (3) in a row <BR>'s in it

<div>
<br>
<br>
<br>
</div>
I have an HTML page that has the above div element in it. How can I scan the page an look for a DIV that contains specific items? In this example I know I have three <br> in a row and that's it. The DIV element does not have a class or an ID, and I would like to delete it.
You can target elements in a row by using the sibling selector, +. You can make sure the target elements are a direct child of the div by using the > selector.
You can find the div that contains the three br elements like so:
document.querySelector('div > br + br + br').parentNode;
To remove this element from the DOM use the remove method.
const elToDelete = document.querySelector('div > br + br + br')?.parentNode;
elToDelete?.remove();
Edit:
Added optional chaining syntax to the answer to show how to prevent undefined errors from being thrown.
You can use the :has pseudo-class to select the div directly
var elem = document.querySelectorAll("div:has(>br+br+br)");
console.log([...elem])
elem.forEach(x=>x.remove())
<div id=a> a
<br/>
<br/>
<br/>
</div>
<div id=b> b
<br/>
<br/>
</div>
<div id=c> c
<br/>
<br/>
<not-br/>
<br/>
</div>
You can try this:
[].slice.call(document.getElementsByTagName("div")).forEach(function(div){
var count = 0;
if(div.children.length === 3)
[].slice.call(div.children).forEach(function(br, i){
if(br.nodeName === "BR")
count++;
});
if(count > 2)
div.parentElement.removeChild(div);
});
You can just hide it with CSS
div:has(>br+br+br) {
display: none;
}
<div>1</div>
<div><br/><br/><br/></div>
<div>3</div>
Best solution that will work cross-browser is to tackle this programmatically. Note that :has() pseudo class doesn't work on Firefox, IE or Opera (see https://caniuse.com/css-has).
Here's a concise functional Javascript approach:
[].filter.call(document.querySelectorAll('div'), el => el.querySelectorAll('br').length === 3)

can I remove a line in my HTML code with javascript?

I have this code:
<div class="input">
<input type="number" id="myID" oninput="myFunction()">
<div>
<h3>MY TEXT</h3>
</div>
</div>
and I want to make a javascript code to remove the div below the input field whenever I write anything in the input
..........
I tried this code:
function myFunction(){
var field = document.getElementById("myID");
var num = field.value;
var parent = field.parentNode;
parent.innerHTML = field.outerHTML;
field.value = num;
}
but it have a problem each time I make an input, I have to re-click inside the input to make it active again
check out the code here
You should not use inline HTML event attributes to wire up event handlers. That technique is 25+ years old and will not die the death it deserves because people just keep copying it from other code they've seen.
See the comments for the simple explanation:
// Add the event handler to the input in JavaScript, not in HTML
document.getElementById("myID").addEventListener("input", removeElement);
function removeElement(){
// Remove the sibling element that follows the input
document.querySelector("#myID").nextElementSibling.remove();
// Now that the element has been removed, this function is no
// longer required, so remove the event handler to prevent attempts
// to remove it again when it's no longer there. "this" refers to
// the object that caused this function to be invoked (the input
// element in this case).
this.removeEventListener("input", removeElement);
}
<div class="input">
<input type="number" id="myID">
<div>
<h3>MY TEXT</h3>
</div>
</div>
How to remove an HTML element using JavaScript ?
Given an HTML element and the task is to remove the HTML element from the document using JavaScript.
Approach:
Select the HTML element which need to remove.
Use JavaScript remove() and removeChild() method to remove the
element from the HTML document.
Exemple to remove a div :
div.parentNode.removeChild(div);
Follow this link for more information.
I hope I was able to help you.
<div class="input">
<input type="number" id="myID" >
<div id="id2">
<h3>MY TEXT</h3>
</div>
</div>
<script>
document.getElementById("myID").oninput = function() {myFunction()};
function myFunction() {
document.getElementById("id2").innerHTML="";
}
</script>
Problem with using innerHTML is you are basically using a whiteboard. You erase everything on it and you have to redraw it all. That means you would need to reset the value and focus. It is doable, just not practical.
The better thing to do would be to select the element and remove it with .remove()
var field = document.getElementById("myID");
var num = field.value;
if (num.length) {
field.nextElementSibling.remove()
}
It will work, but you will be better off using a class to hide the element. It also has the benefit that if the user deletes the text in the input, you can reshow the message. I would just hide it with a css class with toggle. I would select the div with nextElementSibling.
function myFunction(){
var field = document.getElementById("myID");
var num = field.value;
field.nextElementSibling.classList.toggle('hidden', num.length)
}
.hidden {
display: none;
}
<div class="input">
<input type="number" id="myID" oninput="myFunction()">
<div>
<h3>MY TEXT</h3>
</div>
</div>

Show/Hide Immediate next element Input

I'm trying to show hide immediate next imput within the div, but it opens all the inputs
I also tried
`$(this).next("input").show();` ( traversing )
nothing seems to work.
Any help?
Here is my http://jsfiddle.net/526stLtg/1/
You need to use siblings() and for toggling visibility use toggle()
$(document).ready(function() {
$(".add-guest > button").click(function() {
$(this).siblings('input').toggle();
});
});
.add-guest input[type="text"] {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="add-guest">
<b>Bride:</b>
<button id="bride">Add</button>
<br>
<input type="text" name="Bride">
</div>
<br/>
<br/>
<div class="add-guest">
<b>Groom:</b>
<button id="bride">Add</button>
<br>
<input type="text" name="Bride">
</div>
You can use this to refer to html element and using .parent() and .find():
$(document).ready(function() {
$(".add-guest > button").click(function() {
$(this).text() === "Add" ? $(this).text("Remove") : $(this).text("Add");
$(this).parent().find("input").toggle();
});
});
.add-guest input[type="text"] {
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="add-guest">
<b>Bride:</b>
<button id="bride">Add</button>
<br>
<input type="text" name="Bride">
</div>
<br/>
<br/>
<div class="add-guest">
<b>Groom:</b>
<button id="bride">Add</button>
<br>
<input type="text" name="Bride">
</div>
Additionally you can use .toggle() instead of .show.
You can use $(this) to select the clicked button (the event trigger).
Then, if you look at your code, you'll see that the next element is a <br/>, and the next the <input> that you want to show. So, if you change:
$(".add-guest > input").show();
to
$(this).next().next().show();
It will work. You can think tha you can also use a selector to find the first sibling filtered by the selector, i.e.
$(this).next('input').show();
But this doesn't work. This checks if the sibling can be selected with the paseed selector. But you can use the .nextAll('input'), only because in this case there are only one sibling which can be seelcted like this. If not you could use this selector, and .first()
Your original code was selecting all inputs precede by elements with the .add-guest class, whic is not what you wanted to do.
If there are multiple input elemnts within div and you want to select first input element only then use :first pseudo-class
$(this).parent().find("input:first").toggle();

disable-enable the hyperlinks by clicking on a button

I want to make something similar to this:
disable-enable a hyperlink by clicking on radio-buttons
but I would like to apply this method on multiple links, so I have to use the class of the elements.
Just changing the code using ".getElementsByClassName" doesn't work, and I don't understand why.
Can you explain that to me?
StackoverFlow answer for question
var link;
function disable_link() {
document.getElementsByClassName('testlink').disabled=true;
link = document.getElementsByClassName('testlink').href;
document.getElementsByClassName('testlink').removeAttribute('href');
}
function enable_link() {
document.getElementsByClassName('testlink').setAttribute("href",link);
}
</script>
</head>
<body>
<form id="form1" name="form1" method="post" action="">
<p>
<label>
<input type="radio" name="RadioGroup1" value="radio" id="RadioGroup1_0" onchange="disable_link();" />
Disable</label>
<br />
<label>
<input type="radio" name="RadioGroup1" value="radio" id="RadioGroup1_1" onchange="enable_link();" />
enable</label>
<br />
</p>
<a class="testlink" href="http://www.yahoo.com"> test </a>
<a class="testlink" href="http://www.yahoo.com"> test </a>
<a class="testlink" href="http://www.yahoo.com"> test </a>
<a class="testlink" href="http://www.yahoo.com"> test </a>
</form>
</body>
</html>
Even other methods are fine.
edit: Thanks to all of you for the answers.
getElementsByClassName returns a HTMLCollection, so you will have to loop over it and handle each link individually.
In this case you no longer can use temporary variable to hold disabled link href. Simple solution would be to store removed href attribute in another attribute on the corresponding element.
It can look something like this:
function disable_link() {
var links = document.getElementsByClassName('testlink');
for (var i = 0; i < links.length; i++) {
links[i].setAttribute('data-href', links[i].getAttribute('href'));
links[i].removeAttribute('href');
}
}
function enable_link() {
var links = document.getElementsByClassName('testlink');
for (var i = 0; i < links.length; i++) {
links[i].setAttribute("href", links[i].getAttribute('data-href'));
}
}
Demo: http://jsfiddle.net/5z8av0xg/
Note s in the following quote:
The getElementsByClassName() method returns a collection of all elements in the document with the specified class name, as a NodeList object.
The NodeList object represents a collection of nodes. The nodes can be accessed by index numbers. The index starts at 0.
Tip: You can use the length property of the NodeList object to determine the number of elements with a specified class name, then you can loop through all elements and extract the info you want.
[ http://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp ]
this line wont work because it doesn't make sense which href of testclass should be set in parameter:
link = document.getElementsByClassName('testlink').href;
Actually You dont need to remove href. instead of that you can make a not_active class and toggle this class on all links is testlink class. (workd in IE11+ and others)
.not-active {
pointer-events: none;
cursor: default;
}
jquery to toggle class (handles both enabling and disabling):
function disable_link(){
$(".testlink").toggleClass("not_active")
}

Make First Ingredient never able to be deleted

I'm making an ingredients application where users insert ingredients
My application looks like this:
As you can see, the first ingredients span doesn't have a X at the end, because you must have at least one ingredient, but the rest of the ingredient spans do. I'm also using the Jquery Sortable Plugin so if you click near the outside of any of the ingredient spans, you can change the order of the ingredients. This works fine, except if you move the first ingredient span, then that span doesn't have an X at the end, even if you move it to the last spot.
So what I'm trying to do is make the first ingredient span always have no X at the end, even if switched order with another ingredient span. I tried this:
$('ingredientsCOUNT > span:first').hide(deleteButton);
but it didn't work? Any other suggestions? All help is greatly appreciated, and here's my code:
HTML (the php can just be ignored!)
<div class='formelementcontainer funky'>
<label for="ingredient">Ingredients</label>
<div id='ingredientsCOUNT' class='sortable'>
<span>
<input type="text" class='small' name="ingredient" id="ingredient" placeholder='QTY'/>
<select name='measurements'>
<option value='' name='' checked='checked'>--</option>
<?foreach ($measurements as $m):?>
<option value='<?=$m->id;?>'><?=$m->measurement;?></option>
<?endforeach;?>
</select>
<input type="text" name="ingredient" id="ingredient" placeholder='Ingredient'/>
</span>
</div>
<div class="clear"></div>
<div class='addSPAN tabover'>
<a class='float-right' id='btnAddIngredients' href='#'>Add Ingredient</a>
</div>
</div>
jQuery
(function($) {
$(document).ready(function () {
$('#btnAddIngredients').click(function () {
var num = $('#ingredientsCOUNT span').length;
var newNum = new Number(num + 1);
var deleteButton = $("<a class='float-right' style='margin:10px 2px;' href='#'><img src='<? echo base_url()."public/img/delete.png";?>' height='11' width='11' /></a>");
deleteButton.click(deleteThis);
$('#ingredientsCOUNT > span:first')
.clone()
.attr('name', 'ingredient' + newNum)
.append(deleteButton)
.appendTo('#ingredientsCOUNT')
.fadeIn();
$('ingredientsCOUNT > span:first').hide(deleteButton); //THIS IS MY SOLUTION THAT DIDN'T WORK
});
function deleteThis() {
var span = $(this).closest('span')
span.fadeOut('slow', function() { span.remove(); });
}
$( ".sortable" ).sortable(); //jQuery Sortable initialized
});
})(jQuery);
How about hiding it with CSS? The following assumes you added a class delete-button to your delete links:
#ingredientsCOUNT > span:first-child .delete-button { display: none; }
With that CSS, you can reorder the list, add or remove items, and the first delete button will never show.
Since :first-child is quirky in oldIE ( https://developer.mozilla.org/en-US/docs/CSS/:first-child#Internet_Explorer_notes ), it's possible to use the Sortable API like this:
$(".sortable").sortable({
update: function (event, ui) {
var rows = $("#ingredientsCOUNT").children("span");
rows.removeClass("first-child");
rows.first().addClass("first-child");
}
});
(there's probably a better way to utilize the event and/or ui parameters)
This way, you wouldn't have to determine which row to add a delete button to; you would always include a delete button in every row in your HTML. Then, when a sorting is done, the jQuery in the stop event (EDIT: update event) will hide the first row's delete button and show the rest (via classes).
Of course, you would need this CSS:
#ingredientsCOUNT > span.first-child a.delete-button {
display: none;
}
And to add a delete-button class to your delete buttons <a>
EDIT:
I changed the Sortable method from stop to update so that it only runs the code when the sorting arrangement has actually changed, after the sorting is done.

Categories