Detect new DOM elements and changes to input boxes - JQuery - javascript

Take a look at the following HTML:
<div id="tab1">
<input type="text">
</div>
<div id="tab2">
<input type="text">
<button>Add New Input Box</button> <!-- Adds another <input type="text"> in tab -->
</div>
<div id="tab3">
<input type="text">
<button>Hide Input Box</button> <!-- Adds style 'display:none' to input -->
</div>
I am looking for a way to detect changes to the DOM with JQuery. I am aware of MutationObserver objects and these are great but I would only like to detect changes in the following scenarios:
New HTML elements are added (see #tab2 button - 'Add new input box')
Text is entered into input box (see #tab1 input field)
And NOT detect changes where:
HTML element attributes are changed (see #tab3 button - 'Hide input box')
Of course MutationObserver will flag the changes when the HTML attributes change (which I don't want) but it will not flag when a user types into an input box (which I do want). For this reason I am thinking MutationObserver objects are not suitable for this problem (correct me if I'm wrong).
Are there any other things I can use for this?
My Scenario: Just to give you some more context, I am creating a save prompt to a data entry app that contains multiple tabs. It is easy to forget to save your changes before moving to the next tab but sometimes you may want to move to another tab without saving yet. I am trying to show the user an alert informing them that they have not saved when they click the next tab. Some fields can be hidden/shown on the click of a button which MutationObserver will detect as a change to the DOM even though they may not have entered any new values. Some values can be pulled from another location at the click of a button via ajax which although the user has not typed anything, it should still be flagged as a change that needs to be saved as the DOM has changed.

To detect new elements added or removed from tab2, only add and remove elements, you may use the events: DOMNodeInserted DOMNodeRemoved, while for the changes to the input field you may use the input event.
These events are deprecated because they will be removed from the web.
For a better description see Mutation events
$(function () {
$('div, #tab1 input').on('DOMNodeInserted DOMNodeRemoved webkitTransitionEnd input', function (event) {
switch (event.type) {
case 'input':
if (event.target.parentNode.id == 'tab1') {
event.stopImmediatePropagation();
alert('Content changed');
}
break;
case 'DOMNodeInserted':
if (event.target.parentNode.id == 'tab2') {
alert('Content added!');
}
break;
case 'DOMNodeRemoved':
if (event.target.parentNode.id == 'tab2') {
alert('Content removed');
}
break;
}
});
$('#add').on('click', function (e) {
$(this).after('<input type="text">');
});
$('#remove').on('click', function (e) {
$(this).siblings('input').remove();
});
$('#tab3 button').on('click', function (e) {
$(this).siblings('input').toggle();
})
});
<script src="http://code.jquery.com/jquery-1.11.3.min.js"></script>
<div id="tab1">
<input type="text">
</div>
<div id="tab2">
<input type="text">
<button id="add">Add New Input Box</button>
<button id="remove">Remove All Input Boxes</button>
</div>
<div id="tab3">
<input type="text">
<button>Hide/Show Input Box</button>
</div>

Related

Focus reverts to text input on first attempt to transfer it to another element; only when VoiceOver is active

Note: This question is specific to desktop/non-touch keyboard navigation on OS X. The question comes from a use case revealed in QA. The issue was not reported for Windows running NVDA or the like.
When testing with VoiceOver enabled, attempting to transfer focus from the input to another element (on the keyup event, filtered to the down arrow key), the targeted element gets focus for a moment before it immediately returns to the input element.
It only does so the first time, though. And only if the input is not empty. After that, everything seems to work as expected.
let
$results = $('#results');
$(document).on({
'keyup': event => {
event.preventDefault();
if (event.which == 40) {
$results.children().eq(0).focus();
}
}
}, '#main');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form action="" autocomplete="off">
<input type="text" id="main">
<div id="results">
<p tabindex="0">foo</p>
<p tabindex="0">bar</p>
<p tabindex="0">baz</p>
</div>
</form>

How to re-disable (disable) the text box on clicking a button or a link?

I have a script that enables the disabled text box when clicking on a button. But, I just don't know how to re-disable the text box again.
The coding is below.
HTML:
<div class="input-group">
<label for="some-tbox" class="input-group-addon">Label:</label>
<input id="some-tbox" type="text" class="input-box" value="some value" disabled>
<span class="input-group-btn">
<button class="enable" type="button">button</button>
</span>
</div>
JS:
$(".enable").click(function(){
$(this).parent().parent().children(".input-box").removeAttr("disabled");
$(this).toggleClass("disable");
$(this).toggleClass("enable");
});
$(".disable").click(function(){
$(this).toggleClass("enable");
$(this).toggleClass("disable");
$(this).parent().parent().children(".input-box").attr("disabled", "disabled");
});
And I have made a fiddle out of it. But, It's not working. Here is the link.
Instead of messing with adding and removing classes, just toggle the disabled property with:
$(".enable").click(function() {
$(this).closest('.input-group').find('input').prop('disabled', !$(this).closest('.input-group').find('input').prop('disabled'))
});
jsFiddle example
The problem is this line $(".disable").click(function(){ ...})
You are binding a click event handler to a class named disabled which was not available initially during page load, it appears dynamically later.
You need to delegate the event handler to some parent which always exist and then handle the event there, in this case you can do this:
$(".input-group").on('click', '.disable', function(){
$(this).toggleClass("enable");
$(this).toggleClass("disable");
$(this).parent().parent().children(".input-box").attr("disabled", "disabled");
});
jQuery's on function
You cann't bind an element ".disable" that don't exist , In that case you can rebind it when you changed it's class. Code behind may help you:
$(".enable").on("click",enabledClick)
function enabledClick (argument) {
$(".enable").parent().parent().children(".input-box").removeAttr("disabled");
$(".enable").toggleClass("disable");
$(".enable").toggleClass("enable");
$(".disable").on("click",disabledClick)
}
function disabledClick (argument) {
$(".disable").parent().parent().children(".input-box").attr("disabled", "");
$(".disable").toggleClass("enable");
$(".disable").toggleClass("disable");
$(".enable").on("click",enabledClick)
}

Detect when clicking on another input after a focusout with Firefox

Consider that I have a page with multiple lines of text.
When then user clicks on it, it turns into multiple text inputs so he can modify it.
When he clicks outside the text input, its is saved and the input is replaced by the text.
But if he clicks on another text input, I don't want to save it for now, so he doesn't have to click multiple times on a line to modify it.
I was able to that using the 'focusout' event. I detect that the user clicks ont another input using jQuery's e.relatedTarget.
It works great with Chrome but Firefox doesn't support well focusout. e.relatedTargetis always null
How can I achieve something similar with firefox ?
$('input').on('focusout', function(e) {
if (e.relatedTarget != null) {
$('#display').html("don't save for now")
} else {
$('#display').html("save the inputs");
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div>
<input type="text" />
</div>
<div>
<input type="text" />
</div>
</div>
<div id="display"></div>
You are correct that relatedTarget is not very useful in Firefox.
The workaround is to explicitly check what element recieves the focus. This is not available during the focusout event (as the new element has not received focus yet), but it will be directly thereafter. Using a timeout of 0 to move the request to the end of the current execution queue will reliable allow you to get the newly focused element, and check if it is one of the inputs or not.
$('input').on('focusout', function(e) {
setTimeout(function() {
if ($(document.activeElement).is('input')) {
$('#display').html("don't save for now")
} else {
$('#display').html("save the inputs");
}
}, 0);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<div>
<input type="text" />
</div>
<div>
<input type="text" />
</div>
</div>
<div id="display"></div>

Delegated click event doesn't fire

I am developing a web application. You can find the website here.
If you click on the "road" icon, and after the menu opened the plus sign ("+"), a text input will appear with a label. This <ul> is using the jQueryUI Sortable plugin, to - of course - be able to sort the addresses after input.
I would like to add a click event to the label of these address fields, so that when a user clicks the number, a dialog box will appear where he/she can manually edit the number (it can get a little counter-productive if there are hundreds of addresses).
Since the <li> elements, in which the label and the inputs are gets created later, I tried to delegate the click event, like so:
$(document.body).on('click', '.control-label', function () {
console.log($(this));
});
However the event never fires. I am starting to think that maybe the sortable plugin disables my events to that label?
Here is the HTML code of an address field (label+input+delete button)
<li>
<div class="form-group">
<label class="col-md-1 control-label">1.</label>
<div class="col-md-11 input-group">
<input type="text" name="waypoints[]" class="form-control form-control-square waypoint animated fadeInRight" placeholder="Megálló" autocomplete="off" required=""><span class="input-group-btn animated fadeInRight"><button type="button" class="btn btn-square btn-danger btn-removewaypoint animated fadeInRight">×</button></span>
<div class="search-suggestions">
<ul></ul>
</div>
</div>
</div>
</li>
Here is the addWaypoint() function which adds a new row. This gets called every time when the user clicks the + button.
Edit: Apparently it isnt the sortable plugin, but something else that blocks the click event. Anyone got any ideas?
You need to setup a variable related to each control-label class in order to console.log it (or alert it, or use it anyway you want).
This is how I suggest you modify the javascript:
$(document.body).on('click', '.conrtol-label', function () {
var spanText=$(this).text();
console.log($(this));
alert(spanText);
});
Maybe this fiddle would help: http://jsfiddle.net/jo6957au/1/
Modified to use li's http://jsfiddle.net/jo6957au/3/

Text box focusout event and enter issues in IE9

I have a text input and one button of type submit adjacent to the input. I have bound focusout event-handler to the input and click event-handler to the button. Now when I focus on the input and then press enter, the focusout event-handler gets triggered and the buttons-event handler gets triggered. I want to trigger focusout only when text box focus is lost. What should I do ?
Code :-
<div >
<span>Local Currency: </span>
<input type='text' id='txtFocusElement' />
<button id="btnClickElement" >
<span> Add new line</span>
</button>
</div>
I used selector as:
$("#txtFocusElement").bind("focusout", function() {
console.log('focusout');
})
$("#btnClickElement").bind("click", function() {
console.log('click');
})
and written above code in one function which I call at the time of loading document.
Its IE9 issue with the HTML button tag.
So we should try it with HTML input tag with attribute type as button.
above code can be rewritten as :
<div >
<span>Local Currency: </span>
<input type='text' id='txtFocusElement' />
<input id="btnClickElement" type="button" value="Add new line" />
</div>
Using this my problem gets solved .
You could try to change the selector to input[type=text].
This will only get triggered when you focus out on a text field.
Try to attach to a mouseup event instead of click, that is the only solution I see for now
You can also add a check for mouse button which was pressed, so it wouldn't fire if user would press a right button
var ClickElementEventHandler = function(e) {
if (e.which != 1) return;
//your code
};
$("#btnClickElement").bind("mouseup",ClickElementEventHandler)

Categories

Resources