Focusout with autocomplete - javascript

I'm trying to figure out how to direct the focus on these objects to get auto complete to go away when it's not needed.
I'll post the code and then explain what I've tried. The only issue with writing too much is that it scares some people away so I'll be brief yet thorough!
This is the library I'm using http://complete-ly.appspot.com/
jQuery
var autocontainer = link.siblings('.food-input-div');
autocontainer.show();
link.hide();
var autoobj = completely(autocontainer[0]);
autoobj.options = ['chicken', 'cheese', 'chobani', 'chocolate', 'chum', 'cherries', 'coka-cola', 'coconut', 'crack', 'cocain', 'creme brule'];
autoobj.repaint();
autoobj.input.focus();
var wrapper = $(autoobj.wrapper);
console.log(wrapper);
console.log(document.activeElement);
wrapper.attr("tabindex", "0");
wrapper.focusout(function() {
autocontainer.hide();
link.show();
this.remove();
});
The DOM
<td class="left">
<a class="add-food-link">+ Add food</a>
<div class="food-input-div" style="display:none;"></div>
</td>
Complete.ly adds code similar to this directly inside the 'food-input-div' element
<div>
<div>
<input>
<input>
<div>
<div>list item</div>
<div>list item</div>
<div>list item</div>
<div>list item</div>
</div>
</div>
</div>
My jQuery gives the first 'wrapper' element of complelys code a tabindex of 0 so that it is able to having a focus.
The issue is this:
When I click the link:
Link is removed
completely box is rendered
completely wrapper input has focus
When a item from the dropdown is clicked:
Everything is removed and link is rendered
I don't understand why this is happening because focusout is bound to those individual element's parent element.
I toyed around with the assumption that children elements receive focus here and found that is false. http://jsfiddle.net/adiakritos/nU988/
So now I need to get it so that only when ANY element outside of "food-input-div" is clicked, said element and it's children are removed, and the link is redisplayed.
How do I do this?
Playing with this right now:
Use jQuery to hide a DIV when the user clicks outside of it
This is the code I have working nicely right now. Except I still can't click list items.
$(document).mouseup(function (e){
if (!wrapper.is(e.target) && wrapper.has(e.target).length === 0){
autocontainer.hide();
link.show();
autoobj.wrapper.remove();
console.log(e);
};
});
Now when I get click the drop down e.target returns the element directly under the div I'm clicking.
So if I click "cheese" and there's a h4 element that is part of the layout under it, e.target returns that h4 instead of the drop down div list item.
Implementing Dropped.On.Caprica's Code
var showFoodSearch = function(link) {
var autocontainer = link.siblings('.food-input-div');
autocontainer.show();
link.hide();
var autoobj = completely(autocontainer[0]);
autoobj.options = ['chicken', 'cheese', 'chobani', 'chocolate', 'chum', 'cherries', 'coka-cola', 'coconut', 'crack', 'cocain', 'creme brule'];
autoobj.repaint();
autoobj.input.focus();
var wrapper = $(autoobj.wrapper);
wrapper.on('blur', 'input', function(){
autocontainer.hide();
link.show();
autoobj.wrapper.remove();
$(document).mouseup(function(e){
console.log(e.target);
});
});
};
Same exact behavior as described above this try.

This is how I got the JS to work exactly how I wanted it to:
var autocontainer = link.siblings('.autocomplete');
autocontainer.show();
link.hide();
var autoobj = completely(autocontainer[0]);
autoobj.options = ['chicken', 'cheese', 'chobani', 'chocolate', 'chum', 'cherries', 'coka-cola', 'coconut', 'crack', 'cocain', 'creme brule'];
autoobj.repaint();
autoobj.input.focus();
var wrapper = $(autoobj.wrapper);
$(document).click(function() {
var focus = document.activeElement;
if ( focus === document.body ) {
autocontainer.hide();
link.show();
autoobj.wrapper.remove();
}
});
The $(document).click(function() { part checks for any clicks to the main doc element... then it determines what the focus is... if it's on the body (where users normally click to close out of something) it'll hide the drop down.

Related

Use XPath or onClick or onblur to select an element and use jQuery to blur this element

*UPDATE:I am new to jQuery, as well as using XPath, and I am struggling with getting a proper working solution that will blur a dynamically created HTML element. I have an .onblur event hooked up (doesn't work as expected), and have tried using the $(document.activeElement), but my implementation might be incorrect. I would appreciate any help in creating a working solution, that will blur this element (jqInput) when a user clicks anywhere outside the active element. I have added the HTML and jQuery/JavaScript below.
Some ideas I have had:
(1) Use XPath to select a dynamic HTML element (jqInput), and then use jQuery's .onClick method to blur a this element, when a user clicks anywhere outside of the area of the XPath selected element.
(2) Use the $(document.activeElement) to determine where the .onblur should fire:
var thisTitle = input0;
var activeElement = $(document.activeElement);
if (thisTitle != activeElement) {
jqInput.hide();
_layout.viewHeaderTextInput.inputOnBlurHandler(canvasObj, jqHeaderText, jqInput);
}
I am open to all working solutions. And hopefully this will answer someone else's question in the future.
My challenge: Multiple elements are active, and the .onblur does not fire. See the image below:
NOTE: The <input /> field has focus, as well as the <div> to the left of the (the blue outline). If a user clicks anywhere outside that <input />, the blur must be applied to that element.
My Code: jQuery and JavaScript
This is a code snippet where the variable jqInput and input0 is created:
var jqInput = null;
if (jqHeaderText.next().hasClass("inline-editable"))
{
//Use existing input if it already exists
jqInput = jqHeaderText.next();
}
else
{
//Creaet a new editable header text input
jqInput = $("<input class=\"inline-editable\" type=\"text\"/>").insertAfter(jqHeaderText);
}
var input0 = jqInput.get(0);
//Assign key down event for the input when user preses enter to complete entering of the text
input0.onkeydown = function (e)
{
if (e.keyCode === 13)
{
jqInput.trigger("blur");
e.preventDefault();
e.stopPropagation();
}
};
This is my .onblur event, and my helper method to blur the element:
input0.onblur = function ()
{
_layout.viewHeaderTextInput.inputOnBlurHandler(canvasObj, jqHeaderText, jqInput);
};
inputOnBlurHandler: function (canvasObj, jqHeaderText, jqInput)
{
// Hide input textbox
jqInput.hide();
// Store the value in the canvas
canvasObj.headingText = jqInput.val();
_layout.updateCanvasControlProperty(canvasObj.instanceid, "Title", canvasObj.headingText, canvasObj.headingText);
// Show header element
jqHeaderText.show();
_layout.$propertiesContent.find(".propertyGridEditWrapper").filter(function ()
{
return $(this).data("propertyName") === "Title";
}).find("input[type=text]").val(canvasObj.headingText); // Update the property grid title input element
}
I have tried using the active element, but I don't think the implementation is correct:
var thisTitle = input0;
var activeElement = $(document.activeElement);
if (thisTitle != activeElement) {
jqInput.hide();
_layout.viewHeaderTextInput.inputOnBlurHandler(canvasObj, jqHeaderText, jqInput);
}
My HTML code:
<div class="panel-header-c">
<div class="panel-header-wrapper">
<div class="panel-header-text" style="display: none;">(Enter View Title)</div><input class="inline-editable" type="text" style="display: block;"><div class="panel-header-controls">
<span></span>
</div>
</div>
</div>
I thank you all in advance.

JavaScript - Apply if-statement to node-list / multiple elements instead of just one

I am trying to see whether an element with an .editable class is clicked on, in that case I want to return false. As you can see in the runnable example, I managed to hard-code a working solution.
However, it works only with the first node in the editableElements list, that is because I do not know how to do the equivalent of $(editableElements).contains(...), i.e. filtering through multiple nodes in an if-statement.
I'd appreciate any help.
var elements = document.querySelectorAll('.accordion-item');
Array.prototype.forEach.call(elements, function(el, i) {
// onclick handler
elements[i].onclick = function(e) {
var editableElements = document.querySelectorAll(".editable");
// This line works fine with selecting the first element of editableElements node list:
if (e.target == editableElements[0] || editableElements[0].contains(e.target)) {
// But I want something more like this, containing all elements:
// if (e.target == editableElements || editableElements.contains(e.target))
return false;
}
alert("proceeding as usual");
};
});
<div class="accordion">
<div class="accordion-item">
Click me
</div>
<div class="accordion-item">
Click me
<div class="editable">Click me and nothing happens 1</div>
<div class="editable">Click me and nothing happens 2 <i>(not working because node element 1 is hard-coded)</i></div>
</div>
</div>

Click outside an element doesn't work

I have this code:
function showAll(el){
var id = el.parentNode.id;
var all= document.getElementById(id).getElementsByClassName('items')[0];
if(all.style.display === 'block'){
all.style.display = 'none';
} else{
all.style.display = 'block';
window.addEventListener('mouseup', function(e){
document.getElementById('test').innerHTML = e.target.className;
if(e.target != all){
all.style.display = 'none';
}
});
}
}
<div id="parent">
<div class="selected" onClick="showAll(this);">
</div>
<div class="items" style="display: none">
</div>
</div>
Basically what i want to achieve is: click on selected to display items which is now hidden after that if i click again on selected or if i click outside of items(a random spot on that page or even on selected) i want to be able to hide items.
The problem is that without the EventListener when i click on selected it works to display items and then if i click again on selected it works to hide items but if i click on a random spot it doesn't work to close items.
But when i add EventListener and i click on selected it works to click a random spot to close items but it doesn't work to click selected again to close items.
Can anybody help me with a full JavaScript explanation, please?
You're going to want to use highly reusable code. I use change() and id_() on my web platform all of the time and it's very direct and simple. In the below example the second parameter will make the class empty (you can also use id_('items').removeAttribute('class') for a cleaner DOM (Document Object Model)).
HTML
<input onclick="change(id_('items','');" type="button" value="Display Items" />
<div clas="hidden" id="items"><p>Items here.</p></div>
CSS
.hidden {display: none;}
JavaScript
function change(id,c)
{
if (id_(id)) {id_(id).className = c; if (id_(id).className=='') {id_(id).removeAttribute('class');}}
else if (id) {id.className = c; if (id.className=='') {id.removeAttribute('class');}}
else {alert('Error: the class id \''+id+'\' was not found or has not yet been imported to the DOM.\n\nNew class intended: '+c);}
}
function id_(id)
{
if (id == '' && window['console']) {console.log('Developer: empty id called from: '+id_.caller.toString().split('function ')[1].split('(')[0]);}
return (document.getElementById(id)) ? document.getElementById(id) : false;
}
This code exists from years of refining the same platform instead of industry standard drama of pointlessly changing things. You are two clicks from finding more highly reusable functions on my platform's JavaScript documentation from the link in my profile.

remove onclick when attached to children

I have the following code:
layoutOverlaysBldg = $("#layout-overlays-bldg")
layoutOverlaysBldg.on("click", "div", function(event) {
var floor;
console.log("floornum: " + this.dataset.floornum);
floor = parseInt(this.dataset.floornum);
...
$("#choose-floor").fadeOut();
$("#choose-apt").fadeIn();
});
later - based on data I'm getting back from the DB - I want to remove some of the .on("click", "div", ...) from only some of the divs. I already have the selector that is getting the right divs but I cannot figure out how to remove the click event. I have tried .off("click") after selecting the right div but it has no effect.
This issue here is because you are using a delegated event. You can add or remove the event for all child elements, but not individual ones given your div selector.
With that in mind the easiest way to do what you need is to add the event based on a class, then add and remove that class on the children as needed. Something like this:
layoutOverlaysBldg = $("#layout-overlays-bldg")
layoutOverlaysBldg.on("click", "div.clickable", function(event) {
// your code...
});
You can then enable/disable the event on the child div by adding or removing the .clickable class.
You can try like this :
Example :
<div id="test">
<div id="first">first</div>
<div id="second">second</div>
</div>
<div onclick="unbindSecondDiv();">UNBIND</div>
<script>
function unbindSecondDiv()
{
test = $("#second")
test.unbind("click");
alert('Selected Area Click is Unbind');
}
$(document).ready(function(){
//BIND SELECTED DIV CLICK EVENT
test = $("#test > div")
test.bind("click" , function(event) {
alert($(this).attr('id'));
});
});
</script>
In the above example , selected DIV elements click event is bind.
And after execute function unbindSecondDiv() , second DIV click event will be unbind.
Have a try , may helps you.

Changing content of a div with Prototype or JavaScript

I have this code :
<div class="box_container">
<div class="box_container_button" id="navigator_1">
Button 1
</div>
<div class="box_container_button" id="navigator_2">
Button 2
</div>
<div class="box_container_button" id="navigator_3">
Button 3
</div>
<div class="box_container_content" style="background-color:#d5d5d5;" id="navigator_content_1">
Content 1
</div>
<div class="box_container_content" style="background-color:#00aeef; display:none;" id="navigator_content_2">
Content 2
</div>
<div class="box_container_content" style="background-color:#4db848; display:none;" id="navigator_content_3">
Content 3
</div>
</div>
If I press on the button with navigator_2, navigator_content_1 must be hidden, and navigator_content_2 showed.
How can I do this with prototype? (Or javascript if it's too stronger). Unfortunatly I can't use jQuery.
Try this
function nav(obj)
{
document.getElementById("navigator_content_1").style.display = "hidden"
document.getElementById("navigator_content_2").style.display = "hidden"
document.getElementById("navigator_content_3").style.display = "hidden"
obj.style.display = "none";
}
Add onclick="nav(this)" to each button element.
Here is my suggestion:
Give the container holding the buttons in ID (for convenience).
Change the IDs of the content containers from navigator_content_1 to navigator_1_content (again, for convenience).
Then all you have to do is to keep a reference to the currently showed content pane and you have to attach a click handler to the container holding the buttons:
// by default, the first panel is shown
var current = document.getElementById('navigator_1_content');
document.getElementById('box_container').onclick = function(event) {
event = event || window.event; // for IE
var target = event.target || event.srcElement; // for IE
current.style.display = 'none';
current = document.getElementById(target.id + '_content');
current.style.display = 'block';
};
This makes use of event bubbling. event.target has a reference to the element that was actually clicked (I don't know if the Safari bug is still present, you might have to traverse the DOM up to find the correct element). This can certainly be improved but should give you a good start. You can easily add new buttons / content panels without having to modify the code.
Here is a DEMO.
To learn more about event handling, I suggest to have a look at the excellent articles at quirksmode.org
This would use prototype and get what you want
$$('.box_container_button').each(function(element) {
element.observe('click', function(event) {
$$('.box_container_content').each(function(element) {
element.setStyle({
'display': 'none'
});
});
$('navigator_content_' + this.id.replace("navigator_", "")).setStyle({
'display': 'block'
});
});
});
http://jsfiddle.net/VENLh/
THIS solution would work even if you add more buttons / contents without changing any line in the javascript (just add the html part!)

Categories

Resources