I am building custom autocomplete like drop down using angular7. I have this html in my component.html
<div class="wrapper">
<div class="row mt-3">
<div class="col-6">
<input type="text" class="form-control" placeholder="text here" (keyup)="credentialsSearchFilter($event)" (blur)="hideList()" [(ngModel)]="nameDisplayModel">
</div>
</div>
<div class="row mt-2" *ngIf="records.length > 0">
<ul class="suggestion-list">
<li *ngFor="let record of records" (click)="getNameValue(record)">{{record.name}}</li>
</ul>
</div>
</div>
And in component.ts i have this code
records = [];
selectedName : string = '';
nameDisplayModel = '';
users = [
{name : 'Fahad', value :'fahad'},
{name : 'Saad', value :'saad'},
{name : 'Anus', value :'anus'},
{name : 'Hazik', value :'hazik'},
{name : 'Ahsan', value :'ahsan'},
{name : 'Sohaib', value :'sohaib'}
]
credentialsSearchFilter(event: any) {
const val = event.target.value.toLowerCase();
this.records = this.users.filter(function(d) {
return d.name.toLowerCase().indexOf(val) !== -1 || !val;
});
}
hideList(){
this.records = [];
}
getNameValue(row){
console.log('hello')
this.nameDisplayModel = row.name;
this.users.forEach(item=>{
if(item.name === row.name){
this.selectedName = row.value;
}
})
this.records = [];
console.log(this.selectedName)
}
Now i am facing 3 issues.
Issue-01
On li i want to execute getNameValue function which is not executing right now and i don't know why it's not executing.
Issue-02
in the ul below the input box when i hover on li so hover css is not applying on whole li. It only applies only the small portion of li. But i want to make hover effect on whole li element.
Issue-03
When i type anything in input so when ul displays so width of ul that shows on typing in input should be in equal width as of input box.
You can see all these 3 issues in live Stackblitz link
here
1) The blur event is executed before click
Solution: use mousedown event instead of click
2) You need to remove padding on your ul element and apply them to li element
3) You can make ul element absolutely positioned. This way it's easier to make the width of ul element to be equal width of the wrapped box with relative position.
html
<div class="autocomplete">
<input type="text" ...>
<ul *ngIf="records.length > 0" class="suggestion-list">
...
</ul>
</div>
css
.autocomplete {
position: relative;
}
.suggestion-list{
position: absolute;
top: 100%;
left: 0;
right: 0;
...
}
Forked Stackblitz
Regarding issue #1
You are never clicking on the li because you are hiding it before that. Why? Because on (blur) you are removing the array of records, and therefore the ul element is disappearing. Check this fork of your project.
You have to find your own way of preventing this from happening. The basic idea is:
If you click outside of the input field, and not in the list, hide
the list.
If you click outside of the input field, but it's in the
list, perform your action and then hide the list.
I'd solve it with some variable that flags whether the user clicked on the list or not when the input was blurred.
Regarding issue #2
That's pure CSS. You're applying the CSS effects on hover on the entire li, it's just that the ul element has padding. You can solve that removing the padding from the ul and adding it to the li, for example, but there are many other ways.
Regarding issue #3
Seems to be purely a CSS question too. I'd put them with the same parent container and give them a width of 100%, but there are dozens of ways to solve it.
Related
I have a carousel on my homepage. When the third carousel appears, the carousel buttons div class="rotator-controls" move down due to the image taking space. My goal here is to keep this div the same height as the other 4. Which means that when the <span> (index 2) of the grandchild div <div class="rotator-pagination"> is active, I apply the correct css to the <div class="rotator-controls"> (e.g. bottom:60px). As the carousel is jQuery cycle 2, when the span is active it has the class cycle-pager-active.
I have tried using domcontentloaded. i.e.
document.addEventListener("DOMContentLoaded", function() {
var span = document.querySelector("#homepage-rotator > div.banner.cycle-slide.cycle-slide-active > div > div.banner-content-area > div.rotator-controls > div.rotator-pagination").children[2];
if (jQuery(span).hasClass("cycle-pager-active")){
var grandPDiv = document.querySelector("div.rotator-controls");
grandPDiv.style.bottom = "-60px";
}
});
This does not work. But if I do this in the console, and wait for the 3rd carousel to be acitve, using jQuery(span).hasClass("cycle-pager-active") returns true.
How do i apply css (to its grandparent element) only when the span element is active?
Try this
.banner-content-area {
min-height: 440px;
}
if not work then add min-height: 440px!important;
This works perfectly:
.banner-content-area {
min-height: 440px;
}
I have this piece of code:
input type="text" name="email" id="email" value="" placeholder="" class="txt"
This is a simple input.
What I need.
Click on this input type="text" -> a drop-down select menu with several options appears (but it is still possible to write something manually into this input type="text") -> click on any option -> one of the options is inserted into the input type="text" -> click again on the input type="text" -> the same drop-down select menu with several options appears.
Please help to do this.
This can't be done with the standard form controls alone, but you can make your own. See the comments below for explanation.
// Get references to elements used
var input = document.getElementById("selectedBrowser");
var list = document.getElementById("list");
// Get all the list items into an array
var listItems = Array.prototype.slice.call(document.querySelectorAll("#list > div"));
// Make the "drop down" list the same width as the input
list.style.width = getComputedStyle(input).width;
// Set up click handler on the input
input.addEventListener("click", function(){
list.classList.remove("hidden"); // Show the list
});
// Set up input event handler on input
input.addEventListener("input", function(){
list.classList.add("hidden"); // Hide the list
});
// Loop over the list items
listItems.forEach(function(item){
// Set up a click event handler
item.addEventListener("click", function(){
input.value = item.textContent; // Copy the value into the input
list.classList.add("hidden"); // Hide the list
});
// Set up a mouseover event handler
item.addEventListener("mouseover", function(){
item.classList.add("highlight"); // Hide the list
});
// Set up a mouseout event handler
item.addEventListener("mouseout", function(){
item.classList.remove("highlight"); // Hide the list
});
});
/* Applied to the drop down list by default to hide it and
removed when the list needs to be shown. */
.hidden {
display:none;
}
#container {
display:inline-block;
vertical-align:top;
}
/* Ensures that the input will be positioned at the top-left of its parent */
#selectedBrowser {
position:absolute;
}
#list {
position:absolute; /* Position at top-left of parent */
top:1.85em; /* But, then move down to be below the input */
border:1px solid #e0e0e0;
height:5em; /* Limit height of list */
overflow-y:scroll; /* Add vertical scroll bar when list won't fit in height */
}
#list > div {
cursor:pointer;
user-select:none;
margin:2px 0;
}
.highlight {
background-color:rgba(255, 255, 0, .5);
}
<label for="selectedBrowser">Choose a browser from this list:</label>
<div id="container">
<input id="selectedBrowser" name="browser">
<div id="list" class="hidden">
<div>Chrome</div>
<div>Firefox</div>
<div>Internet Explorer</div>
<div>Opera</div>
<div>Safari</div>
<div>Microsoft Edge</div>
</div>
</div>
HTML5 has a built-in input and a datalist that renders as a combo box. You add a list attribute to the input that matches the value of the id in the datalist. An example is shown below.
<input type="text" list="items" />
<datalist id="items">
<option>Item1</option>
<option>Item2</option>
<option>Item3</option>
<option>Item4</option>
</datalist>
An issue with this solution is that it is not supported by the Apple Safari browser. W3Schools has the latest compatibility info.
If compatibility is an issue, a number of jQuery or javascript solutions are out there that may solve the problem. Here is a link to a Javascript solution that may work for you.
I am using <select> element to display a container with info. Using JQuery I display the selected container and hide the rest. In the container I have three <div> elements.
Description
Measurement in CM
Measurement in Inches.
The user has the ability to select which measurement unit to see by clicking on the different tabs. So far it all works great. It does display the info as wanted, however when I re-select different size I can not see any of the tabs info unless I click on one of them. In other words to re-create the issue:
Select size
Change the measurement units
Re-select size
Unless clicked none of the tab will show the info
To make it easier to understand I've created JSFIDDLE.
Can someone possibly have an idea how to keep the cm tab open by default even after the size was re-selected?
Try this: Its working.
http://jsfiddle.net/realdeepak/yjaoccmb/2/
$(function () {
$('#community').change(function () {
var option = $(this).find('option:selected');
var valuer = $(this).val();
$("#tabs-" + valuer).prop('checked', true);
$('#size-single1').toggle(option.hasClass('show1'));
$('#size-single2').toggle(option.hasClass('show2'));
}).change();
});
I added some new class to the input checkbox tag (.cm and .in respectively)
<div class="d-tab"><input checked="checked" id="tab-6" class="cm" name="tab-group-2" type="radio" /> <label for="tab-6"> Centimeters </label>
I also added a new function when selecting on the select size. This function to keep track which measurement is active.
$(".cm, .in").click(function(){
$(".cm, .in").removeClass("active");
if($(this).hasClass("cm")){
$(".cm").addClass("active");
else
$(".in").addClass("active");
});
Lastly I tweaked the css to show the active state
[type=radio]:checked ~ label,
.cm.active ~ label,
.in.active ~ label{
background: #dbd7d7;
z-index: 2;
}
[type=radio]:checked ~ label ~ .measurement-content,
.cm.active ~ label ~ .measurement-content,
.in.active ~ label ~ .measurement-content{
z-index: 1;
opacity: 1;
}
DEMO http://jsfiddle.net/a1jnLq49/
I have 5 divs that contain copy.
I have a back and next button, to display each div.
Back | Next
<div class="vote-result first">
this is example copy
</div>
<div class="vote-result">
this is some more copy
</div>
<div class="vote-result">
some more copy
</div>
<div class="vote-result">
this is the last div
</div>
// hide the divs, except the first one.
.vote-result { display: none; }
.vote-result.first { display: block; }
The first time the next button link is clicked, I want to remove the off class, to show it as clickable, I probably should disable the link initially too and re-enable it too.
$(".back-btn").removeClass("off");
Once I display the last div, I need to add the off class to the next-btn and disable it.
I thought about using a carousel js plugin to accomplish this, but it is overkill for now.
I know of a way to do this, but it would involve assigning subclasses to the links based on what next or back button was clicked, so it will know what div to show next, as well as removing or adding the off class to the links.
I am hoping to find a solution that allows me to add more div's to display without modifying the code. Any help is appreciated, thank you.
Here is solution for you. I have created Fiddle for your requirement.
HTML code:
<a class="back-btn off">Back</a> | <a class="next-btn">Next</a>
<div class="vote-result first selectedDiv">
this is example copy
</div>
<div class="vote-result">
this is some more copy
</div>
<div class="vote-result">
some more copy
</div>
<div class="vote-result last">
this is the last div
</div>
JS/JQuery Code:
$(".back-btn").click(function(){debugger;
var prevElement=$('.selectedDiv').prev();
prevElement.show();
$(".selectedDiv").hide();
$(".selectedDiv").removeClass("selectedDiv");
prevElement.addClass("selectedDiv");
if($('.first').css('display')=="block"){
$(".back-btn").addClass("off");
}
else{
$(".next-btn").removeClass("off");
}
});
$(".next-btn").click(function(){debugger;
var nextElement= $('.selectedDiv').next();
nextElement.show();
$(".selectedDiv").hide();
$(".selectedDiv").removeClass("selectedDiv");
nextElement.addClass("selectedDiv");
if($('.last').css('display')=="block"){
$(".next-btn").addClass("off");
}
else{
$(".back-btn").removeClass("off");
}
});
CSS code:
.vote-result { display: none; }
.vote-result.first { display: block; }
.off{display:none;}
Your HTML file:
<html>
<head>
<style>
.vote-result { display: none; }
.vote-result.first { display: block; }
.off {
color: Red;
}
a {
color: blue;
}
</style>
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="code.js"></script>
</head>
<body>
Back | Next
<div class="vote-result first">
this is example copy
</div>
<div class="vote-result">
this is some more copy
</div>
<div class="vote-result">
some more copy
</div>
<div class="vote-result">
this is the last div
</div>
</body>
</html>
Your new "code.js" file in the same directory:
/**
* The zero-based index of the <div class="vote-result"> element that is currently being shown
* #var {Number}
*/
var activeIndex = 0;
function getNumberOfItems() {
return $('.vote-result').length;
}
function synchronizeInterface() {
var numberOfItems = getNumberOfItems(),
lastIndex = numberOfItems - 1;
$('.vote-result').removeClass('first');
$('.vote-result').each(function(index) {
if (index == activeIndex) {
$(this).addClass('first');
}
})
$('.back-btn').toggleClass('off', activeIndex == 0);
$('.next-btn').toggleClass('off', activeIndex == lastIndex);
}
$(function() {
$('.back-btn,.next-btn').on('click', function() {
// If the button clicked is not deactivated
if (!$(this).hasClass('off')) {
// Determine whether the "Next" button was clicked (otherwise "Back" was clicked)
var clickedNext = $(this).hasClass('next-btn');
// Move the active index in the appropriate direction while not allowing it to fall outside the boundaries of appropriate indices
activeIndex = clickedNext
? Math.min(activeIndex + 1, getNumberOfItems() - 1)
: activeIndex = Math.max(0, activeIndex - 1);
// Make sure the interface now reflects the updated JavaScript variables
synchronizeInterface();
}
return false;
});
});
Some notes: You had an unclosed double-quote for one of your class attributes in your provided HTML. Also, I added some additional styling -- you may want to rename the ".first" CSS class to ".active" instead.
take a look at jquerys .next() function for navigating - jQuery - Next(). you can also check for the last item like this.
if($(this).is(':last-child'))
{
$('.next-btn').removeClass('off');
}else{
$('.next-btn').addClass('off');
}
check everytime a navigation button is clicked and do the same for the first button
I am currently building a menu bar that consists of icons that show a contextual submenu when hovered over. Essentially, when hovering over an icon a popup menu/tooltip appears (with more options), but the icon itself should be clickable as well.
So far, I use the following HTML construct and jQuery for each menu item:
<div id="profile" class="menu-item">
<div id="profile-tip" class="tip">
**insert profile menu options**
</div>
</div>
<div id="search" class="menu-item">
<div id="search-tip" class="tip">
**insert search menu options**
</div>
</div>
and
$(".menu-item").hover(function() {
$(this).find("div").fadeIn("fast").show(); //add 'show()'' for IE
$(this).mouseleave(function () { //hide tooltip when the mouse moves off of the element
$(this).find("div").hide();
});
});
What I wish to do is to change the HTML to look as follows (so I can apply an onClick link to the "profiles" div):
<div id="profile" class="menu-item" onclick="window.location = 'profile.php'"></div>
<div id="profile-tip" class="tip">
**insert menu options**
</div>
However, I don't know how to modify the jQuery to find the matching div to display when hovered over. The associated tooltip/popup menu div will always be xxxx-tip (where xxx is the name of the parent div).
As an example, I imagine it will look something like this (keep in mind I know very little about jQuery so I'm well aware this will look stupid):
$(".menu-item").hover(function() {
$.find("div").attr('id'+"-tip").fadeIn("fast").show(); //add 'show()'' for IE
$(this).mouseleave(function () { //hide tooltip when the mouse moves off of the element
$.find("div").attr('id'+"-tip").hide();
});
});
To summarise: I need the jQuery modified to show the div based on the parent div's ID + the string "-tip"
Hopefully that isn't too confusing. Any help GREATLY appreciated :)
Not sure I understand completely what you want, but maybe try something a little more like this:
$(".menu-item").hover(
function() {
$(this).find(".tip").fadeIn("fast").show(); //add 'show()'' for IE
},
function() { //hide tooltip when the mouse moves off of the element
$(this).find(".tip").hide();
}
);
Edit: If the tip element is not a child of the menu item div, this could work:
$(".menu-item").hover(
function() {
$('#' + this.id + '-tip').fadeIn("fast").show(); //add 'show()'' for IE
},
function() { //hide tooltip when the mouse moves off of the element
$('#' + this.id + '-tip').hide();
}
);
Instead of finding the name of the div in the PARENT of the thing you're hovered over, use jQuery to find the tooltip that is a CHILD of the thing you're hovered over...search down the DOM, instead of UP.
Use jQuery's $(this) operator...
$('.menu-item').hover(function(){
$(this).find('.tip).fadeIn();
},
function() {
$(this).find('.tip).fadeOut();
});
I'm not 100% clear on the goal here but you can get your div by ID as shown here:
$(".menu-item").hover(function()
{
$(this).find(".tip").fadeIn("fast").show();
});
Or in CSS:
.menu-item .tip
{
display: none;
}
.menu-item .tip:hover,
.menu-item:hover .tip
{
display: auto;
}