Make First Ingredient never able to be deleted - javascript

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.

Related

jQuery toggle failed to hide ul element

This Meteor code is expected to show and hide a <ul id="Bulb"> element. An event fires the first time shows the element but when clicked again it failed to hid it.
Please note the browser console.log($('#' + category)) image showing both events. Any idea why the second click not hiding the element and how to make it hide on the second event so that the toggle works?
Thank you.
'click .category': function(e){
let category = e.target.innerText
$('#' + category).toggle()
console.log($('#' + category))
}
.horizontal {
display: inline;
}
.group, .subGroup {
display: none;
}
<li class="category" data-category={{category}}> <img src="/{{category}}.svg"/>{{category}}
<ul id={{category}} class="no-bullets group">
<!-- the last word is the argument passed to the helper function -->
{{#each categories category}}
<li class="horizontal" data-category={{category}}>{{this}}</li>
{{/each}}
</ul>
Fix but with unwanted side effect
The reason is that the first click gives a value to e.target.innerText which is different than the value it gets in the second click.
The second value includes all the "innerText" of all the li items which are now visible in the child ul.
So instead of using let category = e.target.innerText I used:
let category = e.target.getAttribute('data-category')
and this value does not change between click as did the innerText.
The problem side effect of this is that clicking the li elements inside the child ul triggers the toggle which is not what I want.

detecting class changes in Bootstrap Switch Jquery (converting working checkbox JS to button js)

I am trying to convert a piece of JQuery that changes the class of a tr when checked to a piece of JQuery that changes the class of a tr when a button gets a class called "active". I am a JQuery/Javascript newbie and I am at a loss.
For those who have suggested it's a duplicate, I have tried to detect class and failed (updated code below).
ORIGINAL CODE (THAT WORKS)
javascript:
var $input_class = $('.addCheckbox');
function setClass() {
var tr = $(this).closest( "tr" );
if ($(this).prop('checked') == true){
tr.addClass( "highlight" );
}
else{
tr.removeClass( "highlight" );
}
}
for(var i=0; i<$input_class.length; i++) {
$input_class[i].onclick = setClass;
}
MY HORRIBLE TRY (UPDATED BELOW...NO LONGER THIS)
javascript:
var $input_class = $('.btn-group .btn-toggle .btn');
function setClass() {
var tr = $(this).closest( "tr" );
if ($(this).prop('.btn-success .active')){
tr.addClass( "highlight" );
}
else{
tr.removeClass( "highlight" );
}
}
for(var i=0; i<$input_class.length; i++) {
$input_class[i].onclick = setClass;
}
I am using the Bootstrap Switch Plugin which converts checkboxes to toggles
http://www.bootstrap-switch.org/
The converted html looks like this:
<tr>
<td width="15px"><input class="addCheckbox" type="checkbox" value="true" style="display: none;">
<div class="btn-group btn-toggle" style="white-space: nowrap;">
<button class="btn active btn-success btn-md" style="float: none; display: inline-block; margin-right: 0px;">YES</button>
<button class="btn btn-default btn-md" style="float: none; display: inline-block; margin-left: 0px;"> </button>
</div>
</td>
<td width="85px">May 2016</td><td class="restaurant-name">
Joe's Crab Shack
</td>
<td class="text-center">
#my table info
</td>
</tr>
UPDATE!!! As per 'duplicate' suggestions.
After looking through this question (which was very helpful), I have changed my code to this, and I still can't get it to work. I am wondering if it is having trouble finding the exact input class? Because the plugin converts the checkbox to html, I can't (or don't know how) set specific names or ids for the buttons.
javascript:
var $input_class = $('.btn');
var tr = $(this).closest( "tr" );
function checkForChanges()
{
if ($('.btn').hasClass('btn-success'))
tr.addClass( "highlight" );
else
tr.removeClass( "highlight" );
}
for(var i=0; i<$input_class.length; i++) {
$input_class[i].onclick = checkForChanges;
}
There are issues in your code resulting from not being familiar with the language. Also keep in mind this jQuery what you posted, not javascript.
As I am not quite sure what is your final objective here so let's go step by step.
First of all:
$('.btn-group .btn-toggle .btn');
The above means an element with all three classes class="btn-group btn-toggle btn" and I do not see such in your code. Are you sure you didn't want to use $('.btn-group, .btn-toggle, .btn'); ? At the moment var $input_class is empty, so later in your code you loop through nothing.
Second thing:
as I posted in the comments make sure you run your script after loading jQuery and rest of the content of the page. If your script is above jQuery, like this:
<head>
<script type="text/javascript">/* Your script here */</script>
<script type="text/javascript" src="jquery-1.9.1.min.js"></script>
</head>
Above won't work for two reasons:
You run your script before you load the jQuery, so commands like $(".class") aren't understood.
You run your script before loading the content, so for example var $input_class = $('.addCheckbox'); will be empty, because the element with class addCheckbox doesn't exist yet. [for this one assume jQuery is included before the script, but the script is still inside the <head>].

Building a list dynamically (depending on checkboxes)

I have the following question:
I have a couple of checkboxes (at the moment 11) and what I want to do now is "building" a list dynamically, depending on the value of the checkboxes, so having something like this:
A user comes, ticks a checkbox and one li is appearing, when he ticks the next one, the next li is appearing, when he ticks the next one, again one li is appearing and so on (when he unticks one of them, the li should disappear again). I'm quite sure this can work with JS, but I have no idea how to realize it.
What I have is a <ul> and all the checkboxes defined with
<input type="checkbox" name="check_phone" id="check_phone"/>
<label for="check_phone"><span></span>Phone Number</label>
(Every checkbox has it's individual name)
What I think is going to be the biggest problem is creating the list-points dynamically, but I really hope somebody knows how to do this.
What I already thought about is just having 11 list-points in my list, all set to display:none and then just setting them to display:block when a checkbox is checked, but this will propably not work because I'm using a plugin to resort the list after this, and having 11 list-points, but just 2 visible or anything like that won't work.
Thanks for your help!
Here is a very quick demo, each time a checkbox is changed it creates all checked list items.
$(document).ready(function(){
$('.item').on('change', function() {
var $list = $('ul#checked').empty();
$('.item:checked').each(function(index, item) {
var itemName = $(item).prop('name');
var text = $('label[for='+itemName+']').text()
$('<li></li>')
.text(text)
.appendTo($list)
;
})
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="checkbox" class="item" name="check_phone" id="check_phone"/>
<label for="check_phone"><span></span>Phone Number</label>
<ul id="checked">
</ul>
$("[name^='check_']").click(function(){
$("li."+ this.name).toggle( this.checked );
});
#check_list li{ display:none; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<label><input type="checkbox" name="check_phone"/>Phone Number</label>
<label><input type="checkbox" name="check_mobile"/>Mobile Number</label>
<ul id="check_list">
<li class="check_phone">PHONE LI</li>
<li class="check_mobile">MOBILE LI</li>
</ul>
I think this will do it. You just have to set the names of the list items to be the same as their corresponding checkboxes' names.
$("input:checkbox").click(function() {
var current = $(this),
linkedListCorrespondingElement = $('#list-id > li[' + current.attr('name') + ']');
if (current.is(":checked")) {
linkedListCorrespondingElement.show();
} else {
linkedListCorrespondingElement.hide();
}
});

target the <h4 id="name"> tag for the dynamically created divs using jquery

I am a total beginner to jquery. and am badly stuck. i would really appreciate if i could get some help with my code.
The scenario is,
- I have a drop down list for the names.
- When i select a name from the list, it should display in the div which is placed beneath the drop down menu. The div will be created automatically via jquery. every item selected from the list will be displayed in its own respective div. The name Sarah should not be included in the drop down list.Its like a stand alone thing. However, when i select an item in the list, the name Sarah is replaced with the selected item.
What i was able to code was --
- I could get the divs with some names associated with it. However, i am unable to target the selected item to its respective div.
I hope it makes sense. I am posting the link to my jsFiddle. Please help.
http://jsfiddle.net/zohana28/0akosx2a/
<div class="part-4">
<select id="sel">
<option value="Cheese">Cheese</option>
<option value="Olives">Olives</option>
<option value="Pepperoni">Pepperoni</option>
<option value="Oregano">Oregano</option>
<option value="Thyme">Thyme</option>
</select>
</div>
<!--end of part 4-->
<div class="main">
<div class="part-2" id="click-1" style="cursor:pointer;">
<div class="part-2-address">
<h4 id="name">sarah</h4>
</div>
</div>
jQuery is:
$(document).ready(function () {
$(document).on('change', '#sel', function (e) {
$('.part-3').html($('.part-2').html());
$('.main').append('<div class = "part-3" > </div>');
var str = $('select option:selected').text();
$('#name').text(str);
console.log(str);
});
return false;
});
thank you in advance.
I've adjusted your Fiddle a bit.
$(document).ready(function () {
$(document).on('change', '#sel', function (e) {
var nameTempl = '<div class="part-2" class="click-1">'
+ '<div class="part-2-address">'
+ '<h4 class="name">{name}</h4></div></div>';
var str = $('select option:selected').text();
$('.main').append(nameTempl.replace(/{name}/, str));
});
return true;
});
For the HTML: I removed the inline-style cursor:pointer; and added it as style for the class .click-1 - previously click-1 and name were ids, I've changed both to be classes. ids have to be unique, so you have to use classes instead.
Though it would be possible to clone() the <div class="part-2" class="click-1"> and then change the name to the current selected option, I just preferred to use the target div as template in the function, with {name} as placeholder to be replaced with the current selected option: nameTempl.replace(/{name}/, str).
Another adjustment that you can change back is - I've set the height:200px; of the .main div to min-height: 200px;, so this container grows when necessary. You can just change this back to height:200px; in case you prefer the yellow div to have a static height like before.
As reference for replace(): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace

traverse element inside the div

html:
<div style="width: 260px;margin:25px 0 0 30px">
<input type="checkbox" name="send_email" class="delete_followup" />Send email alerts
<input type="checkbox" value="delete" type="checkbox" />Send SMS alerts <button type="submit" name="delete" value="{{follower.id}}" class="delete_follower">Delete</button>
</div>
js:
$(".delete_followup").click(function(){
var $this = $(this);
$(this).find(".delete_follower").show();
});
I want to show the hidden button on clicking the delete_followup class.i TRIED WITH ABOVE jQuery but not working.
Or try .nextAll:
$(this).nextAll(".delete_follower").show();
Working here: http://jsfiddle.net/tw5XK/
The delete_follower element is not a decedent of delete_followup element, it is a sibling element so instead of find() you need to use siblings()
$(".delete_followup").click(function(){
var $this = $(this);
$this.siblings(".delete_follower").show();
});
You are trying to search downward into the div, when you already have a reference to the element you want. Making it way more complicated than it needs to be lol
$(".delete_followup").click(function(){
$(this).show();
});
Whenever you trigger off a click event, the actual element clicked on is passed through as the scope of the function. Since you are triggering off the click of ".delete_followup", that div is your element scope
Try this:
$(".delete_followup").click(function () {
if (this.checked) {
$(this).siblings(".delete_follower").show();
} else {
$(this).siblings(".delete_follower").hide();
}
});
Demo here

Categories