Dynamic nested list : insert line on click, after current element - javascript

I am struggling with a list that can be drag/dropped and nested.
How it should work :
1.Each row has an "add line" button.
2.When this button is clicked, I am trying to insert a new line, which is a text box, directly below/after the element where the button was clicked
3.Then get/add a unique ID for the new element/row.
4.Lastly once typing text in the new elements text box, get this text (to post to server).
The Javascript looks like this now :
$(document).on('click', '#addLabel_Item', function () {
var tree_id = ($(this).prop("title"));
var $tree_box = '#' + tree_id;
var $tree_box_item = '#' + tree_id + ' li';
var currentListItem = $(this).closest(".listed").attr("id");
var $items=$('.listed');
var parentID = $items.index($(this).closest(".listed"));
$("#list_reference_2").show();
//$("#list_reference_2").clone(true).insertAfter($("li").closest("ol#top_list_items li:eq(" + parentID + ")"));
//$("#list_reference_2").clone().insertAfter('ol > li:nth-child(1)');
$("#list_reference_2").clone().insertAfter("ol li:eq(" + parentID + ")");
});
Right now if I click to add a new line, it adds to the proper place on the initial/first click on the button. However, subsequent clicking on a different button adds the lines under the initial/first row rather than under the current one just clicked.
Fiddle showing what it does
Apologies if my explanation is confusing, I am confusing myself a bit :-)
Any help or point in the right direction would be greatly appreciated.

You can add the lines in this way:
$(document).on('click', '#addLabel_Item', function () {
var $li = $(this).closest('.listed');
$("#list_reference_2").show();
$li.after($("#list_reference_2").clone().removeAttr('id'));
$("#list_reference_2").hide();
});
JSFiddle: http://jsfiddle.net/tx7hbkjL/15/
PS: Take a look at your duplicate IDs, like #addLabel_Item. IDs must be unique in the page, use class instead.
Give it a try and let me know if it helps!

Related

JQuery: Finding a way to name cloned input fields

I'm not the best at using jQuery, but I do require it to be able to make my website user-friendly.
I have several tables involved in my website, and for each the user should be able to add/delete rows. I created a jquery function, with help from stackoverflow, and it successfully added/deleted rows. Now the only problem with this is the names for those input fields is slightly messed up. I would like each input field to be an array: so like name[0] for the first row, name[1] for the second row, etc. I have a bunch of tables all with different inputs, so how would I make jQuery adjust the names accordingly?
My function, doesn't work completely, but I do not know how to go about changing it.
My Jquery function looks like:
$(document).ready(function() {
$("body").on('click', '.add_row', function() {
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
var clone = tr.clone();
clone.find("input").val('');
clone.find("select").val('');
clone.find('input').each(function(i) {
$(this).attr('name', $(this).attr('name') + i);
});
clone.find('select').each(function(i) {
$(this).attr('name', $(this).attr('name') + i);
});
tr.after(clone);
});
$("body").on('click', '.delete_row', function() {
var rowCount = $(this).closest('.row').prev('table').find('tr.ia_table').length;
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
if (rowCount > 1) {
tr.remove();
};
});
});
I also created a jsFiddle here: https://jsfiddle.net/tareenmj/err73gLL/.
Any help is greatly appreciated.
UPDATE - Partial Working Solution
After help from a lot of users, I was able to create a function which does this:
$("body").on('click', '.add_row', function() {
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
var clone = tr.clone();
clone.find("input").val('');
clone.find("select").val('');
clone.find('input').each(function() {
var msg=$(this).attr('name');
var x=parseInt(msg.split('[').pop().split(']').shift());
var test=msg.substr(0,msg.indexOf('['))+"[";
x++;
x=x.toString();
test=test+x+"]";
$(this).attr('name', test);
});
clone.find('select').each(function() {
var msg1=$(this).attr('name');
var x1=parseInt(msg1.split('[').pop().split(']').shift());
var test1=msg1.substr(0,msg1.indexOf('['))+"[";
x1++;
x1=x1.toString();
test1=test1+x1+"]";
$(this).attr('name', test1);
});
tr.after(clone);
});
A working jsFiddle is here: https://jsfiddle.net/tareenmj/amojyjjn/2/
The only problem is that if I do not select any of the options in the select inputs, it doesn't provide me with a value of null, whereas it should. Any tips on fixing this issue?
I think I understand your problem. See if this fiddle works for you...
This is what I did, inside each of the clone.find() functions, I added the following logic...
clone.find('input').each(function(i) {
// extract the number part of the name
number = parseInt($(this).attr('name').substr($(this).attr('name').indexOf("_") + 1));
// increment the number
number += 1;
// extract the name itself (without the row index)
name = $(this).attr('name').substr(0, $(this).attr('name').indexOf('_'));
// add the row index to the string
$(this).attr('name', name + "_" + number);
});
In essence, I separate the name into 2 parts based on the _, the string and the row index. I increment the row index every time the add_row is called.
So each row will have something like the following structure when a row is added...
// row 1
sectionTB1_1
presentationTB1_1
percentageTB1_1
courseTB1_1
sessionTB1_1
reqElecTB1_1
// row 2
sectionTB1_2
presentationTB1_2
percentageTB1_2
courseTB1_2
sessionTB1_2
reqElecTB1_2
// etc.
Let me know if this is what you were looking for.
Full Working Solution for Anyone Who needs it
So after doing loads and loads of research, I found a very simple way on how to do this. Instead of manually adjusting the name of the array, I realised that the clone method will do it automatically for you if you supply an array as the name. So something like name="name[]" will end up working. The brackets without any text has to be there. Explanation can't possible describe the code fully, so here is the JQuery code required for this behaviour to work:
$(document).ready(function() {
$("body").on('click', '.add_row', function() {
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
var clone = tr.clone();
clone.find("input").val('');
tr.after(clone);
});
$("body").on('click', '.delete_row', function() {
var rowCount =
$(this).closest('.row').prev('table').find('tr.ia_table').length;
var tr = $(this).closest('.row').prev('table').find('tr.ia_table:last');
if (rowCount > 1) {
tr.remove();
};
});
});
A fully working JSfiddle is provided here: https://jsfiddle.net/tareenmj/amojyjjn/5/
Just a tip, that you have to be remove the disabled select since this will not pass a value of null.

Adding component to container doesn't work

I could hardly found an easier example but for some unknown reason i have problems with this few lines of code. I dynamically create buttons and add them to my container to the end.
I don't know why but only the first button is added. Please help
Code:
var buttonCount = this.getFoldersContainer().query('button').length;
var button = Ext.create('Ext.button.Button');
button.id = 'folderButton' + record.get('id');
button.setText(record.get('name') + " >>");
console.debug('count');
console.debug(buttonCount);
this.getFoldersContainer().insert(buttonCount,button);
I created a new blank project with only this functionality and it works fine. I don't have a clue what could be causing this in my existing project.
First you should be sure that all buttons get a application wide unique id!
Next is that the id should be present at construction time of the button (in your case it will not be critical but I recommend it). It makes no sense when you are saying that add() would insert at the beginning, because it always insert at the end!
// ....getFoldersContainer().query('button').length; // count all the items!!
// you may do a check if the id is unique while debugging
if(Ext.getCmp('folderButton' + record.get('id')) != null)
console.error('Id duplicated! >> ','folderButton' + record.get('id'))
var ct = this.getFoldersContainer(),
itemCount = ct.items.getCount(),
button = Ext.create('Ext.button.Button', {text:record.get('name') + " >>",id:'folderButton' + record.get('id')});
ct.insert(itemCount > 0 ? --itemCount : itemCount ,button);
// if you just want to insert at the end you will be fine with
// ct.add(button);

Displaying a div when clicking on a link only works for the first one of a list

I am having a bit of trouble finding what is wrong with my code, it is supposed to display a hidden popUp when I click a link (id= lnkInfo) on a div, the problem is that it only works for the first div and not for the others on a list.
This is the code I was using to hide nd display:
JS
function displayPopUp(pIdDivToShow){
var fElementDivToShow = document.getElementById(pIdDivToShow),
newClass ='';
newClass = fElementDivToShow.className.replace('hide','');
fElementDivToShow.className = newClass + ' show';
}
function hidePopUp(pIdDivToShow){
var fElementDivToShow = document.getElementById(pIdDivToShow),
newClass ='';
newClass = fElementDivToShow.className.replace('show','');
fElementDivToShow.className = newClass + ' hide';
}
Said divs are created via php, as does the information that goes inside the pop up, so to show exactly what is going on I made a fiddle out of it with how it would look when I have two divs, the id of the lab divs is always the last one's id+1.
Fiddle EDITED
I know that I should use a class instead of a id, but doing so makes the JS part to malfunction, even if I use querySelector or getByClass.
Any help would be deeply appreciated! Thanks in advance.
EDIT:
So I was thinking something along these lines to do what was suggested and apply the changes to each element. Prettu sure that is not how I attach the array to the displayPopUp thou.
var elementoVerInfo = document.getElementsByClassName('lnkInfo'),
elementoBotonCerrar = document.getElementById('btnCerrar');
elementoVerInfo.addEventListener('click', function () {
for (var i = 0 ; i < elementoVerInfo.length; i++) {
elementoVerInfo[i].displayPopUp('popUpCorrecto1');
};
});
ID's must be unique.
You will have to change the id to a class and use something like document.getElementsByClassName

The first letter of each <h3> into a hyperlink

Using javascript I'm looping through my H3 elements like this:
$('h3').each(function(){ });
I'm then generating an anchor for that tag formatted like this: "section-x" where x increments for each H3 on the page. The problem I have is that I'd like the first letter of the header to be an anchor link, like this:
*H*eading
.. where H is underlined, representing a link. I can format the anchors however I don't know how to wrap a hyperlink tag around the first letter in each heading. Some help would be greatly appreciated.
Regards,
kvanberendonck
Something like this?
$('h3').each(function(){
var currentHeading = $(this).text();
$(this).html("<a href='link'>" + currentHeading.substr(0,1) + "</a>" + currentHeading.substr(1, currentHeading.length - 1));
});
Let's throw some plain javascript into the mix:
$('h3').html(function(i){
var self = $(this)
, html = self.html()
return html[0].anchor('section-'+i) + html.substring(1)
})
html (and most other setter functions) accepts a function as an argument and uses the return value for each element
"string".link(target) creates the code string. A nice vintage useful method
edit: switched from .link to .anchor. Anchors are deprecated though, you should start using IDs for that:
$('h3').html(function(i){
var self = $(this)
, text = self.text()
// give the H3 an id and link to it
// ideally the headers should already have an id
this.id = 'section-'+i
return text[0].link('#section-'+i) + text.substring(1)
})
$('h3').each(function(i){
var firstLetter = $(this).text()[0];
$(this).html('' + firstLetter + '' + $(this).text().substr(1));
});
Not sure where you'd like to put section-x in that heading, but you can use i inside that each() to get the current iteration index.

using replaceWith on all child inputs JQuery

Basically on .show() I've been trying to have all of the inputs convert to image tags with the img src equaling the original inputs value like this:
var currentPage = $('.three_paj_els:visible');
var nextPage = currentPage.next('.three_paj_els');
var the_parent_div_id = currentPage.attr('id');
nextPage.show(function() {
$('div#' + the_parent_div_id + ':input').each(function() {
var the_image_SRC = $(this).val();
$(this).replaceWith('<img src="' + the_image_SRC + '" ')
})
})
Been at it for a few hours now. I want only the ones in that specific div that gets shown to convert.
here's a fiddle of what I've been working on http://jsfiddle.net/Utr6v/100/
when you click the next button, the <input type="hidden" /> tags should convert to <img> tags and the images should show.
Thanks a bunch in advance.
-Sal
currentPage doesn't seem to have an ID. But you're overcomplicating it - if you have the element, you can use that to execute jQuery functions on. You don't need to do an element -> ID -> element conversion since that's pointless.
To find descendants you need to put a space between the element selector and the descendant selector, otherwise the selector applies to the elements themselves. In your case, you can just use .find.
Also, you were missing the closing tag of the image.
http://jsfiddle.net/Utr6v/101/
// I guess you want to replace with images on the new page, not the one
// which gets hidden
nextPage.find(':input').each(function() {
var the_image_SRC = $(this).val();
$(this).replaceWith('<img src="' + the_image_SRC + '">')
});

Categories