Differentiating rows' elements in Prototype - javascript

I have a table that contains in each row an input and a "save" image.
<td>
<div id="acp_1" style="margin-left:100px;display: inline">
<input size="10" type="text" value="11:00" name="acpr_1" id="acpr_1" />
<span class="modify-listener" id="ml_1">
<img id="save_1" src="/images/skin/database_save.png" alt="modify"/>
</span>
</div>
</td>
<td>
<div id="acp_2" style="margin-left:100px;display: inline">
<input size="10" type="text" value="11:00" name="acpr_2" id="acpr_2" />
<span class="modify-listener" id="ml_2">
<img id="save_2" src="/images/skin/database_save.png" alt="modify"/>
</span>
</div>
</td>
The __number pattern is used to differentiate one row's element from another.
I need to capture the click event on the image, so I can save the input's value in the backend. Something like:
Event.observe('modify-listener', 'click', function(){
....
How can I detect which row's image was clicked so I can call an Ajax function with the right values?
Thanks.

The technique you are searching for is called event delegation. It basically means that you handle an event on a higher lever of the tree so as to have only one event handler instead of many.
What you need to do is to find the container element that includes all the images (like the table that they are in), and use it as the base for event handling, and give its id to Event.observe. Then you can find out which img was clicked by using the Event.findElement method.
Event.observe('target', 'click', function(event) {
alert( Event.findElement(event, 'IMG').id ); // e.g.: save_1
});
assuming that your table has an id #target
You can find a working demo here.

Related

How do I disable tabbing in child divs

I have a div element with several children. I need to disable tabbing in all of them. I have been using tabindex but is there any way to disable them all by setting a value in the parent.
I don't want to touch the child divs.
I have no idea what your code looks like but you could grab the parent element and add the tabindex attribute to its children that are inputs using attr() as follows:
$(".wrapper").children("input").attr("tabindex", "-1");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="wrapper">
<input type="text" name="1">
<input type="text" name="2">
<input type="text" name="3">
<input type="text" name="4">
</div>
NOTE: when you say "I don't want to touch the child divs" I'm assuming you mean you don't want to manually go through every instance and add tabindex as it would be time consuming?
More info: http://api.jquery.com/attr/

Adding input rows using jQuery clone()

Background:
I've got a set of input elements form invoice item details. I want a user to be able to add rows of input fields for each additional item.
Input Markup
<div class="input-row">
<div class="form-group">
<label for="item_name">Item:</label>
<div>
<input type="text" name="item_name[]" placeholder="Name">
</div>
<div>
<input type="text" name="item_qty[]" placeholder="Quantity">
</div>
<div>
<input type="text" name="item_price[]" placeholder="Price">
</div>
<div>
<input type="text" name="item_total[]" placeholder="Total">
</div>
</div>
</div>
And a button to add an additional item
Button Markup
<div class="col-lg-2">
<a id="add-item" href="#">Add Item</a>
</div>
Button Javascript
$('#add-item').click(function(){
$('.input-row:first').clone().appendTo('.input-row:last');
})
Problem:
When I click the add button the first time, it works fine and adds a row of input fields after the first one, however if I click it again it adds 2 rows and then click it again it adds 4 rows. I realise this may be because the cloned .input-row div is being included in the clone, but I'm trying to only copy the first div element using the :first selector. Any ideas how to resolve this?
Question
How can I ensure only one div is appended to the markup.
The best solution I've seen so far is the following jQuery Library:
http://www.andresvidal.com/labs/relcopy.html
Solution
The jQuery appendTo method adds the element into the existing div, meaning when you clone it the second time the div contains two rows of input fields and then the third time will contain 4 rows of input fields.
To overcome this use the insertAfter() method
Button Javascript
$('#add-item').click(function(){
$('.input-row:first').clone().insertAfter('.input-row:last');
})

Find element that appears after a specific element in a separate <td>

I first use this code to find an element with a specific text content:
$('someElement').filter(function() {
return $(this).text() == 'Some text';
});
Then, I want to find the <input> element that's inside the next <td> tag.
Below is the HTML code:
<tr>
<td>
<label for="SH_Request_First_Name">
First name <span class="required">*</span>
</label>
</td>
<td colspan="2">
<input type="text" name="SH_Request_First_Name" id="SH_Request_First_Name"
value="" size="38" maxlength="50" onchange="validatePresent(this, 'SH_Request_First_Name_Note');"
/> <span id="SH_Request_First_Name_Note"> </span>
</td>
</tr>
I first found the label with text "First name". Then I want to find the <input> that's in the next <td> tag.
Is it possible to do the above tasks in JavaScript, instead of jQuery?
When you've found the first td tag you can access the next one in JS with
yourTd.nextSibling
This will return the next tag in the document.
If you want to get there from the label you first have to get the parent and then the sibling:
yourLabel.parentElement.nextSibling
but this construct is error prone if you change the HTML construct some times. I would recommend to use jQuery and select by a specidic css class or something like that, so it doesn't have to be exactly the next element, only one of the next elements with that css class.

Accordion + Appended Content Jquery

So I have an accordion menu that I created with Jquery:
<script>
$(document).ready(function() {
/*Accordian Script for the Request New Appraisal Panel*/
$('.accordian_item').hide();
$('.accordian_item').first().slideDown();
$('.accordian_trigger').click(function(event) {
event.preventDefault();
$(this).parent().find('.accordian_item').slideToggle();
});
});
</script>
Now, I want to be able to dynamically append extra accordion items to the accordion box, which I have done like this:
<script>
$('#add_contact_btn').click(function(event) {
event.preventDefault();
var large = '<div class="accordian_container"><h4>Co-Borrower Information</h4><hr/><div class="accordian_item"><label> First Name</label><br/><input type="text"/><br/><label>Middle Name</label><br/><input type="text"/><br/><label>Last Name</label><br/><input type="text" /><br/><label>Home Number</label><br/><input type="text"/><br><label>Work Number</label><br/><input type="text"/><br><label>Cell Number</label><br/><input type="text"/><br></div></div>';
$('#accordion_container_box').append(large);
});
</script>
This works perfect, except the dynamically generated items don't collaps when you click on the collapse button. The existing accordion items still work. For some reason it seems like Jquery wont trigger for dynamically created links. Any ideas how I can correct this?
BTW, here is the basic HTML structure:
<div id="accordion_container_box">
<div class="accordian_container">
<h4>Borrower's Information</h4>
<hr/>
<div class="accordian_item">
<label> First Name</label><br/>
<input type="text"/><br/>
<label>Middle Name</label><br/>
<input type="text"/><br/>
<label>Last Name</label><br/>
<input type="text" /><br/>
<label>Home Number</label><br/>
<input type="text"/><br>
<label>Work Number</label><br/>
<input type="text"/><br>
<label>Cell Number</label><br/>
<input type="text"/><br>
</div>
</div>
<div class="accordian_container">
<h4>Co-Borrower's Information</h4>
<hr/>
<div class="accordian_item">
<label> First Name</label><br/>
<input type="text"/><br/>
<label>Middle Name</label><br/>
<input type="text"/><br/>
<label>Last Name</label><br/>
<input type="text" /><br/>
<label>Home Number</label><br/>
<input type="text"/><br>
<label>Work Number</label><br/>
<input type="text"/><br>
<label>Cell Number</label><br/>
<input type="text"/><br>
</div>
</div>
</div>
+ Additional Contact
You have to use .live('click'... on dynamically created content.
By default binding events to elements will only affect nodes that exist at the time that the bind runs. By using event delegation you can make use of the built in way that events bubble. jQuery < 1.7 did this with the delegate and live methods, jQuery 1.7 added the on method to consolidate all the event handlers in a single API.
For example you could use the following to handle all clicks on nodes with a class of accordian_trigger regardless of when they were created.
​$(document).on('click', '.accordian_trigger', function() {
//whatever you need to do
});​​​​​​​​​​​
What this will do is attach an onclick event handler to the document itself. When any click occurs in the DOM it will bubble up from the node that the event occurred on to its parent and its parent until it reaches the document. jQuery will then check whether the event occurred on a node that matches the selector passed in as the second parameter of on, in this case it will check whether the node has a class of accordian_trigger. If it does it will run the function passed in as the third parameter.
For efficiency's sake you'll likely want to replace document with a parent node that you know will contain all accordian_trigger nodes. Otherwise all clicks bubble all the way up to the document and check whether the node that was clicked on has the accordian_trigger class, which is potentially expensive, especially if you have a large DOM.

Newly added elements using delegate() won't bind jscolor.js

I have a simple form, where each line consists of 3 input fields. on one of those fields, I use jscolor.js (field has a class="color" and thus binds the JS).
However, when I add new lines using jQuery's delegate(), the input field doesn't bind the JS and the expected functionality is not there. http://jsfiddle.net/alexwald/qARzP/
<script>
var line = '<li class="form_line" id="line">
<span>
<label for="item">Item:</label>
<input type="text" required="required" placeholder="what item is this?" id="item" name="item[]>
</span>
<span>
<label for="amount">Amount: </label>
<input required="required" type="number" id="amount" name="amount[]>
</span>
<span>
<label for="color">Color: </label>
<input type="text" required="required" class="color {pickerClosable:true, hash:true ,pickerFace:3,pickerBorder:0}" id="color" name="color[]">
</span>
</li>';
$(document).ready(function() {
$("form").delegate(".add", "click", function(){
$('ul').append(line);
}); // end of adding
}); //end of main func
</script>
I think the problem is either in:
how I define the line variable, or
I'm using an improper selector with .delegate, so it should be something else and not form..?
Any help greatly appreciated.
There are several problem to your code:
You are using IDs in your "line" variable. ID must be unique within an HTML document. You'd better use name attributes, or create a new line differently so you can change the IDs.
Why do you delegate the 'click' event for the 'Add' button ? Event delegation is used be able to automatically "bind" events to elements created dynamically. In your example, the "Add" button, is static to the page, you don't need to use delegate, simply .click() or .bind().
After creating the new line, you have to explicitly initialize your jscolor on the new field, it's not going to happen automatically. When your page is first parsed, the existing <input class="color" /> are initialized by the jscolor plugin, but insterted elements afterwards are not anymore, the script has run already.
Here's some modified code:
<script>
var line = '<li class="form_line" id="line"><span><label>Item:</label><input type="text" required="required" placeholder="what item is this?" name="item"></span><span><label>Amount: </label><input required="required" type="number" name="amount"></span><span><label>Color: </label><input type="text" required="required" class="color {pickerClosable:true, hash:true ,pickerFace:3,pickerBorder:0}" name="color"></span></li>';
$(document).ready(function() {
var $ul = $('#formulario'); // the UL, select it once and r-use this selection
$('.add').click(function(e) {
var $line = $(line);
$line.appendTo($ul);
// initialize the new jscolor instance
new jscolor.color($line.find('input[name=color]')[0], {});
});
}); //end of main func
</script>
And this jsfiddle for testing.
You could solve this by reinitialize the jscolor object in the append event.
$("body").on('click', 'div .add', function(){
$("#some-id").append('<input type="text" name="color" class="color">');
new jscolor.init();
});
No other solution works for me.
Following solution works for me.
Just create new jscolor object by passing input element object in javascript.
var picker = new jscolor($li.find('.jscolor')[0]);
reference from http://jscolor.com/examples/ go to Instantiating new Color Pickers section.

Categories