Knockout JS - how to detect element that triggered blur? - javascript

I'm trying to update an input value on conditional blur in Knockout - basically I want the element not to trigger a value update when a specific element triggers the blur. I know I can watch mousedown on every element on the document and determine what was last clicked, but seems a bit excessive. Any other work around anyone can think of?
<input class="edit" data-bind="value: title, valueUpdate: 'afterkeydown', enterKey: $root.stopEditing, selected: editing, event: { blur: $root.checkEditing }">
The code I was trying to achieve to pull this off isn't working with document.activeElement.
self.checkEditing = function( item, event ) {
if (document.activeElement == $('a.cancel')) {
// revert to previous title, aka cancel the editing
item.title(item.previousTitle);
item.editing( false );
} else {
// this will update value with whatever was typed right before the blur
item.editing( false );
if ( !item.title().trim() ) {
self.remove( item );
}
}
};

Looks like to appropriately capture the element that has triggered the blur, setTimeout has to be used. After the blur is processed, setTimeout ensures that the focused element has become available.
For example:
The input:
<input class="edit" data-bind="value: title, valueUpdate: 'afterkeydown', selected: editing, event: { blur: $root.checkEditing, click: $root.editItem }">
The method that checks the active element after blur:
self.checkEditing = function( item, event ) {
setTimeout(function(){
console.log("The active element is: " + document.activeElement)
// check if the user selected cancel
if ($(document.activeElement).is("a.cancel")) {
// revert to previous title
item.title(item.previousTitle);
}
});
item.editing( false );
if ( !item.title().trim() ) {
self.remove( item );
}
};
Full fiddle demonstrating this is here: http://jsfiddle.net/hUA9v/5/

Related

Disable opposite input if I type into another of a pair

How do I disable one input field if I type into another out of a pair and then if I removed the input by hitting backspace for example so there is nothing in the input field reenable the second input field and vice versa. Code I have so far is below but is not working.
JavaScript:
//disable the opposite input field
var ATGvalue = $('input#atgOrderId').val();
var BQvalue = $('input#bqOrderId').val();
if ( ATGvalue.length > 0) {
$('input#bqOrderId').prop("disabled", true);
} else {
$('input#bqOrderId').removeAttr("disabled");
}
if ( BQvalue.length > 0) {
$('input#atgOrderId').prop("disabled", true);
} else {
$('input#atgOrderId').removeAttr("disabled");
}
HTML:
<label for="bqOrderId">bqOrderId </label><input name="bqOrderId" id="bqOrderId" type="text" />
<label for="atgOrderId">atgOrderId </label><input name="atgOrderId" id="atgOrderId" type="text" />
Your code does work, but only once - to have it continuously update, you first wrap the JS in an event-handler function and attach it to your input elements:
function mutuallyExclusive( e ) { ... }
$( '#bqOrderId' ).on( 'change keyup', mutuallyExclusive );
$( '#atgOrderId' ).on( 'change keyup', mutuallyExclusive );
See this JSFiddle.
I attached it to both the change and keyup events: change to handle programatic (scripted) changes, and keyup to "instantly" update the fields' statuses - otherwise it waits till the user removes focus from the input to call the change event.
you need to include your code inside an event to check when a user type something like this:
$(document).on('keyup','#bqOrderId',function(){
//your code
});
$(document).on('keyup','#atgOrderId',function(){
//your code
});
after to change this:
$('input#bqOrderId').prop("disabled", true);
$('input#atgOrderId').prop("disabled", true);
to this:
$('input#bqOrderId').attr("disabled",true);
$('input#atgOrderId').attr("disabled", true);

OnBlur effect for select dropdown

I have a select dropdown and if a user clicks 'outside' of that select dropdown, I want it to disappear. This is what I currently have:
$(this).html($("<select/>", {
id: 'sel',
change: function() {
selectdone(this, title_id, status_type);
},
blur: function() {
selectdone(this, title_id, status_type);
},
In the above, if I click outside of the dropdown, nothing happens. The only time the function is firing is if I change the value of the select dropdown.
How would I accomplish the above, such that when a user clicks anywhere on the document outside of the select dropdown, it fires this function?
I don't think this is possible. As pointed out in another answer, it appears that the active <select> is prohibiting other input from being accepted.
See my updated fiddle. Notice that when you click the background you get the alert test when the select isn't expanded. When it is expanded and you click off, the alert doesn't fire. This appears to be the default behavior of the browser. It appears to be ignoring all other inputs (mouse movements included) while the select is activated.
I was, however, able to get your event to fire for any selected element by setting the selectedIndex to -1. This way any valid option will result in a change.
Example
$(function(){
var title_id = '', status_type = '';
$('body').html(
$("<select/>", {
id: 'sel',
change: function() {
selectdone(this, title_id, status_type);
},
blur: function() {
selectdone(this, title_id, status_type);
}
})
.append($('<option />', { 'text':'one'}))
.append($('<option />', { 'text':'two'}))
);
$('#sel').prop('selectedIndex', -1);
});
function selectdone(element, titleid, statustype){
$(element).hide().prop('selectedIndex', -1);
}

Customised jQuery autocomplete

I have a customised jQuery autocomplete control that is declared something like this.
$('#SystemCode_Autocomplete').autocomplete({
source: [{"label":"Access","value":0},{"label":"Documentum","value":0}], //move values
minLength: 1,
change: function(event, ui) {// some function},
select: function(event, ui) {// some function}
});
The change and select events are custom.
The problem is if I type something into the textbox then click the submit button (i.e. no tab out, or lost of focus), or if I press the key to submit after typing into the text box, the change event isn't fired and it has to be before I submit.
I was hoping to do it without putting javascript behind the submit button, and to ideally do it from within the autocomplete control itself. I tried adding the change to the blur event.
${'foo').blur(function() { $('bar').trigger('autocompletechange');
// or
${'foo').blur(function() { $('bar').change();
But none of them have worked, anyone have any ideas?
You can try something like this:
$('#SystemCode_Autocomplete').autocomplete({
source: [{"label":"Access","value":0},{"label":"Documentum","value":0}], //move values
minLength: 1,
change: function(event, ui) {/* some function */},
select: function(event, ui) {/* some function */}
}).each(function(){
var self = $(this).closest("form").submit(function(e){
self.trigger("change");
// you may not need anything like this...but whatever
if(!functionToCheckIfFormIsValid()){
e.preventDefault();
}
});
});
focus function autocomplete
Before focus is moved to an item (not selecting), ui.item refers to the focused item. The default action of focus is to replace the text field's value with the value of the focused item, though only if the focus event was triggered by a keyboard interaction. Canceling this event prevents the value from being updated, but does not prevent the menu item from being focused.
Solve the problem:
$('#SystemCode_Autocomplete').autocomplete({
source: [{"label":"Access","value":0},{"label":"Documentum","value":0}], //move values
minLength: 1,
focus: function( event, ui ) {
return false;
},
select: function(event, ui) {
alert('Select Event:'+ui.item.value);
}
});
So your problem is that you have to make sure that action a occurs before action b and you're having trouble reconciling that between two event handlers? That actually sounds like a pretty common UI problem, not something that's limited to jQuery.
How would you solve it in any other circumstance? What if I suggested you to use the jQuery data object to attach to the element and then do some sort of semaphore checking in each method, like setting a flag in the one method, and in the other method checking to see if the flag is set?
That's how I would do it, were it me.
DEMO: http://ask.altervista.org/demo/jquery-autocomplete-help/
$(function() {
var json = [{"label":"Access","value":0},{"label":"Documentum","value":0}];
$('#SystemCode_Autocomplete').autocomplete({
source: function( request, responce ) {
responce( $.map( json, function( item ) {
return { id: item.value, label: item.label, value: item.label }
}));
$.each( json, function( i, item ) {
if ( request.term.toLowerCase() == item.label.toLowerCase() ) {
// do something here, ex.: AJAX call or form submit...
$('#submit_button').click();
}
});
},
minLength: 1,
change: function(event, ui) { /*alert(ui.item.label + ' ' + ui.item.id)*/ },
select: function(event, ui) {}
});
});
Ok I completely for to update this to what we actually did to get it to work.
Basically we editted the autocomplete .js file to get it to do want we wanted.
Specifically we added our own options to the autocomplete then we editted the _response method to something like this
_response: function (content) {
if (content.length) {
content = this._normalize(content);
this._suggest(content);
this._trigger("open");
this.options.isInError = false;
this.element.removeClass("input-validation-error");
} else {
this.close();
if (this.element.val() == '') {
this.options.hiddenField.val('');
} else {
this.options.hiddenField.val('-1');
}
if (this.options.mustBeInList) {
this.options.isInError = true;
this.element.addClass('input-validation-error');
}
}
this.element.removeClass("ui-autocomplete-loading");
},
That way we know if the User is entering "rubbish" as they type and the controll goes red and into an "error"mode. To stop them from posting back we do this
case keyCode.ENTER:
case keyCode.NUMPAD_ENTER:
// when menu is open or has focus
if (self.options.isInError == true) {
return false;
}
if (self.menu.element.is(":visible")) {
event.preventDefault();
}
//passthrough - ENTER and TAB both select the current element
case keyCode.TAB:
if (!self.menu.active) {
return;
}
self.menu.select(event);
break;

Set focus on textfield when un-focused

I want a text field to always be focused. When they click out of the textfield, I want the focus to go back into the textfield.
How would I accomplish this with jQuery?
$('input').focus();
$('input').**unfocused?**( function($) { $('input').focus();} );
You're looking for the blur event:
$(':text').blur(function() { this.focus(); });
The following code is an alternative solution which depends on periodically checking the control's state.
var controlFocus=false;
$("#txtName").focus(function(){
$(this).addClass("focused");
if(!controlFocus) {
controlFocus = true;
setInterval(function(){
var o = $("#txtName");
if(!o.hasClass("focused")) o.focus();
}), 200);
}
}).blur(function(){$(this).removeClass("focused");});
After the textbox (named txtName) gets its first focus, every 0.2 second, the code controls whether the textbox has focus. If it doesn't, it's focused. But this can be a really annoying thing.
Bind to get the change event, and check if focus must be forced to this input if so, insert some data in the document. $(document).data(‘_force_focus’, e.target)
$('input.force').bind('change', function(e) {
if( need_force_focus() ) {
$(document).data('_force_focus', e.target);
} else {
$(document).removeData('_force_focus');
}
});
Now on the document bind to the focusin event, testing if document have the “_force_focus” data. If so set the focus to the value. It’s important prevent the focusin retrigger by testing against e.target
$(document).bind('focusin', function (e) {
var t = $.data(document, '_force_focus');
if( t && e.target !== t ) {
$(t).trigger('focus');
return false;
}
return true;
});

Javascript Textbox Event

I am facing problem with input text type (ie. Text Box).
I have written a function used by the onkeyup event on a Text Box. The line looks like this:
<input type='TEXT' value='abc' onkeyup='changeSomething( this );'>
But now I am facing problem that when user selects values from the previously entered values,
I am not getting any event when user selects any previously entered values from the drop down (edit: I believe he is referring to browser autocomplete here).
Does anyone have solution for this? :)
use onchange instead of onkeyup in this case
see: http://www.w3schools.com/jsref/event_onchange.asp
e.g.
<input type='text' value='abc' onchange='changeSomething(this);' />
to get around this
EDIT
Two things:
1) Autocomplete values can be selected using arrow keys and enter/tab, and by using the mouse. The arrow keys/enter.tab fire the onkeyup events... clicking in the autocomplete box does not, however, fire the onclick event.
2) The onchange event fires as soon as focus is lost IF the content has changed. Focus is not lost when selecting autocomplete values.
Essentially, there does not appear to be any way to reasonably guarantee the event will be processed the way you want.
First off, do you really need to listen to every keystroke?
Secondly, would you be better served by turning off autocomplete?
(e.g. <input type='text' value='abc' autocomplete='off' onkeyup='changeSomething(this);' />)
Here's a solution which polls the element periodically for any changes
<script type="text/javascript">
var changeWatcher = {
timeout: null,
currentValue: '',
watchForChange: function( el ) {
if( el.value != this.currentValue ) {
this.changed( el );
}
this.timeout = setTimeout( function() {
changeWatcher.watchForChange(el)
}, 200 );
},
cancelWatchForChange: function() {
clearTimeout( this.timeout );
this.timeout = null;
},
changed: function( el ) {
this.currentValue = el.value;
// do something with the element and/or it's value
//console.log( el.value );
}
}
</script>
<input type='text' value='abc' onfocus='changeWatcher.watchForChange(this)' onblur='changeWatcher.cancelWatchForChange()' onchange='changeWatcher.changed(this)' />

Categories

Resources