How to handle events on markup inserted through jQuery - javascript

I have the following markup:
<div id="section">
<input type="text" id="myInput">
</div>
On click of a button, I'm cloning and inserting a copy of this markup with unique IDs using this script:
var newSection = $("#section").clone();
$(newSection).attr('id', "section" + ($("div[id^=section").length + 1));
$(newSection).find("input").attr('id', "myInput" + ($("input[id^=myInput").length + 1));
$("div[id^=section").last().after(newSection);
My resulting markup:
<div id="section">
<input type="text" id="myInput">
</div>
<div id="section2">
<input type="text" id="myInput2">
</div>
My question: is it possible to manipulate this new markup with jQuery? I assume since it has loaded dynamically after a click it's not part of the initial DOM and jQuery doesn't recognize it? I'm having trouble getting a click event to register on #myInput2. Thanks for any insight.

Add classes to your markup:
<div id="section" class="section">
<input type="text" id="myInput" class="section-input">
</div>
Simplify your code
var $newSection = $('#section').clone();
var $sections = $('.section');
var index = $sections.length +1;
$newSection.attr('id', 'section' + index);
$newSection.find('input').attr('id', 'myInput' + index);
$sections.last().after($newSection);
Make sure click handlers are added to existing and new elements
$(document).on('click', '.section-input', function(){
... your code
})

if you wrap them in a container, you can delegate that container keep track of the buttons. For example, if you have:
<div id="container">
<div id="section">
<input type="text" id="myInput">
</div>
<div id="section2">
<input type="text" id="myInput2">
</div>
</div>
you can delegate the task to the container like this:
$("#container").on("click","input",function(){
var newSection = $("#section").clone();
$(newSection).attr('id', "section" + ($("div[id^=section").length + 1));
$(newSection).find("input").attr('id', "myInput" +
($("input[id^=myInput").length + 1));
$("div[id^=section").last().after(newSection);
}
This way you can manipulate them if not defined while binding
EDIT: Updated from .delegate() to .on()

Related

How to remove input group in bootstrap?

This is what I have right now. I'm trying to add fields to the form dynamically using jQuery add() and append() method. But I want to remove the particular added field when the remove button is clicked.
<div class="col-md-12">
<h3>Added Description Fields</h3>
<div class="col-md-12" id="descFields">
</div>
</div>
JS
$(document).ready(function() {
console.log(descFields);
$('#addDesc').click(function(e) {
var descFields = $('#descFields');
var descLabel = $('#descLabel').val();
var large = '<div class="form-group" id="descField"><div class="input-group"><input type="text" class="form-control" placeholder="Enter Value For ' + descLabel + '" /><span class="input-group-btn"><button class="btn btn-danger" id="removeDesc" type="button">Remove</button></span></div>';
descFields.add(large).appendTo(descFields);
e.preventDefault();
});
$('#removeDesc').click(function(e) {
$(this).remove();
});
});
When the user click on the #removeDesc button , the the field that is added should be removed. I cannot figure out how to achieve this.
There are many ways of doing this, but the simpler for your problem is this one:
$(document).ready(function() {
console.log(descFields);
$('#addDesc').click(function(e) {
var descFields = $('#descFields');
var descLabel = $('#descLabel').val();
var large = '<div class="form-group" id="descField"><div class="input-group"><input type="text" class="form-control" placeholder="Enter Value For ' + descLabel + '" /><span class="input-group-btn"><button class="btn btn-danger" id="removeDesc" type="button">Remove</button></span></div>';
descFields.add(large).appendTo(descFields);
e.preventDefault();
});
$('#descFields').on('click', '#removeDesc', function(e) {
$(this).parents('.form-group').remove();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="descLabel"/>
<button id="addDesc">Add Desc</button>
<div class="col-md-12">
<h3>Added Description Fields</h3>
<div class="col-md-12" id="descFields">
</div>
</div>
Your problem is in the callback to delete the rows. When the document has finished loading you are trying to attach a click event to an object #removeDesc that is still not present in the DOM because it's created on the fly when the user clicks the #addDesc.
That's why you should use:
$('#descFields').on('click', '#removeDesc', function(e) {
$(this).parents('.form-group').remove();
});
As #vijayP suggested before you can use the on() to attach an event handler to the container where you'll be adding the object that is still not present in the DOM. Then you pass in the query selector as the second parameter to filter in execution time which of its children will trigger the event and execute the callback.
My additional trick is that I'm using .parents('.form-group') to select the div containing the group and remove all of the fields that were added instead of removing only the button.
Happy coding!
Add click event for remove button like follows:
$(document).on("click","#removeDesc",function(e) {
$(this).remove();
});

Hiding and showing div series using Javascript

I'm making basic GPA calculator using Javascript.
Here is my code:
<div class="list">
<div class="row">
<div class="col col-50">Subject 1</div>
<div class="col"><input type="text" name ="GR1" placeholder="Grade"></div>
<div class="col"><input type="tel" name="CR1" placeholder="Credits"></div>
</div>
<div class="row">
<div class="col col-50">Subject 2</div>
<div class="col"><input type="text" name ="GR2" placeholder="Grade"></div>
<div class="col"><input type="tel" name ="CR2" placeholder="Credits"></div>
</div>
<button class="button button-positive">
Add Another Field //it can add uptop 10 fields
</button>
</div>
It will increment the same div series while incrementing the input name up to 10 fields. User can click Add Another Field and add a new div field.
In every div field, it only changes the subject and input fields' name with an incrementation of 1.
Question:
What is the best way to achieve this without duplicating the same thing over and over? Or do I need to first create 10 div forms and hide all and show them one by one upon each click? Please give me example.
Here is a solution that is in pure Javascript that will allow you to add up to 10 "field blocks". In the HTML file, put:
<div id="list">
<button onclick="addRow()">Add another field</button>
</div>
And here's the Javascript function to add a new row, and initialise the two first row:
<script type="text/javascript">
window.onload = function() {
addRow();
addRow();
};
function addRow() {
var element = document.getElementById('list');
var nextId = element.childElementCount;
if (nextId <= 10) {
var div = document.createElement('div');
div.setAttribute('class', 'row');
div.innerHTML = '<div class="col col-50">Subject ' + nextId + '</div><div class="col"><input type="text" name ="GR' + nextId + '" placeholder="Grade"></div><div class="col"><input type="tel" name="CR' + nextId + '" placeholder="Credits"></div>';
element.insertBefore(div, element.getElementsByTagName('button')[0]);
}
}
</script>
You can try it online on the following fiddle: https://jsfiddle.net/w82t30r4/
Try jQuery's clone (read about it here)
$(document).ready(function(){
$row = $(".row").clone();
$("button").click(function(){
$(".list").append($row.clone());
})
})
What's happening is that I clone the row to start with (before any data is in it). Then I add a clone of that clone to .list when the button is clicked.

how to remove div from clone(jQuery - remove element's parent row)

I have add clone (more than 3) and remove clone button. when i try to clone
<div class="data-add">
<div class="form-group" id="id1">
<label class="col-lg-2 control-label"> Image* : </label>
<div class="col-lg-10">
<input id="input-702" name="userfile[]" type="file"class="file-loading">
</div>
</div>
<div class="form-group clearfix" id="id2">
<label class="col-lg-2 control-label">option* :
</label>
<div class="col-lg-10">
<select name="option[]" autocomplete="off">
<option>name1</option>
<option>name2</option>
<option>name3</option>
</select>
</div>
</div>
</div>
<button class="add" type="button">Add Another </button>
<button class="remove" id="remove"> remove </button>
$(".add").click(function(){
$("#id1").clone().appendTo(".data-add");
$("#id2").clone().appendTo(".data-add");
});
It clone particular div happening proper. when i click remove its not working
(not able to remove)
$(".remove").click(function(){
$(this).closest("#id1").remove();
$(this).closest("#id2").remove();
});
i have tried this also
$(".remove").click(function(){
$(this).parents("#id1").remove();
$(this).parents("#id2").remove();
});
$(".remove").click(function(){
$("#id1").remove();
$("#id2").remove();
});
when i used like this it removing first clone(first id1 and id2). not removing current clone div
Change ID first of all, like below.
var newId = 10; // Sample ID To Append
var startID = ["id1_", id2_];
$(".add").click(function(){
var oldId = newId;
startID[0].replace(oldId, newId);
startID[1].replace(oldId, newId);
var newId++;
$("#id1").clone().attr('id', startID[0]).addClass("clonedDiv").appendTo(".data-add");
$("#id2").clone().attr('id', startID[1]).addClass("clonedDiv").appendTo(".data-add");
});
Then use the new ID or the common class .clonedDiv to remove them.
Elements having #id1 and #id2 are being added in the DOM dynamically, so you should use .on() function to bind your events e.g.
$(document).on('click', '.remove', function(){
$("#id1").remove();
$("#id2").remove();
});

jQuery select element and next together

I have an auto-generated HTML and I want to group together elements.
Input Html:
<div class="editor-label"><label for="StringField">StringField</label></div>
<div class="editor-field"><input id="StringField" type="text" value="" /></div>
<div class="editor-label"><label for="IntField">IntField</label></div>
<div class="editor-field"><input id="IntField" name="IntField" type="number" value="0" /></div>
<!-- more like above -->
Desired output:
<div class="form-group">
<div class="editor-label"><label for="StringField">StringField</label></div>
<div class="editor-field"><input id="StringField" type="text" value="" /></div>
</div>
<div class="form-group">
<div class="editor-label"><label for="IntField">IntField</label></div>
<div class="editor-field"><input id="IntField" name="IntField" type="number" value="0" /></div>
</div>
I'm trying to use jQuery's next selector to get those groups, and then wrap them, but I'm having trouble getting the items to select as one to use with wrap(). I'm not sure if I can write a single selector to get this, or if I will need to do it iteratively. Here are some of the selectors I've tried.
//selects just the labels
$('.editor-label')
//returns only the .editor-fields
$('.editor-label + .editor-field')
//returns all 4 elements separately
$('.editor-label, .editor-label + .editor-field')
What selector can I use to select the element (.editor-label) and it's next (.editor-field) as one "element"?
You are going to need to do the selection in a for each and not with a selector by itself.
$(".editor-label").each(function() {
var lab = $(this);
var inp = $(lab).next();
lab.add(inp).wrapAll('<div class="wrapper"/>');
});
.wrapper { border: 2px solid black; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="editor-label"><label for="StringField">StringField</label></div>
<div class="editor-field"><input id="StringField" type="text" value="" /></div>
<div class="editor-label"><label for="IntField">IntField</label></div>
<div class="editor-field"><input id="IntField" name="IntField" type="number" value="0" /></div>
Try this
$('.editor-label').each(function(){
var group = $(this).next().addBack().wrapAll('<div class="form-group"></div>');
});
Use .each(), .addBack() and .wrapAll()
jsBin demo
$('.editor-label').each(function(){
$(this).next(".editor-field").addBack().wrapAll("<div class='form-group'/>");
});
.each() will target all the desired elements, inside the callback, find the .next(".editor-field"), addBack the starting selector (the current .editor-label) and wrapAll() inside the desired element
You can use the jQuery siblings method:
$(".editor-label").siblings(".editor-label")
See if this will work.
var fields = $('.editor-field');
$.each(fields, function(index, obj){
var field = $(obj);
var label = field.prev('.editor-label');
field.wrap('<div class='form-group'></div>').before(label);
});

Replace the text inside a div

I got this snippet of code and I would like to replace the "ARRIVAL" text which is between the top and lower level <div> element but I can't figure out a way.
I don't want to use replaceWith , html or similar methods on <div class="left booktext"> because that would replace the rest of html elements. There is an event handler attached to input class="bookfields" and I don't want to lose that. Unfortunately, there is no event delegation.
<div class="left booktext">
ARRIVAL
<div class="bookborder">
<input type="hidden" name="checkin" value="2014-03-05">
<input type="text" class="bookfields hasDatepicker" style="width:65px;" id="checkin-select" placeholder="dd/mm/yyyy">
</div>
</div>
You can use contents() along with replaceWith():
$('.left').contents().first().replaceWith("New Text");
Fiddle Demo
In pure Javascript:
var books = document.querySelectorAll('.booktext');
for (var i = 0, length = books.length; i < length; i++) {
books[i].firstChild.data = "your text";
}
Easier with jQuery though:
$('.booktext').contents().first().replaceWith("your text");
Advice
Is better put text in a span element, with all the benefits of the case.
In this way you can put your text in any order inside div, like:
<div class="left booktext">
<div class="bookborder">
<input type="hidden" name="checkin" value="2014-03-05">
<span>ARRIVAL</span>
<input type="text">
</div>
</div>
And than replace with:
$('.bookborder span').text('my new text');
In pure javascript you can access a text node like this
var bookText = document.querySelector(".booktext");
bookText.firstChild.nodeValue = "Some other text";
see it working here
http://codepen.io/sajjad26/pen/JkAms

Categories