Alrighty, I'm stuck.
I'm trying desperately to focus on a text area programmatically from javascript (jQuery) on mobile. I did my research, and learned that the only way to bring the keyboard up with .focus() is to use a click event. So I made a click event. And it works when I click on the element, except I need to trigger this from a touchhold on a different element. So naturally, I tried .trigger() and .triggerHandler() on the element. But neither of those things work.
TLDR; I need to be able to hold on an element from a list, and after a time, a div will slide down with a textarea and the textarea gets focus (with keyboard).
Any help is appreciated!
Here is my code:
<div class="quicknote" data-id="0">
<span>New Note</span>
<div class="name"></div>
<textarea class="text"></textarea>
<div class="toolbar">
<div class="left cancel">cancel</div>
<div class="right finish">finish</div>
</div>
</div>
jQuery
jQuery(document).ready(function($) {
var holdThresh = 800;
$(".row").on("touchstart", function(e) {
var id = $(this).attr("data-id");
var name = $(this).html();
$(this).addClass("down");
var timer = setTimeout(function() {
$(".quicknote").attr("data-id", id);
$(".quicknote .name").html(name);
$(".quicknote").addClass("open");
$(".quicknote").trigger("click");
e.preventDefault();
}, holdThresh);
$(this).one("touchend touchmove", function(event) {
$(this).removeClass("down");
clearTimeout(timer);
})
$(".quicknote .cancel").on("touchstart", function() {
$(".quicknote").removeClass("open");
})
$(".quicknote").click(function(event) {
$("textarea").focus();
event.preventDefault();
event.stopPropogation();
})
});
I figured it out! For anyone who finds this, here is my updated jQuery:
$(".row").on("touchstart", function(e) {
var id = $(this).attr("data-id");
var name = $(this).html();
var go = true;
var focus = false;
$(this).addClass("down");
var timer = setTimeout(function() {
go = false;
$(".quicknote").attr("data-id", id);
$(".quicknote .name").html(name);
$(".note").val("");
$(".quicknote, .overlay").addClass("open");
focus = true;
e.preventDefault();
}, holdThresh);
$(this).one("touchmove", function(event) {
go = false;
$(this).removeClass("down");
clearTimeout(timer);
});
$(this).one("touchend", function() {
if (go) window.location = "view.php?id=" + id;
else {
if (focus) {
$(".note").focus();
focus = false;
}
$(this).removeClass("down");
clearTimeout(timer);
}
})
})
I'm not sure exactly why this works, but instead of triggering a click on a third element to then focus on the textarea, I set a flag "var focus", and based on some conditions, was able to focus the textarea from the touchend event. Hope this helps someone! :)
Related
I want to be able to ckick on the h2 in the .editable div and it should change into an input box. Then you can edit it and it will updat the input when you click out of it or press enter. This is what I have for it, i'm stuck:
jQuery:
$('.editable').on('click', function() {
var h3 = $(this)
var input = $('<input>').val(h3.text())
h3.after(input)
h3.hide()
input.on('blur', function(){
})
//blur
//keyup code 13 -- code 27 reset
})
jade: (petty much html)
div.edit-menu-page
div.title
h2 Edit Menu
div.menu-wrap
div.menu-category
div.menu-title
div.editable
h3 Meat
div.menu-items
div.menu-row
span.item-description New York Striploin
div.control-items
span.item-price 10$
span.delete X
.
Basically what you want to do is place a form element next to the original element, then when you're done, replace the form element with the original element.
Something like this should work:
$(document).on('click', '.editable', function() {
var $wrapper = $('<div class="editing"></div>'),
$form = $('<form action="#" class="edit-form"></form>'),
$input = $('<input type="text">');
// Place the original element inside a wrapper:
$(this).after($wrapper);
$(this).remove().appendTo($wrapper).hide();
// Build up the form:
$wrapper.append($form);
$form.append($input);
$input.val($(this).text()).focus();
});
$(document).on('submit', '.edit-form', function(e) {
// Don't actually submit the form:
e.preventDefault();
var val = $(this).find('input').val(),
$wrapper = $(this).parent(),
$original = $wrapper.children().first();
// Use text() instead of html() to prevent unwanted effects.
$original.text(val);
$original.remove();
$wrapper.after($original);
$original.show();
$wrapper.remove();
});
Edit: Here's the JSFiddle: http://jsfiddle.net/c0fb11qw/1/
<div contenteditable="true">
This text can be edited by the user.
</div>
full info: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content
Here is a quick answer for you, http://codepen.io/someyoungideas/pen/mJWLXE. Looks like Jade doesn't play too nice with jQuery with the way your input works because it adds some spacing in the input.
$('.editable').on('click', function() {
var h3 = $(this)
var input = $('<input>').val(h3.text())
h3.after(input)
h3.hide()
input.on('blur', function(){
h3.text(input.val());
h3.show();
input.hide();
})
//blur
//keyup code 13 -- code 27 reset
})
Here is what you need:
Working JsFiddler: https://jsfiddle.net/t0hjxxgy/
HTML
<div class="editable">
<h3>Edit me</h3>
</div>
JS
$('.editable').on('click', function() {
var $editable = $(this);
if($editable.data("editing")) {
return;
}
$editable.data("editing", true);
var h3 = $("h3", this);
var input = $('<input />').val(h3.text())
h3.after(input);
h3.hide();
input.on('blur', function(){
save();
})
input.on('keyup', function(e){
if (e.keyCode == '13') {
save();
}
if (e.keyCode == '27') {
reset();
}
})
function save() {
h3.text(input.val());
input.remove();
h3.show();
$editable.data("editing", false);
}
function reset () {
input.remove();
h3.show();
$editable.data("editing", false);
}
})
What I want to do is to toggle an element when I click on a button. I have more buttons that trigger the toggle event. What is comes tricky a bit is if the div is already shown, is toggles to invisible than shown again. The point of this is that the element to be shown hold information generated by ajax.
I've made it to the point when this works, but the event chain is finished only if I click on the first button even clicked.
Here's the HTML:
<div class="row">
<button id="classOption1" class="btn btn-primary toggleOptions">firstButton</button>
<button id="classOption2" class="btn btn-primary toggleOptions">secondBotton</button>
<button id="classOption3" class="btn btn-primary toggleOptions">thirdButton</button>
<button id="classOption4" class="btn btn-primary toggleOptions">yet another button</button>
</div>
<div class="classOptions">
//some irrelevant HTML here
</div>
$(".toggleOptions").click(function(){
var trigger = $(".toggleOptions").attr('id');
if (trigger != $(this).attr('id')) {
$(".classOptions").toggle(1000).promise().done(function() {
trigger = $(this).attr('id');
});
$(".classOptions").toggle(1000);
} else {
$(".classOptions").toggle(1000).promise().done(function() {
trigger = $(this).attr('id');
});
}
});
If I click first on firstButton, then on secondButton, it works. But if I click again on secondButton to hide the element, is just hides and show again. However, if I click on firstButton again, it hides element as intended.
JsFiddle reproduction code.
I hope I made myself understand-able, not my first language.
Remove this code $(".classOptions").toggle(1000); from your solution.
$(".toggleOptions").click(function(){
var trigger = $(".toggleOptions").attr('id');
if (trigger != $(this).attr('id')) {
$(".classOptions").toggle(1000).promise().done(function() {
trigger = $(this).attr('id');
});
} else {
$(".classOptions").toggle(1000).promise().done(function() {
trigger = $(this).attr('id');
});
}
});
As I understood:
...what I want to do is to toggle an element when I click on a
button....
...is comes tricky a bit is if the div is already shown,
is toggles to invisible than shown again...
In this case you can change your selector to know if the element is visible or not like this:
var isVisible = $(".classOptions:visible").length > 0;
And if you want to make the div "blink" when already hidden just test it:
$(".toggleOptions").click(function(){
var isVisible = $(".classOptions:visible").length > 0;
$(".classOptions").toggle(1000);
if(!isVisible){
$(".classOptions").toggle(1000);
}
});
Sorry if I didn't understand you clearly.
JSFiddle reproduction
Just found the proper way, here's the code:
$( document ).ready(function() {
var selector;
var lastSelector = null;
$(".toggleOptions").click(function(){
selector = $(this).attr('id');
if(lastSelector != selector && lastSelector != null){ //different button clicked or page just loaded
if($(".classOptions").is(":visible")){ // element is shown, so we hide and show again
$(".classOptions").toggle(1000); // toggle to invisible
$(".classOptions").toggle(1000).promise().done(function() {
lastSelector = selector;
});
} else { // element is hidden, just show it
$(".classOptions").toggle(1000).promise().done(function() {
lastSelector = selector;
});
}
}
if(lastSelector == selector || lastSelector == null){ // same button pressed twice, toggle as intended
$(".classOptions").toggle(1000).promise().done(function() {
lastSelector = selector;
});
}
$("#lastSelector").text("Last Selector: " + lastSelector);
$("#thisSelector").text("Just Clicked: " + selector);
});
});
http://jsfiddle.net/3qjeqqkk/32/
Thanks guys for help! Shame I can't vote up.
I am trying to prepare a custom dropdown control for my application. The requirement goes here.
Main Flow:
If i click on the textbox, a div opens and user need to select a item from the div. the selected item needs to be filled into the textbox.
Alternate Flow : If the user clicks on the textbox and later clicks on somewhere on the screen except the dropdown div, the dropdown div should close.
I am able to achieve the main flow easily. I am unable to script code for the alternate flow i have mentioned. I have tried the simple blur event, it didnt work.
Please help me solve the issue.
HTML
<input type="text" class="display-none food-textbox" id="txtFood" value="None"/>
<div class="food-dropdown display-none">
<div class="food-item">Curled Spinach</div>
<div class="food-item">Veg Mayo</div>
<div class="food-item">French Toast</div>
<input type="hidden" id="hdnFoodTargetTxt"/>
</div>
jQuery Code:
$('.food-textbox').on('click', function () {
var positionOfTb = $(this).offset();
var widthofTb = $(this).width();
$('.food-dropdown').removeClass('display-none').offset({ top: positionOfTb.top, left: positionOfTb.left }).css('width', widthofTb + 10);
$('.food-dropdown').focus();
$('#hdnFoodTargetTxt').val($(this).attr('id'));
});
$('.food-item').on('click', function () {
var targetTxt = '#' + $('#hdnFoodTargetTxt').val();
$(targetTxt).val($(this).html());
$(targetTxt).next().eq(0).val($(this).html());
$('.food-dropdown').addClass('display-none');
});
You can stop the click propagation using stopPropagation and add a click handler on the document to close the opened dropdown.
Code:
$('.food-textbox').on('click', function (e) {
e.stopPropagation();
var positionOfTb = $(this).offset();
var widthofTb = $(this).width();
$('.food-dropdown').removeClass('display-none').offset({ top: positionOfTb.top, left: positionOfTb.left }).css('width', widthofTb + 10);
$('.food-dropdown').focus();
$('#hdnFoodTargetTxt').val($(this).attr('id'));
});
$('.food-item').on('click', function (e) {
e.stopPropagation();
var targetTxt = '#' + $('#hdnFoodTargetTxt').val();
$(targetTxt).val($(this).html());
$(targetTxt).next().eq(0).val($(this).html());
$('.food-dropdown').addClass('display-none');
});
$(document).on('click', function () {
$('.food-dropdown').addClass('display-none');
});
Demo: http://jsfiddle.net/IrvinDominin/PKndL/
When user clicks on input field, two consecutive events are being executed: focus and click.
focus always gets executed first and shows the notice. But click which runs immediately after focus hides the notice. I only have this problem when input field is not focused and both events get executed consecutively.
I'm looking for the clean solution which can help me to implement such functionality (without any timeouts or weird hacks).
HTML:
<label for="example">Example input: </label>
<input type="text" id="example" name="example" />
<p id="notice" class="hide">This text could show when focus, hide when blur and toggle show/hide when click.</p>
JavaScript:
$('#example').on('focus', _onFocus)
.on('blur', _onBlur)
.on('click', _onClick);
function _onFocus(e) {
console.log('focus');
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
$('#notice').removeClass('hide');
}
function _onClick(e) {
console.log('click');
$('#notice').toggleClass('hide');
}
function _onBlur(e) {
console.log('blur');
$('#notice').addClass('hide');
}
UPDATED Fiddle is here:
I think you jumbled up the toggles. No need to prevent propagation and all that. Just check if the notice is already visible when click fires.
Demo: http://jsfiddle.net/3Bev4/13/
Code:
var $notice = $('#notice'); // cache the notice
function _onFocus(e) {
console.log('focus');
$notice.removeClass('hide'); // on focus show it
}
function _onClick(e) {
console.log('click');
if ($notice.is('hidden')) { // on click check if already visible
$notice.removeClass('hide'); // if not then show it
}
}
function _onBlur(e) {
console.log('blur');
$notice.addClass('hide'); // on blur hide it
}
Hope that helps.
Update: based on OP's clarification on click toggling:
Just cache the focus event in a state variable and then based on the state either show the notice or toggle the class.
Demo 2: http://jsfiddle.net/3Bev4/19/
Updated code:
var $notice = $('#notice'), isfocus = false;
function _onFocus(e) {
isFocus = true; // cache the state of focus
$notice.removeClass('hide');
}
function _onClick(e) {
if (isFocus) { // if focus was fired, show/hide based on visibility
if ($notice.is('hidden')) { $notice.removeClass('hide'); }
isFocus = false; // reset the cached state for future
} else {
$notice.toggleClass('hide'); // toggle if there is only click while focussed
}
}
Update 2: based on OP's observation on first click after tab focus:
On second thought, can you just bind the mousedown or mouseup instead of click? That will not fire the focus.
Demo 3: http://jsfiddle.net/3Bev4/24/
Updated code:
$('#example').on('focus', _onFocus)
.on('blur', _onBlur)
.on('mousedown', _onClick);
var $notice = $('#notice');
function _onFocus(e) { $notice.removeClass('hide'); }
function _onClick(e) { $notice.toggleClass('hide'); }
function _onBlur(e) { $notice.addClass('hide'); }
Does that work for you?
Setting a variable for "focus" seems to do the trick : http://jsfiddle.net/3Bev4/9/
Javascript:
$('#example').on('focus', _onFocus)
.on('click', _onClick)
.on('blur', _onBlur);
focus = false;
function _onFocus(e) {
console.log('focus');
$('#notice').removeClass('hide');
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
focus = true;
}
function _onClick(e) {
console.log('click');
if (!focus) {
$('#notice').toggleClass('hide');
} else {
focus = false;
}
}
function _onBlur(e) {
console.log('blur');
$('#notice').addClass('hide');
}
If you want to hide the notice onBlur, surely it needs to be:
function _onBlur(e) {
console.log('blur');
$('#notice').addClass('hide'); // Add the hidden class, not remove it
}
When doing this in the fiddle, it seemed to fix it.
The code you have written is correct, except that you have to replae $('#notice').removeClass('hide'); with $('#notice').addClass('hide');
Because onBlur you want to hide so add hide class, instead you are removing the "hide" calss.
I hope this is what the mistake you have done.
Correct if I am wrong, Because I don't know JQuery much, I just know JavaScript.
you can use many jQuery methods rather than add or move class:
Update: add a params to deal with the click function
http://jsfiddle.net/3Bev4/23/
var showNotice = false;
$('#example').focus(function(){
$('#notice').show();
showNotice = true;
}).click(function(){
if(showNotice){
$('#notice').show();
showNotice = false;
}else{
showNotice = true;
$('#notice').hide();
}
}).blur(function(){
$('#notice').hide();
});
I'm writing a simple jQuery plugin that will dynamically place a div under a text box whenever it has focus. I've been able to get the position just about right in all the browsers.
I have to attach two event handlers as well on the focus and blur events of the textbox. And it works okay, but the problem is that the div that has been placed under the textbox closes even when we click on it. Now it makes sense why it would so happen, it's because the textbox loses focus, but is there a way I can stop it from happening?
I tried attaching this to the blur event handler -
if($(mainElem).is(":focus")) return;
where mainElem is the div that is shown below the textbox.
Here is a jsFiddle to illustrate the problem.
You are not going to be able to use the blur event if you want to place "clickable" elements in the div that shows. One way to solve this is to bind your event listener to a more global element like the document and then filter out the targets.
Here is a code sample:
$(document).on('click', function (e) {
var targetEl = e.target,
parent = $(e.target).parents()[0];
if (relElem[0] === targetEl || self[0] === targetEl || self[0] === parent) {
$(mainElem).show();
} else {
$(mainElem).hide();
}
});
Here is an update to your fiddle: http://jsfiddle.net/9YHKW/6/
This is a fiddle that I threw together for a project a while back: http://jsfiddle.net/MYcZx/4/
While it is not based off of your fiddle (and I do apologize) I believe that the functionality is much the same as what you're looking for. My example does not include input fields, but rather spans that hold the values. And while I'm not managing focus/blur, you could add a tabIndex attribute to the spans and then add a trigger on focus that would open the menu.
var $sub = $('.subscription');
$sub
.on('click', '.remove', function() {
$(this).parent().remove();
})
.on('click', 'li', function(e) {
var $this = $(this),
$parent = $this.parent(),
$options = $parent.children('li'),
$value = $parent.siblings('.value'),
isMulti = $parent.hasClass('multi'),
values = [];
if(!isMulti) {
$options.removeClass('active');
}
$this.toggleClass('active');
$options.filter('.active').each(function() {
values.push($(this).text());
});
$value.text(values.join(', ') || 'select');
$value[(values.length ? 'add' : 'remove') + 'Class']('set');
});
var $clone = $sub.clone(true);
$('.new')
.on('click', function() {
$(this).before($clone.clone(true));
});