Element value inside Bootstrap accordion doesn't validate empty - html

I have some cards dynamically generated with a loop. In one part, I have an accordion element that is triggered with a button (Bootstrap method). I change the background color of that button when the element accordion-body, which is contenteditable true, has value in it after losing focus. The problem is, I want to remove the button color if the accordion-body is empty, but the element accordion-body seems to still have a value after losing focus even when the user deletes all content.
This is the accordion code:
Why is it that $(this).val() never evaluates empty? I had a console message in the if statements, it never goes to the else validation.
$('.accordion-body').on('focusout', function() {
var style = $(this).closest('.accordion-item').find('button[id=infobtn]').attr('style');
//it will return string
style += ';background-color: #f4cccc;';
if ($(this).val() != '') {
$(this).closest('.accordion-item').find('button[id=infobtn]').attr('style', style);
} else {
$(this).closest('.accordion-item').find('button[id=infobtn]').attr('style');
}
});
<script> src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<span class="mySpan">
<div class="accordion accordion-flush py-0" id="accordionFlushExampleOne">
<div class="accordion-item py-0">
<h2 class="accordion-header" id="flush-headingOne">
<button class="accordion-button collapsed" id="infobtn" name="infobtn" style="height:25px; <?php if (!empty($additionalInfo)) echo " background-color: #f4cccc; " ?>" type="btn btn-sm" data-bs-toggle="collapse" data-bs-target="#flush-collapseOne>" aria-expanded="false"
aria-controls="flush-collapseOne">Additional Info
</button>
</h2>
<div id="flush-collapseOne" class="accordion-collapse collapse" aria-labelledby="flush-headingOne" data-bs-parent="#accordionFlushExampleOne">
<div class="accordion-body fw-bold" id="additionalInfo" name="additionalInfo" contenteditable="true">
<?php echo "$additionalInfo" ?>
</div>
</div>
</div>
</div>
</span>

Giving HTML block elements the attribute contenteditable="true" is responsible for that behaviour.
Removing the content of such an element in the browser, will set a replacement <br> instead in there.
Thus, if ($(this).val() != '') will never be true, because your containing element will never be empty.
Changing the containing div to an inline element such as span fixes the issue and your conditonal logic will get to work.
HTML - swap <div> with <span>
<span class="accordion-body fw-bold" id="additionalInfo" name="additionalInfo" contenteditable="true">
<?php echo "$additionalInfo" ?>
</span>
HTML & JQuery - inner <span> within <div> to preserve bootstrap accordion design
<div class="accordion-body fw-bold" id="additionalInfo" name="additionalInfo" contenteditable="true">
<span contenteditable="true">
<?php echo "$additionalInfo" ?>
</span>
</div>
$('.accordion-body span').on('focusout', function() {...

Thanks for all the recommendations and information about this matter. #bitski suggestion took me to the right direction. I tried all the options given, and somehow my accordion-body element always received the <br> value, it was never empty. I did some research and found a way to reset the content after losing focus (I ended up using blur instead).
So my accordion-body field looks like this now:
<div class="accordion-body fw-bold" id="additionalInfo" name="additionalInfo" contenteditable="true" onblur="event.target.scroll(0,0)">
And my jquery looks like this:
$('.accordion-body').on('blur', function() {
var style = $(this).closest('.accordion-item').find('button[id=infobtn]').attr('style'); //it will return string
style += ';background-color: #f4cccc;';
if ($(this).text().trim().length != 0) {
$(this).closest('.accordion-item').find('button[id=infobtn]').attr('style', style);
} else {
style += ';background-color: #FFFFFF'; //When field is empty, change the button background color back to white
$(this).closest('.accordion-item').find('button[id=infobtn]').attr('style', style);
}
});
That did the trick! Hope this helps someone else.

Related

How to show/hide chosen image on button click in query

I would really appreciete any help in the following task.
The task is pretty simple. I have a couple of paragraphs of text. Each paragraph has a title and desription. Decription should be hidden, and shown only after clicking "plus" button. On click "plus" icon should change to "minus". So far, I have maganed to acheve this. But then, after clicnkin again, text should hide again (that works), but the icon should change to "plus" again. And here I am failing. I have tried many ideas I found in the Internet, but could't make it working.
My HTML code:
<div class='toggle-description'>
<p class='event-type speaker-country'>$event_type</p>
<button class='plus-button'>
<img class='plus-icon' src='https://cdn-icons-png.flaticon.com/512/748/748113.png'>
<img class='minus-icon' src='https://cdn-icons-png.flaticon.com/512/43/43625.png'>
</button>
<h4 class='lt-opis'>$event_title</h4>
<div class='more-text' style='display: none;'>
<p>$event_description</p>
</div>
</div>
jQuery code:
$(document).ready(function() {
$(".minus-icon").hide();
$(".plus-button").click(function(){
$(this).closest(".toggle-description").find(".more-text").toggle();
var button_plus = $(this).closest(".toggle-description").find(".plus-icon");
button_plus.css("display", "none");
var button_minus = $(this).closest(".toggle-description").find(".minus-icon");
button_minus.css("display", "block");
});
});
$(document).ready(function() {
$(".minus-icon").hide();
$(".plus-button").click(function(){
$(this).find(".plus-icon").toggle();
$(this).find(".minus-icon").toggle();
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='toggle-description'>
<p class='event-type speaker-country'>$event_type</p>
<button class='plus-button'>
<img class='plus-icon' src='https://cdn-icons-png.flaticon.com/512/748/748113.png'>
<img class='minus-icon' src='https://cdn-icons-png.flaticon.com/512/43/43625.png'>
</button>
<h4 class='lt-opis'>$event_title</h4>
<div class='more-text' style='display: none;'>
<p>$event_description</p>
</div>
</div>
In the jquery part change this button_plus.css("display", "none"); to button_plus.toggle() and button_minus.css("display", "block"); to button_minus.toggle() and it works.
jsfiddle link

How can I make a <i> element clickable without listening to a keypress?

I have a few <i> elements with glyphicons and I want them to be triggered when I press the ENTER key. I am using Angular 2
How can I do this?
<i class="glyphicon glyphicon-menu-down down"
*ngIf="!(sort.name === 'Last Name' && sort.order > 0)" (click)="sortTrips('name')" ></i> .
I've found the answer (only for Angular 2):
<div (keyup.enter)="function()">
<i class="glyphicon glyphicon-menu-down down"><i>
</div>
In this situation the application is working as inttended.
Try to create an event like #HassanIman say it looks like :
<!DOCTYPE html>
<html>
<body>
<p>This example demonstrates how to assign an "onclick" event to a p element.</p>
<p id="demo" onclick="myFunction()">Click me.</p>
<script>
function myFunction() {
document.getElementById("demo").innerHTML = "YOU CLICKED ME!";
}
</script>
</body>
</html>
You try see the full exemple in this website : W3SCHOOLS ONCLICK EVENT

How to show/hide in Angular2

I have a component that show/hide element by clicking a button.
This is my html
<div *ngFor="let history of histories | sortdate: '-dateModified'">
<p><b>{{ history.remarks }}</b> - <i>{{history.dateModified | date:'short'}}</i></p>
<a href="google.com"
[class.datatable-icon-right]="history.$$expanded"
[class.datatable-icon-down]="!history.$$expanded"
title="Expand/Collapse Row"
(click)="toggleExpandRow(history)"></a>
<!-- hide/show this by clicking the button above.-->
<div *ngFor="let step of history.steps; let i = index">
<b>{{i+1}}.</b> {{step}}
<span class="clear"></span>
</div>
<hr />
</div>
and my .ts
toggleExpandRow(row) {
console.log('Toggled Expand Row!', row);
//row
return false;
}
trying to search but, can't find any same sample.
On jquery, I can do this, but on Angular2, I am having hard time to figure this.
There are two options:
1- You can use the hidden directive to show or hide any element
<div [hidden]="!edited" class="alert alert-success box-msg" role="alert">
<strong>List Saved!</strong> Your changes has been saved.
</div>
2- You can use the ngIf control directive to add or remove the element. This is different of the hidden directive because it does not show / hide the element, but it add / remove from the DOM. You can loose unsaved data of the element. It can be the better choice for an edit component that is cancelled.
<div *ngIf="edited" class="alert alert-success box-msg" role="alert">
<strong>List Saved!</strong> Your changes has been saved.
</div>
Use the ngIf in your repeated rows. Create a boolean property called showStep to indicate whether the row should be expanded or not.
<div *ngFor="let step of history.steps; let i = index" ngIf="history.showStep">
<b>{{i+1}}.</b> {{step}}
<span class="clear"></span>
</div>
Then, in your .ts file:
toggleExpandRow(history) {
history.showStep = !history.showStep
//note the same porperty of showStep that is used in your html
}
Extra:
In fact, to save a few lines of codes, you don't even need the toggleExpandRow function at all. You can do it inline in your html:
//other attributes omitted for brevity
<a (click)="history.showStep = !history.showStep">

Trying to put a button into a link

I have a clickable span, which has a button in it. I want the span to go to one href and the button to another. Here is the code I currently have:
<script>
function deleteAlbum(url) {
var txt;
var r = confirm("Do you really want to delete this album?");
if (r == true) {
window.location.href = url;
}
document.getElementById("demo").innerHTML = txt;
}
</script>
<a href='gallery.php?album=16022015NewTest'>
<span class='album'>
<p>New Test</p>
<p>16/02/2015</p>
<button class='delete' onClick=deleteAlbum('gallery.php?delete_album=16022015NewTest')>
Delete Album
</button>
</span>
</a>
Anyone have any ideas?
You want to read up on event bubbling - the quirksmode explanation in that answer is very nice.
Here's one possible fix for your example:
<script>
function gotoAlbum(albumId) {
window.location.href="gallery.php?album="+albumId;
}
function deleteAlbum(e, url) {
var r = confirm("Do you really want to delete this album?");
if (r == true) {
window.location.href = url;
}
e.stopPropagation();
}
</script>
<span class='album' onClick="gotoAlbum('16022015NewTest');" >
<p>New Test</p>
<p>16/02/2015</p>
<button class='delete' onClick="deleteAlbum(event, 'gallery.php?delete_album=16022015NewTest');">Delete Album</button>
</span>
Aside: as the other comments mention, a button inside an anchor is odd - it's not compliant HTML5 - see this question
You don't. Don't put <button> inside <a>.
According to atmd's comment restructure your html: Don't put button inside a. To be html conform use quotes for attribute values:
<div class="album">
<a href="gallery.php?album=16022015NewTest">
<p>New Test</p>
<p>16/02/2015</p>
</a>
<button class="delete" onClick="deleteAlbum('gallery.php?delete_album=16022015NewTest')">Delete Album</button>
</div>
So the a tag does not include the button tag. It is also a good idea not to have block elements inside inline elements. The span tag has already been changed to a div tag. You might also change the p tags to span. Then the html looks like this:
<div class="album">
<a href="gallery.php?album=16022015NewTest">
<span>New Test</span>
<span>16/02/2015</span>
</a>
<button class="delete" onClick="deleteAlbum('gallery.php?delete_album=16022015NewTest')">Delete Album</button>
</div>

Drop Down Menu Categories / Sub Categories

What I am trying to do is have a drop down menu divided. In this example there are Five Options how can I split the drop down into categories? For example option 1 and 2 pop out of the environment category and option 3 and 4 sports category and 5 college category? http://jsfiddle.net/fc3550sk/
For example:
Drop down: Please Select when you click it Menus will be Environment, Sports, Colleges..
Then hover over Environment and it will let you choose from option 1 or 2... or hover over sports and it will let you chose from 3 or 4 and so on..
This is what I have so far:
<select name="SPECIAL" id="SPECIAL">
<option>Please Select</div>
<option data-img="/images/img/AnimalFriend.png" value="1">AnimalFriend</option>
<option data-img="/images/img/Aquaculture.png" value="2">Aquaculture</option>
<option data-img="/images/img/ProtectOurOceans.png" value="3">Protect Our Oceans</option>
<option data-img="/images/img/ConserveWildlife.png" value="4">Conserve Wildlife</option>
</select>
<!-- Modal -->
<div class="modal fade" id="modal_special" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span><span class="sr-only">Close</span></button>
<h4 class="modal-title" id="myModalLabel">Specialty Plate</h4>
</div>
<div class="modal-body">
...
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" class="btn btn-primary accept">Accept</button>
</div>
</div>
</div>
</div>
$(function() {
$('#SPECIAL').on('change', function() {
if ($('option:selected', this).is('[data-img]')) {
$('#modal_special').find('.modal-body').html('<p>Image will go here:</p>')
.append('<img alt="coming soon" src="' + $('option:selected', this).data('img') + '"/>')
.end().modal('show');
}
});
$('.accept').on('click',function() {
//do something
$('#modal_special').modal('hide');
});
});
Any help would be greatly appreciated!!
I don't know of a way to attach a "hover" event listener to a standard drop-down menu, but it's not too much work to implement your own custom drop-down with jquery, html and css.
Custom Drop-down Advantage #01
You get to assign as many custom values to each entry as you want.
In your example, you have "Specialty Plates", and you may want to assign a price, a special code assigned to that plate, an image assigned to that plate, and so on. With an HTML/jQuery version, you can create your custom drop-downs with simple <span> tags like this:
<span data-code="SPRT01" data-image="" data-price="34.00">Sports 01</span>
<span data-code="SPRT02" data-image="" data-price="35.00">Sports 02</span>
<span data-code="SPRT03" data-image="" data-price="36.00">Sports 03</span>
Notice how each entry has three custom values assigned to it: data-code, data-image, and data-price. If you use an html drop-down, you don't have as much freedom. There are ways to extend the values associated with a standard drop-down, but getting at the values is messy, and you will still not have access to the hover behavior your features require.
Custom Drop-down Advantage #02
You can actually use the hover behavior in any way you want.
In your example, you want the "submenus" to show up when certain values in your drop-down are selected, but as far as I know, there isn't a way to gain access to the values that are "hovered" in a standard drop-down, and looking for an HTML-only solution just doesn't exist, so you would have to use javascript in one way or another.
Using jQuery, you can easily get to the values in your custom drop-down elements like this:
$("span").hover(
function(){
var text = $(this).text();
console.log("You have hovered on: ", text);
},
function(){
// You have hovered off the span
}
);
My Solution to Your Problem
Putting these ideas into practice, I put together a simple demo of how you can create a custom drop-down using your applications parameters.
You can review a jsfiddle of the demo here.
The Basic idea is that you create a hierarchy in html with the structure of your Top-level options (Environment, Sports, Colleges) in the div .drop_down_scroll_container, and you place all your sub-level divs (Environment 01, Environment 02, etc) below that div in a div classed .dropdown-subcategory. Where the magic happens, is that javascript looks up the index of the top-level option, and then reveals the dropdown-subcategory with that same index.
For example, in the following snippet of html, you can see the index positions of each of the spans within the drop_down_scroll_container div:
<div class="drop_down_scroll_container">
<span>Environment</span> <!-- index 0 -->
<span>Sports</span> <!-- index 1 -->
<span>Colleges</span> <!-- index 2 -->
</div>
So then, when you hover over any of those Top-level options (Environment, Sports, Colleges) you can ask jQuery to reveal the corresponding submenu div, which are sitting below the .drop_down_scroll_container div in div containers with a class of .dropdown-subcategory
<div id="dropdown" class="specialtyPlatesCategories">
<div class="selectHeader">Click to Select Plates:</div>
<!-- THIS IS WHERE YOU WILL PUT YOUR TOP-LEVEL OPTIONS -->
<div class="drop_down_scroll_container">
<span>Environment</span>
<span>Sports</span>
<span>Colleges</span>
</div>
<!-- THIS DIV IS AT INDEX 0 of: #dropdown.dropdown-subcategory -->
<!-- Will fade in when the drop_down_scroll_container index 0 is hovered -->
<div id="env_subcategories" class="dropdown-subcategory">
<span data-code="ENV01" data-image="" data-price="31.00">Environment 01</span>
<span data-code="ENV02" data-image="" data-price="32.00">Environment 02</span>
<span data-code="ENV03" data-image="" data-price="33.00">Environment 03</span>
</div>
<!-- THIS DIV IS AT INDEX 1 of: #dropdown.dropdown-subcategory -->
<!-- Will fade in when the drop_down_scroll_container index 1 is hovered -->
<div id="sports_subcategories" class="dropdown-subcategory">
<span data-code="SPRT01" data-image="" data-price="34.00">Sports 01</span>
<span data-code="SPRT02" data-image="" data-price="35.00">Sports 02</span>
<span data-code="SPRT03" data-image="" data-price="36.00">Sports 03</span>
</div>
<!-- THIS DIV IS AT INDEX 2 of: #dropdown.dropdown-subcategory -->
<!-- Will fade in when the drop_down_scroll_container index 2 is hovered -->
<div id="colleges_subcategories" class="dropdown-subcategory">
<span data-code="COLL01" data-image="" data-price="37.00">Colleges 01</span>
<span data-code="COLL02" data-image="" data-price="38.00">Colleges 02</span>
<span data-code="COLL03" data-image="" data-price="39.00">Colleges 03</span>
</div>
</div>
If none of that made any sense, here is another way of looking it at:
When the first item in the .drop_down_scroll_container is hovered, jQuery looks for the first instance of a .dropdown-subcategory below it. When the second item in the .drop_down_scroll_container is hovered, then jQuery will reveal the second instance of the .dropdown-subcategory, and so on. This lets you build as many options as you want, without having to worry about giving everything specific names, only the order matters in this case. So when the "Environment" option (who's index equals 0) is hovered, the .dropdown-subcategory with an index of 0 will show. That is the basic idea.
So now for the jQuery that puts it all together:
$(document).ready(function(){
// When the header for the custom drop-down is clicked
$(".selectHeader").click(function() {
// cache the actual dropdown scroll container
var dropdown = $(this).parent().find(".drop_down_scroll_container");
// Toggle the visibility on click
if (dropdown.is(":visible")) {
dropdown.slideUp();
$(this).parent().find(".dropdown-subcategory").fadeOut();
} else {
dropdown.slideDown();
}
});
// When a top-level menu item is hovered, decide if its
// coorespnding submenu should be visible or hidden
$(".drop_down_scroll_container span").hover(
// hover on
function() {
// Remove the "highlighted class from all other options
$(this).parent().find("span").removeClass("highlighted").removeClass("selected");
$(this).addClass("highlighted").addClass("selected");
// Get the index of the hovered span
var index = $(this).index();
// Use the hovered index to reveal the
// dropdown-subcategory of the same index
var subcategorydiv = $(this).parent().parent().find(".dropdown-subcategory").eq(index);
hideallSubmenusExceptMenuAtIndex($(this).parent().parent(), index);
subcategorydiv.slideDown();
},
// hover off
function() {
if (!$(this).hasClass("highlighted")) {
var index = $(this).index();
var subcategorydiv = $(this).parent().parent().find(".dropdown-subcategory").eq(index);
subcategorydiv.slideUp();
}
});
// Hide all submenu items except for the submenu item at _index
// This will hide any of the previously opened submenu items
function hideallSubmenusExceptMenuAtIndex(formElement, _index) {
formElement.find(".dropdown-subcategory").each(
function(index) {
if (_index != index) {
$(this).hide();
}
}
);
}
// When any menu item is hovered
$("span").hover(
function() {
$(".hoveredOver").text($(this).text());
},
function() {
$(".hoveredOver").text("");
}
);
// When a sub-menu option is clicked
$(".dropdown-subcategory span").click(function() {
$(".dropdown-subcategory span").removeClass("selected");
$(".clickedOption").text($(this).text());
$(this).addClass("selected");
$(this).parent().parent().find(".selectHeader").text($(this).text());
closeDropDown($(this).parent().parent());
showSpecialPlateModal($(this).text(), $(this).attr("data-image"), $(this).attr("data-price"), $(this).attr("data-code"));
});
// Close the dropdowns contained in divToSearch
function closeDropDown(divToSearch) {
divToSearch.find(".drop_down_scroll_container").fadeOut();
divToSearch.find(".dropdown-subcategory").fadeOut();
};
// Populate and Launch the bootstrap Modal Dialog Specialty Plates
function showSpecialPlateModal(name, image, price, code) {
$('#modal_special').find('.modal-body')
.html('<h2>' + name + '</h2>')
.append('<br/>Special Plate Code: <span class="code">' + code + '</span><br/>')
.append('<p>Image will go here:</p><br/><img alt="" src="' + image + '"/>')
.append('<br/><br/>Price: <span class="price">' + price + '</span><br/>')
.end().modal('show');
}
// When the modal "Accept" button is pressed
$('.accept').on('click', function() {
var modal_element = $('#modal_special');
var name = modal_element.find("h2").text();
var price = modal_element.find("span.price").text();
var code = modal_element.find("span.code").text();
$('#modal_special').modal('hide').end(alert(name + " was selected for a price of " + price));
});
});
Note: There may already be some open-source solutions that take care of this problem in a more elegant fashion. But this was my approach at solving an issue like this. As you can see, it only takes a little bit of setup to get going. You can easily control the styling of the drop-down in css, and you can extend this to do anything you want.
Again, you can review a jsfiddle to see all of this code in action here.
Hope this helps!
I am not sure if this is exactly what your were looking for but you could try something like this:
<select name="SPECIAL" id="SPECIAL">
<option>Please Select</div>
<optgroup label="Environmental">
<option
data-img="/images/img/AnimalFriend.png"
value="1">AnimalFriend</option>
<option
data-img="/images/img/Aquaculture.png"
value="2">Aquaculture</option>
</optgroup>
<optgroup label="Sports">
<option
data-img="/images/img/ProtectOurOceans.png"
value="3">Protect Our Oceans</option>
<option
data-img="/images/img/ConserveWildlife.png"
value="4">Conserve Wildlife</option>
</optgroup>
</select>