Evaluating an element that isn't in focus - javascript

I need to evaluate the contents of a hidden input field, who's value changes depending on the contents of an unordered list. For reference, this input field is part of a Tag-it! Single Input Field(2) assembly.
The problem with evaluating this sort of field is that onchange does not seem to fire on the input element, because the element is not in focus. That means I have two possible directions:
Figure out how to make the onchange event fire when the element isn't in focus;
Evaluate the contents of the unordered list.
The latter of these options seems the most appropriate, however it might also be heavy and possibly inaccurate. Which of these approaches should I be going for?
HTML:
<div id="Likes">
<div class="form-modal-back">
<div class="form-modal-title">
<h4>Choose some things you like</h4>
</div>
<div class="form-modal-main">
<h5>Start by typing a few letters, and choose from the suggestions</h5>
<div class="gap20"></div>
<div class="tagBox">
<input id="likesTags" name="tags" />
</div>
...
<a href="#Dislikes">
<input class="form-modal-button-right hiddenLink" id="onb5" type="button" value="Next" />
</a>
...
HTML at runtime:
<input id="likesTags" name="tags" class="tagit-hidden-field">
<ul class="tagit ui-widget ui-widget-content ui-corner-all">
<li class="tagit-new">
<input class="ui-widget-content ui-autocomplete-input" autocomplete="off" type="text">
<span role="status" aria-live="polite" class="ui-helper-hidden-accessible">1 result is available, use up and down arrow keys to navigate.</span>
</li>
</ul>
JS:
$("#likesTags").onchange(function () {
var text = $("#likesTags").val();
if (text.length > 2)
{
pageCompletionSequence += "1";
checkCompletion("#onb5", "#Dislikes", "11");
}
else
{
pageCompletionSequence = "1";
elementRestore("#onb5");
}
})
function checkCompletion(id, np, seq) {
if (pageCompletionSequence == seq) {
$(id).removeClass("hiddenLink");
$(id).parent().attr("href", np);
pageCompletionSequence = "1";
}
}
function elementRestore(id) {
$(id).addClass("hiddenLink");
$(id).parent().removeAttr("href");
}

This plugin has event callbacks for this case.
$("#likesTags").tagit({
//This should be appended to your current tagit initializing call.
afterTagAdded: function() {
onTagsUpdated('#likesTags');
},
afterTagRemoved: function() {
onTagsUpdated('#likesTags');
}
});
function onTagsUpdated(id){
var tags = $(id).tagit("assignedTags"); //Returns an array of the text values of all the tags currently in the widget.
console.log('tags of',id,'updated:',tags);
}

Related

How to add event listeners to the label of an input field on blur?

The input field is to contain a url. On blur, this event will update the input label's href,since this is a clickable label and should guide the user to a new page whose url has just been entered.
When the card containing this input is built, this function gets run. It adds event listeners to other pieces of the card, but this one doesn't seem to work.
function addEventListeners() {
const publishedPostInputs = document.querySelectorAll('.form-group.a input.published-link-input');
publishedPostInputs.forEach(input => {
input.addEventListener('blur', function() {
const link = this.value;
let plLabel = this.parentNode.parent;
plLabel.setAttribute('href', link);
});
});
}
<div class="col-12 mt-3">
<a href="https://images.pexels.com/photos/210019/pexels-photo-210019.jpeg" target="_blank">
<label for="publishedPostLink">Published Link:</label>
</a>
<input type="text" class="form-control published-link-input" name="published-link" value="https://posts.gle/ZpUe9p">
</div>
<!-- IMAGES TO TRY:
https://images.pexels.com/photos/170811/pexels-photo-170811.jpeg
https://images.pexels.com/photos/210019/pexels-photo-210019.jpeg
-->
Issues with your code:
the querySelectorAll() did not match anything because .form-group.a does not exist, so remove it
addEventListeners() is not called, only defined
your <a> tag is not the parent, but a sibling, so go to parent and find the tag
Fixed code:
function addEventListeners() {
const publishedPostInputs = document.querySelectorAll('input.published-link-input');
publishedPostInputs.forEach(input => {
input.addEventListener('blur', function() {
const link = this.value;
const elem = this.parentNode.getElementsByTagName('a')[0];
elem.setAttribute('href', link);
});
});
}
addEventListeners();
<div class="col-12 mt-3">
<a href="https://images.pexels.com/photos/210019/pexels-photo-210019.jpeg" target="_blank">
<label for="publishedPostLink">Published Link:</label>
</a>
<input type="text" class="form-control published-link-input" name="published-link" value="https://images.pexels.com/photos/170811/pexels-photo-170811.jpeg">
</div>
<!-- IMAGES TO TRY:
https://images.pexels.com/photos/170811/pexels-photo-170811.jpeg
https://images.pexels.com/photos/210019/pexels-photo-210019.jpeg
-->
A better way to do it would be to listen for live change events from the input. That way if the value changes it will keep updating the link.
Note: I have edited the answer to better suit the needs, I did not understood the requirement was with multiple fields, this one works better.
Here is the code:
index.html
<!DOCTYPE html>
<html>
<body>
<div class="col-12 mt-3">
<a href="https://images.pexels.com/photos/210019/pexels-photo-210019.jpeg" target="_blank">
<label for="publishedPostLink">Published Link:</label>
</a>
<input type="text" class="form-control published-link-input" name="published-link"
value="https://posts.gle/ZpUe9p">
</div>
<!-- IMAGES TO TRY:
https://images.pexels.com/photos/170811/pexels-photo-170811.jpeg
https://images.pexels.com/photos/210019/pexels-photo-210019.jpeg
-->
<script src="./index.js"></script>
</body>
</html>
index.js
// Find inputs
const publishedPostInputs = document.querySelectorAll('input.published-link-input');
// Loop through inputs
publishedPostInputs.forEach(function (input) {
// Add event listener for input field change
input.addEventListener('change', function (e) {
// Get the link from the same parent element
const linkLabel = e.target.parentElement.querySelector('a');
// Set the attribute href to the value of the input field
linkLabel.setAttribute('href', e.target.value);
});
});

How to replicate function on similar divs with same function

If I have li which contains a function (duplicate on keyup), how can I replicate that same function to a clone of that same li.
this is the element (li, better said), which will be constantly duplicated
<li class="main-item">
<div class="header-item fwidth">
<div>
<h1 class="duplicado fleft"></h1>
</div>
</div>
<div id="internal-items-2" class="collapse collapsible-item">
<div>
<input type="text" value="" class="duplicante nombre-item">
</div>
</div>
</li>
this is the duplicate on keyup function, which produces text on the H1 element according to what is written on the input
$(function() {
$('.duplicante').on('keyup', function() {
var text = $(this).val();
$('.duplicado').text(text);
});
});
How to make that function works for each duplicated li element?
Fiddle example
If I understand correctly, what you want is to updated the individual headers upon keyup.
One way to do it would be like this:
$(function() {
$('.duplicante').on('keyup', function() {
var text = $(this).val();
$(this).closest('li').find('.duplicado').text(text);
});
});
here is the fiddle:
http://jsfiddle.net/s16vds6n/1/

Custom keyboard tab order in html4

I want to manage keyboard tab order functionality, I am using a template for header, footer and sidebar where many anchor element & input element exists. In template content we can not put and tabindex attribute which is not in my control.
Middle part of template is my work area, where I created a form and some element
<fieldset id="myWorkArea">
<div class="fieldrow">
<label for="input1">Class</label>
<input id="input1"/>
<a id="help1" href="#">what's this?</a>
</div>
<div class="fieldrow">
<label for="input2">Class</label>
<input id="input2"/>
<a id="help2" href="#">what's this?</a>
</div>
</fieldset>
In above code I want to cursor tabbing in below id order.
#help1 > #input1
#help2 > #input2
Is any approach to control keyboard tabbing order in only #myWorkArea fieldset elements as we can not put tabindex for all element in page?
Even if you have no access to the template, you can still add the tabindex attribute programmatically.
Here you have a snippet:
var tabindex = 1;
$('#myWorkArea .fieldrow').each( function() {
$('a', this).attr('tabindex', tabindex++);
$('input', this).attr('tabindex', tabindex++);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<fieldset id="myWorkArea">
<div class="fieldrow">
<label for="input1">Class</label>
<input id="input1"/>
<a id="help1" href="#">what's this?</a>
</div>
<div class="fieldrow">
<label for="input2">Class</label>
<input id="input2"/>
<a id="help2" href="#">what's this?</a>
</div>
</fieldset>
Hope it helps!
You can add the tab index programmatically using javascript as David mentioned in his answer.
Or If you want you can control the taborder functionality by binding your own event to only these elements like below code.
Working FIDDLE
$(function(){
var inputs = $('a#help1, a#help2,input#input1, input#input2');
$(inputs).bind('keydown', function (e) {
var self = $(this), form = self.parents('form:eq(0)'), focusable, next;
//check keycode for tabbing
if (e.keyCode == 9) {
switch($(this).attr("id")){
case "help1":
next=$('#input1');
break;
case "help2":
next=$('#input2');
break;
case "input1":
next=$('#help2');
break;
case "input2":
next=$('#help1');
break;
}
next.focus();
e.preventDefault();
return false;
}
});
});

How to select input content if there is only one error class

I want to check if there is only one div with an error class. And if so, I want to .select() the content of the input (that's in the in corresponding input class div).
How would I do such thing?
My attempt which does not work:
if($("div.addition").hasClass(".error").length === 0) {
(this).parent().find('input').select();
}
HTML
<form>
<div class="input">
<input type="text">
<div>
<div class="addition">Message message.</div>
</div>
</div>
<div class="input">
<input type="text">
<div>
<div class="addition">Message.</div>
</div>
<div class="input">
<!-- So in this case this input's content will be selected -->
<input type="text">
<div>
<div class="addition error">Error message.</div>
</div>
</div>
</form>
Here's a jsFiddle that should do it - I mentioned as a comment to your post that you're missing a </div> tag, that is fixed in the fiddle - without it, the jquery selector matches two inputs. Outline of the js:
if ($('div.error').length === 1) {
errorContent = $('div.error').parents('div.input').find('input').val();
alert(errorContent);
}
Here's a plain JavaScript implementation. No need to use jQuery unless you're already using it.
var errors = document.getElementsByClassName('error');
if(errors.length === 1){
//If there is one class with error
var content = errors[0].innerHTML;
} else{
//there is more than one error class.
}
I want to check if there is only one div with an error class.
if ($("div.error").length === 1) {
// Exactly one div with the class "error"
}
else {
// Zero or more than one
}
By using jQuery it can be done like:
$(document).ready(function(){
var div = $('.error');
if(div.length){
var val = div.parents('.input:first').find('input').val();
//val is the value of input
}
});

Flip text input fields between elements, including user-created value attribute

Hi I'm trying to flip the input fields between two div elements. However, if a user enters text into the fields, the text disappears after the flip happens. Is there a way to make sure this value attribute is flipped too? Thanks.
Javascript:
function Flip ()
{
var oldslave = $('div.slave').html();
var oldmaster = $('div.master').html();
$('div.slave').html(oldmaster);
$('div.master').html(oldslave);
}
HTML:
<div class="master">
<input type="text" name="master" id="master" size="42">
</div>
<input type="button" id="button1" onclick="Flip()" value="Flip">
<div class="slave">
<input type="text" name="slave" id="slave" size="42" class="slavefield">
</div>
You can use clone method like this:
function Flip() {
var oldslave = $('div.slave input').clone();
var oldmaster = $('div.master input').clone();
$('div.slave').html(oldmaster);
$('div.master').html(oldslave);
}
http://jsfiddle.net/MaESg/
There is also another variant to achieve the same without using clone:
function Flip() {
$('.master').find('input').appendTo('.slave').prev().appendTo('.master');
}
This one is preferable because appending (moving) nodes much more effective than recreating.
http://jsfiddle.net/MaESg/1/

Categories

Resources