JQuery, cloning a div more than once - javascript

I have the following JSFiddle set up. At the moment, I have three divs, each with their own input. Each input has a checkbox where another input can be added. If unchecked the input is then removed again. The code for this is
$(function() {
$('input:checkbox[name="labelNewline"]').change(function() {
if ( $(this).is(':checked') ){
var clone = $(this).parent().siblings(".labelAndInput").first().clone().insertAfter($(this).parent());
clone.addClass('clone');
} else {
$(this).parent().siblings(".clone").remove();
}
});
});
I am trying now to do something else. If a new line is added, the new input should also get a checkbox with the ability to add a new input. So I no longer want to limit this to only one input being added. However, if the checkbox for an input is unchecked, it should remove its related input.
Would something like this be possible?
Thanks

Yes, it's possible.
Here's a working fiddle:
https://jsfiddle.net/yvnyk69v/1/
Things of note:
$("#testingContainer").delegate('input:checkbox[name="labelNewline"]', 'change', function() {
The delegate function is really useful in this case. What it does it it takes an element, and will apply an event handler to any element that matches the selector specified in the delegate function, even if it's added after code has already run.
The UI was pretty simple, so I was able to target elements with next and previous. If it becomes more complex, you may want to add a an attribute or class to more easily identify the corresponding inputs.

Related

jQuery: generate Select element

I have a table with data, and when I click on a cell in a certain column, I want it to change into a select dropdown for the user to choose a category for that row (which will be written to the database by AJAX but that'll come later).
I've done something similar before with text boxes using this, which works great, but I'm not sure if I'm modifying it correctly.
I've created a JSFiddle which shows the problem I'm having. I click on the text and it turns into a select element as expected, but when I click on that to choose an option, the dropdown doesn't stay open and I can't select anything. Debugging has shown me that when I click the dropdown, it runs the $("td.ChooseType").click() routine again so I've tried to suppress that by removing the class then adding it back on on selection, but that hasn't solved it. On the rare occasion that the dropdown stays open, I am unable to select anything by either mouse or keyboard.
All of the users will be on IE8 unfortunately, so I need it to be compatible with that.
Thanks!
You need to use event delegation, as otherwise that click event is always bound to that td - regardless of whether its class changes.
Simply change:
$("td.ChooseType").click(function() {
To:
$("table").on('click', '.ChooseType', function () {
JSFiddle demo.
Purely as an alternative to the accepted answer, you can remove an attached handler with unbind. So instead of adding and removing the class, you could unbind and rebind your handler. Only requirement is that the function can't be in-line, but has to be declared separately.
example: http://jsbin.com/qiqunici/1/edit
var handler = function () {
$(this).unbind('click', handler); //unbind the clicked element only
//create and change the element
//inside the select-change event, instead of addClass, re-attach:
{
//$(this).parent().addClass("ChooseType").text(selected).find('select').remove();
$(this).parent().click(handler).text(selected).find('select').remove();
}
};
$("td.ChooseType").click(handler);

Trigger onBlur on multiple elements as a single unit

I have two inputs that together form a single semantic unit (think an hours and minutes input together forming a time input). If both inputs lose focus I want to call some Javascript function, but if the user merely jumps between those two, I don't want to trigger anything.
I've tried wrapping these two inputs in a div and adding an onBlur to the div, but it never triggers.
Next I tried adding onBlurs to both inputs and having them check the other's :focus attribute through jQuery, but it seems that when the onBlur triggers the next element hasn't received focus yet.
Any suggestions on how to achieve this?
EDIT: Someone questioned the purpose of this. I'd like to update a few other fields based on the values contained by both these inputs, but ideally I don't want to update the other fields if the user is still in the process of updating the second input (for instance if the user tabs from first to second input).
I made a working example here:
https://jsfiddle.net/bs38V/5/
It uses this:
$('#t1, #t2').blur(function(){
setTimeout(function(){
if(!$('#t1, #t2').is(':focus')){
alert('all good');
}
},10);
});
var focus = 0;
$(inputs).focus(function() { focus++ });
$(inputs).blur(function() {
focus--;
setTimeout(function() {
if (!focus) {
// both lost focus
}
}, 50);
});
An alternative approach is to check the relatedTarget of the blur event. As stated in the MDN documentation this will be the element which is receiving the focus (if there is one). You can handle the blur event and check if the focus has now been put in your other input. I used a data- attribute to identify them, but you could equally well use the id or some other information if it fits your situation better.
My code is from an angular project I've worked on, but the principle should translate to vanilla JS/other frameworks.
<input id="t1" data-customProperty="true" (blur)="onBlur($event)">
<input id="t2" data-customProperty="true" (blur)="onBlur($event)">
onBlur(e: FocusEvent){
const semanticUnitStillHasFocus = (val.relatedTarget as any)?.dataset?.customProperty === "true";
// Do whatever you like with this knowledge
}
What is the purpose of this behavior ?
The blur event triggers when a field looses focus, and only one field can gain focus at a time.
What you could do, in case of validation for instance, is to apply the same function on blur for both the fields and check the values of the fields altogether.
Without a context, it is difficult to help you more.
d.

JQuery clean autocomplete combobox value

I used a jquery combobox for autocompletion and I needed to clean its value.
I got into a solution which is like this: http://jsfiddle.net/BbWza/30/
The problem is that the code below clears all textboxes of all combos in the screen. I'd like to clear only ONE combo (let's say the first one, for example).
$('.ui-autocomplete-input').focus().val('');
Although there is only one clear link button, it doesn't matter which combo will be cleared as long as only one is.
The solution should work for N combos in the screen. E.g. Each button should empty its corresponding combo.
You can add ids to the generated fields by adding this line as the last line of _create():
input.attr( 'id', $(select).attr( 'id' )+'-input' );
Now you can select individual fields with the ids:
$('#combobox-input').focus().val('');
To clear just only one combo you must select it with it's id:
$('#combobox').focus().val('');
$('#combobox').autocomplete('close');
with your code you are selecting all comboboxes because you are using a class selector.
EDIT if you want to make two buttons (one for each combobox) you could do:
$('.clicky').click(function() {
var combo= $(this).prevAll('input:first');
combo.focus().val('');
combo.autocomplete('close');
return false;
});
fiddle here: http://jsfiddle.net/BbWza/39/
Your jsfiddle is a little ambiguous as to which combo box should be cleared - there are two combo boxes but only one clear link, so it's not obvious if the link is supposed to clear just one or both combo boxes.
I suspect in the real world that each combo box would have it's own clear link. Selecting the right text box for your clear link all depends on your html. One simple case would be where the clear link is the next sibling to your <select> element:
<select class="combo">
...
</select>
Clear
Then you could create the combos in one call by using class. Then create the clear click handlers all at once. The handler would use .prevAll(".ui-autocomplete-input") to find its associated textbox.
$("select.combo").combobox();
$("a.clearCombo").click(function () {
$(this).prevAll('.ui-autocomplete-input').first()
.focus()
.val('')
.autocomplete('close');
return false;
});
Working demo at jsfiddle
If your link is not a sibling of your combo box, that's ok. Either find its parent that is a sibling and use the above approach. Or, if that won't work, find the common parent of both the combo and the link. This only works if the common parent contains only one combo and one link:
<span class="comboContainer">
<span>
<select class="combo">
...
</select>
</span>
Clear
</span>
You use .closest(".comboContainer") and .find(".ui-autocomplete-input"):
$("select.combo").combobox();
$("a.clearCombo").click(function () {
$(this).closest(".comboContainer").find('.ui-autocomplete-input')
.focus()
.val('')
.autocomplete('close');
return false;
});
Working demo at jsfiddle
The nice thing about these techniques is that the link doesn't need to know the id of its associated combobox. We can just infer it from the html. This makes it very easy to move combos around and add new ones.
Two suggestions:
Add a clear method to your plugin. Your widget users shouldn't have to know its internal workings. In your example, you have to know that widget uses .autocomplete(). This also prevents you from changing your implementation later. Adding a "clear" method would simplify your click handler to just $(this).prevAll("select.combo").combobox("clear").
Give your widget the option to create the clear button itself. Users can always disable it and add their own clear button if they want.
Well, in the example the following would only clear the last combobox:
$('.ui-autocomplete-input').last().focus().val('');
This would clear the first one:
$('.ui-autocomplete-input').first().focus().val('');
You can clear it in event "close" of the autocomplete
$("#your-input").autocomplete({
source: items,
close: function (event, ui) {
$(this).val("");
}
});
How to give clear button for autocombobox please tell me
You can add ids to the generated fields by adding this line as the last line of _create():
input.attr( 'id', $(select).attr( 'id' )+'-input' );
Now you can select individual fields with the ids:
$('#combobox-input').focus().val('');

how to create a new text field below when pressing a key?

last.fm has this nifty feature when you're adding an event. you have the Artists field, and when you start typing in it, another text field appears beneath it. when you start typing in that next field, another new field appears beneath and so on. I've been trying to figure out how to mimic this functionality using jquery but I can make it work on the first, stationary, field only. any ideas?
edit:
actually, nope, it's not working even for the stationary one, since it adds the field on EVERY key press
edit2:
alrighty, so some fine folks have already solved my adding issue, now, how would one go about adding the field only after the first time a key is pressed.
You are probably only binding your handler to the first static input, and not the dynamically created ones. Use .live() to do your event binding. That will bind the event to future elements that match the selector.
To make sure you only add one new one, make sure you only add it when typing into the last textbox. Check $(this).closest(".container").next(".container").length to make sure there isn't already a new textbox.
$("input.myClass").live("keyup", function (e) {
var $container = $(this).closest(".container");
if (this.value && !$container.next(".container").length) {
var $newContainer $("<div>").insertAfter($container).addClass("container");
...
}
});
Live is the right idea but closest is overkill: jsFiddle
$("input").live("keyup", function (){
if ( !$(this).next('input').length ) $(this).after('<input type="text"></input>');
});

JQuery: Finding the Object that created a DOM Element

So I've been working on this all day and I can't figure out how to get it to work. I have a table with TD's filled with content which is drawn from a database using a JQuery "getJSON" command. I have an event handler set-up so that when you double click a TD element, its contents become a INPUT element with the default value of the enclosing TD's previous contents.
The INPUT element is created inside a Javascript object named "Input" like so:
var Input = function() {
var obj = this;
obj.docElement = $('<input/>').attr('type', 'text').val(obj.defaultValue);
}
All of this is working so far. My problem is, I want the user to be able to hit the RETURN key while the INPUT is selected to signify they've finished editing that field. I've tried something like the following:
$(obj.docElement).bind('keydown', function(e) {
if(e.which == 13) {
// do something
}
}
This works fine for the first time you edit a field; however, if you edit a field multiple times it stops working. Also if you randomly double click TD's eventually it breaks. I tested it and determined that the INPUT element stops registering any type event, as if the "bind" no longer existed on it.
I've done lots of googling and determined that the regular JQuery "bind" handler placed on an INPUT element is unreliable. Therefore I decided to attach the event handler to the document object instead using the following:
$(document).bind('keydown', function(e) {
// do something
}
I know I can use "e.target" to get the target element that the action is executed on (and this works for me, e.target correctly refers to the INPUT element).
My question is, how do I get the object that created the INPUT element in the first place? I need to be able to execute functions contained within the corresponding "Input"
class that was used to create the INPUT element. I need to call these functions from within the "$(document).bind" function. So basically I need to be able to get an INPUT element's parent/creator Input object.
If I haven't explained anything clearly enough, just let me know. Any help in this matter would be greatly appreciated! I'm also open to suggestions for alternative methods (other than using "$(document).bind").
Thanks!
I think I understand the problem ...
You can traverse the DOM to find the parent document element, but that's not what you mean, right? You want the parent script element that has a bunch of logic that operates on the element.
I suspect that it is probably easiest to provide some sort of reference to the parent when the input element is created ... pass this to the event handler, or set it in a globally accessible location (like a current_element_parent var).
I agree with tobyhede. You can either add a custom attribute to the INPUT element that refers back to the parent, or keep a map in memory that maps the dynamically created INPUT element to the parent that created it. When you trap the Return key, simply remove the relationship from the map so it can be added again if the user clicks it again.

Categories

Resources