Issue on how to add jQuery into angular 2 project - javascript

Hi I want to add some jquery code into my angular 2 projet to add input text field dynamically, its work, but the removeTextField doesnt execute when I click on it heres the code:
addTextField(){
var newTextBoxDiv = $(document.createElement('div'))
.attr("id", 'TextBoxDiv' + this.counter);
newTextBoxDiv.after().html('<label>Textbox #'+ this.counter + ' : </label>' +
'<input type="text" name="textbox' + this.counter +
'" id="textbox' + this.counter + '" value="" >'+'<span (click)="removeTextField(this.counter)" class="glyphicon glyphicon-remove pull-right" style="z-index:33;cursor: pointer"> </span>');
newTextBoxDiv.appendTo("#TextBoxesGroup");
this.counter++;
}
removeTextField(currentTextField){
alert(currentTextField);
}
any suggestions, please!!!

Try like this
For example if your input text field is like
<input type="text" class="my-input-field">
In your controller
$(document).click("on", ".my-input-field", ()=>{
//capture the currentTextField using jquery
this.removeTextField(currentTextField);
})
removeTextField(currentTextField){
}
Example
Its a datatable implemented in angular 2.. The update and delete buttons are rendered on the fly.
HTML
<table class="datatable table table-striped table-bordered" (click)="onTableClick($event)"></table>
Controller
onTableClick(event){
if(event.target.className.indexOf('update-row')!= -1){ //will get the class name and check if matches update button class
this.updateRow($(event.target).attr("data-id"))
}
if(event.target.className.indexOf('delete-row')!= -1){ //will get the class name and check if matches delete button class
this.deleteRow($(event.target).attr("data-id"))
}
}

Related

Is there a simpler way to do this script?

I'm learning and trying to put together a little bit of jquery. Admittedly I'm finding it difficult to find a good basics guide, particularly, when adding multiple actions to one page.
I read somewhere that the document listener should only be used once. I believe I'm using it twice here, but not 100% sure how to bring it into one listener.
Also because I've been hacking bits of script together, I think I'm using parts of javascript and parts of jQuery. Is this correct?
A critique of the code below [which does work] and any advice on how best to approach learning jQuery would be most helpful. Thanks.
Script 1 styles a group of 3 radio buttons depending on which one is clicked.
Script 2 appends new inputs to the bottom of a form.
var stateNo = <?php echo $HighestPlayerID; ?> + 1;
$(document).on('click', 'input', function () {
var name = $(this).attr("name");
if ($('input[name="' + name + '"]:eq(1)')[0].checked) {
$('label[name="' + name + '"]:eq(1)').addClass('nostate');
$('label[name="' + name + '"]').removeClass('selected');
}
else {
$('label[name="' + name + '"]').removeClass('nostate selected');
if ($('input[name="' + name + '"]:eq(0)')[0].checked) {
$('label[name="' + name + '"]:eq(0)').addClass('selected');
}
else {
$('label[name="' + name + '"]:eq(2)').addClass('selected');
}
}
});
$(document).on('click', 'button[name=btnbtn]', function () {
var stateName = 'state[' + stateNo + ']';
var newPlayerAppend = `` +
`<tr><td>` +
`<input type="hidden" name="state['` + stateNo + `'][PlayerID]" value="` + stateNo + `" /></td>` +
`<td><input name="` + stateName + `[Name]" value="Name"></td>` +
`<td><input name="` + stateName + `[Team]" type="radio" value="A">` +
`<td><input name="` + stateName + `[Team]" type="radio" value="">` +
`<td><input name="` + stateName + `[Team]" type="radio" value="B">` +
`</td></tr>`;
$("tbody").append(newPlayerAppend);
stateNo++;
});
HTML for the 3 radio button inputs
<td class="Choice">
<label name="state[1][Team]" class="teampick Astate ">A
<input name="state[1][Team]" type="radio" value="A" />
</label>
<label name="state[1][Team]" class="smallx nostate ">X
<input name="state[1][Team]" type="radio" value="" checked />
</label>
<label name="state[1][Team]" class="teampick Bstate">B
<input name="state[1][Team]" type="radio" value="B" />
</label>
</td>
Some of the code can be written more concisely, or more the jQuery way, but first I want to highlight an issue with your current solution:
The following would generate invalid HTML, if it were not that browsers try to solve the inconsistency:
$("tbody").append(newPlayerAppend);
A tbody element cannot have input elements as direct children. If you really want the added content to be part of the table, you need to add a row and a cell, and put the new input elements in there.
Here is the code I would suggest, that does approximately the same as your code:
$(document).on('click', 'input', function () {
$('label[name="' + $(this).attr('name') + '"]')
.removeClass('nostate selected')
.has(':checked')
.addClass(function () {
return $(this).is('.smallx') ? 'nostate' : 'selected';
});
});
$(document).on('click', 'button[name=btnbtn]', function () {
$('tbody').append($('<tr>').append($('<td>').append(
$('<input>').attr({name: `state[${stateNo}][PlayerID]`, value: stateNo, type: 'hidden'}),
$('<input>').attr({name: `state[${stateNo}][Name]`, value: 'Name'}),
$('<input>').attr({name: `state[${stateNo}][Team]`, value: 'A', type: 'radio'})
)));
stateNo++;
});
There is no issue in having two handlers. They deal with different target elements, and even if they would deal with the same elements, it would still not be a real problem: the DOM is designed to deal with multiple event handlers.
There are 2 places you are using anonymous functions. If the code block moves to a named function, the entire code becomes more maintainable. It also helps better in debugging by telling you upfront which function name the error may lie in.
Once you have named functions you will realise that you really do have 2 event listeners for click. So there isn't much benefit of moving them in one listener (or one function you may be referring to). These both event listeners attach on document object and listen to a click event.
Class names are always better when hyphenated. a-state over Astate.
If it works it is correct code, for once you asked about correctness.
It is absolutely fine to have multiple listeners but I usually prefer making everything under one roof. Consider making code as simple as possible which saves lot of time during maintenance.
you can use $(function() {}) or document.ready().
$(document).ready(function() {
$('input[type="radio"]').click(function() {
var thisa = $(this).parent();
var name = $(this).attr("name");
// Remove :selected class from the previous selected labels.
$('label[name="' + name + '"]').removeClass('selected');
// Add conditional class with tenary operator.
thisa.parent().hasClass("smallx") ? thisa.addClass('nostate') : thisa.addClass('selected');
});
$('button[name=btnbtn]').click(function() {
var stateName = 'state[' + stateNo + ']';
// Add TR and TD before appending the row to tbody
var newPlayerAppend = `<tr><td>` +
`<input type="hidden" name="state['` + stateNo + `'][PlayerID]" value="` + stateNo + `" />` +
`<input name="` + stateName + `[Name]" value="Name">` +
`<input name="` + stateName + `[Team]" type="radio" value="A"></td></tr>`;
$("tbody").append(newPlayerAppend);
stateNo++;
});
});
Hope this helps.

How to add checkboxes dynamically using javascript?

I use Bootstrap and have a form with 2 textfields and 2 checkboxes. With an add-Button, I want to add (per click) an additional textfield with checkbox. Currently I'm using this JS:
$("#addButton").click(function () {
var newTextBoxDiv = $(document.createElement('div'))
.attr("id", 'TextBoxDiv' + counter);
/* TODO: patterns festlegen */
newTextBoxDiv.after().html('<div class="form-group label-floating">' +
'<label class="control-label">Answer' + counter + '</label>' +
'<input type="text" class="form-control"/>' +
'</div><div class="togglebutton"><label><input type="checkbox" checked="">Toggle is on</input></label></div>');
newTextBoxDiv.appendTo("#AnswerGroup");
counter++;
});
It adds successfully the textfield, but the checkbox isn't showing up, only the text "Toggle is on".
How can I solve this? I inserted the JS inside $(document).ready(function () {.
EDIT I think the CSS causes the problem. When I simply add '</div><input type="checkbox" checked=""/></div>', it only shows the checkbox without UI. After adding the rest (like class="togglebutton", I see nothing.
The markup for your checkbox is not correct:
<label><input type="checkbox" checked="">Toggle is on</input></label>
should be
<label><input type="checkbox" checked="" />Toggle is on</label>
May be because input tag has no closing pair.
Try
'<input type="checkbox" checked="">'
And it has to have "name" attribute
Tested answer
<html>
<head>
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>
$( document ).ready(function() {
$("#addButton").click(function () {
var counter = 2; //for sample
var newTextBoxDiv = $(document.createElement('div'))
.attr("id", 'TextBoxDiv' + counter);
/* TODO: patterns festlegen */
newTextBoxDiv.after().html('<div class="form-group label-floating">' +
'<label class="control-label">Answer' + counter + '</label>' +
'<input type="text" class="form-control"/>' +
'</div><div class="togglebutton"><label><input type="checkbox" checked="">Toggle is on</input></label></div>');
newTextBoxDiv.appendTo("#AnswerGroup");
counter++;
});
});
</script>
</head>
<body>
<input type="button" id="addButton" value="hello"/>
<div id="AnswerGroup"> </div>
</body>
</html>
First, instead of $("#addButton").click(function () { get in the habit of doing $("#addButton").on('click', function () {, you'll have more control of the event listener in the future.
Next, var newTextBoxDiv = $(document.createElement('div')).attr("id", 'TextBoxDiv' + counter); should be var newTextBoxDiv = $('<div/>').prop('id', 'TextBoxDiv' + counter);.
Next it seems you are creating content newTextBoxDiv and then inserting content after it. I'm not sure you want to do that. I would think you would want to add content to the box you just made. Additionally, according to .after(), it accepts html as an argument. I believe you calling .html() afterward is just setting the inner HTML of newTextBoxDiv anyway.
As your question specifically; you should be able to create a checkbox with the following syntax:
var checkbox = $('<input/>').attr('type', 'checkbox');
To set it to checked (or unchecked) you use .prop() like this:
checkbox.prop('checked', true); //checks the box.
To set it as an HTML string (and have it checked) I believe you should use the following syntax:
<input type="checkbox" checked>
Try use:
newTextBoxDiv.append(...)
instead of
newTextBoxDiv.after().html(...)

Javascript function for form created using Javascript

I have a script which adds a new form when a button is clicked to a HTML page with the code as following:
<script>
var counter = 1;
var limit = 10;
function addInput(divName){
if (counter == limit) {
alert("Max number of forms, " + counter );
}
else
{
var newdiv = document.createElement('div');
newdiv.innerHTML = "<form name='frmMain' action='prelucrare.php' method='POST'><div class='slot' id='dynamicInput' align='center'> Masina " + (counter +1 ) + "<table border='1'><tr><td align='right'><label for='marca'>Marca:</label></td><td colspan='2' align='left'>"
+ "<select id='marc' name='marc'><option selected value=''></option>"
+ "<tr><td align='right'><label for='motorizare1'> Motorizare:</label></td> <td><input type='range' name='motorizare1[]Input' min='0.6' max='5' step='0.1' value=2 id=motor1 oninput='outputUpdate1(value)'></td><td><output for=motorizare1 id=moto1>2</output></td></tr>"
+ "</div></form>"
;
}
document.getElementById(divName).appendChild(newdiv);
counter++;
}
</script>
<input type="button" value="Adauga" onClick="addInput('dynamicInput');">
And I have the script bellow which changes the value from the slider.
<script>
function outputUpdate1(mot1) {
document.querySelector('#moto1').innerHTML = mot1;
}
</script>
My problem is that the JS code only changes the input for the first form, even if the slider is activated from another form. In short, the slider should return the value in the form from which it is activate; not only in the first form added.
Thank you!
Going along with my comment, the problem is stemming from the id value being the same across all of your output elements (moto1). You've actually got all the variables you need to make them unique since you're tracking a count of the number of forms on the page (your counter variable). You can use this in place of your current output HTML:
"<input type='range' name='motorizare1[]Input' min='0.6' max='5' step='0.1' value=2 id='motor_" + counter + "' oninput='outputUpdate1(value)'/>"
"<output for=motorizare1 id='moto_" + counter + "'>"
You can update your function to parse out the correct index for the output you want to update since they should be in sync if you use the HTML above:
function outputUpdate1(mot) {
// Get the counter part of the range element's id
var index = mot.id.split('_')[1];
document.querySelector('#moto_' + index).innerHTML = mot;
}
You may need to make some tweaks to code you haven't provided in the question, but that's one way of making the id values unique and how to access them without knowing the exact id ahead of time.

Add / Delete Rows from Table

I have created a table in Twitter Bootstrap here
I want to be able to do 2 things with it
Delete rows by pressing delete icon - will delete that row
Add a new name by adding text (name) to input field and then pressing "add new row"
DEMO - http://jsfiddle.net/qxdz4/2/
Looking for a way to do this with JavaScript / jQuery
My Code
<div class="input-prepend input-append"><span class="add-on"><i class="icon-picture"></i></span>
<input class="span2"
id="appendedInputButton" type="text" placeholder="Add New Name Here">
<button class="btn" type="button">Add New Row</button>
</div>
<table id="users" class="table table-bordered table-condensed">
<tr>
<th>name</th>
<th></th>
</tr>
<tr>
<td>Mike
</td>
<td class="taskOptions"> <a href="#deleteProject" rel="tooltip" data-toggle="modal" class="tip-top"
data-original-title="Delete Row"><i class="icon-remove"></i></a>
</td>
</tr>
<tr>
<td>John
</td>
<td class="taskOptions"> <a href="#deleteProject" rel="tooltip" data-toggle="modal" class="tip-top"
data-original-title="Delete Row"><i class="icon-remove"></i></a>
</td>
</tr>
<tr>
<td>Mary
</td>
<td class="taskOptions"> <a href="#deleteProject" rel="tooltip" data-toggle="modal" class="tip-top"
data-original-title="Delete Row"><i class="icon-remove"></i></a>
</td>
</tr>
</table>
Notes
Clicking the delete button should delete the row
Typing into the input field and pressing "add new row" button should add a new
row to the end of the table with the Name filled in
You can easily remove the row by doing this:
$('td.taskOptions a.tip-top').on('click', function(e) {
e.preventDefault();
$(this).tooltip('hide');
$(this).parents('tr').remove();
});
Similarly, adding a new row can be done as follows:
$('button.btn').click(function(e) {
e.preventDefault();
var the_name = $.trim($('#appendedInputButton').val());
var new_row = $('<tr>\
<td>\
'+the_name+'\
</td>\
<td class="taskOptions">\
<i class="icon-remove"></i>\
</td>\
</tr>');
new_row.appendTo($('#users'));
});
Please note that it might be worth adding a more specific class name to the button (when clicked to add the row) to avoid any confusion. An ID would work just as well.
I've updated your jsFiddle with the additional functionality. You can see here.
I don't know how you obtain each row's pk data (data-pk) attribute. That's up to you
On document.Ready
$('[rel=tooltip]').tooltip();
function bindCloseButtons(){
$("#users td.taskOptions a").click(function(e){
$(this).parent().parent().remove();
});
}
function addTableRow(name , pk){
// name column
var row = $("<tr></tr>");
row.append('<td>'+name+'</td>');
// close button
var btnClose = $('<td class="taskOptions"> <i class="icon-remove"></i></td>');
row.append(btnClose);
$("#users").append(row);
bindCloseButtons();
$('[rel=tooltip]').tooltip();
}
$("#addNew").click(function(e){
var name = $("#appendedInputButton").val();
var pk = 1; // TODO: set your pk here
addTableRow(name, pk);
});
bindCloseButtons();
Here's a fiddle:
http://jsfiddle.net/qxdz4/16/
First you create one method AddmultipleInput()
Inside the function,
.AddMultipleInput = function (btnAddId, btnDelId, inputContainerIdPrefix, inputContainerCss, firstChildInputIdPrefix) {
if ($('.' + inputContainerCss).length < 2) {
$('#' + btnDelId).attr('disabled', 'disabled');
}
$('#' + btnAddId).click(function () {
var num = $('.' + inputContainerCss).length; // how many "duplicatable" input fields we currently have
var newNum = new Number(num + 1); // the numeric ID of the new input field being added
// create the new element via clone(), and manipulate it's ID using newNum value
var newElem = $('#' + inputContainerIdPrefix + num).clone().attr('id', inputContainerIdPrefix + newNum);
newElem.children().each(function () {
var idPrefix = $(this).attr('id').substring(0, $(this).attr('id').length - 1);
var namePrefix = $(this).attr('name').substring(0, $(this).attr('name').length - 1);
$(this).attr('id', idPrefix + newNum).attr('name', namePrefix + newNum);
})
// insert the new element after the last "duplicatable" input field
$('#' + inputContainerIdPrefix + num).after(newElem);
// enable the "remove" button
$('#' + btnDelId).attr('disabled', '');
// business rule: you can only add 5 names
if (newNum == 5)
$('#' + btnAddId).attr('disabled', 'disabled');
});
$('#' + btnDelId).click(function () {
var num = $('.' + inputContainerCss).length;
$('#' + inputContainerIdPrefix + num).remove();
$('#' + btnAddId).attr('disabled', '');
if (num == 2)
$('#' + btnDelId).attr('disabled', 'disabled');
});
$('.icon-remove').live('click',function(){
$(this).parent('tr').remove();
});
If you are using jQuery 1.7 or above, then use .on instead of .live.
Add a class to your delete links (like delete-row) and use something like:
$(document).on("click",".delete-row",function(ev) {
ev.preventDefault();
$(this).tooltip('hide');
$(this).parents("tr").first().remove();
});
Note: "$(this).tooltip('destroy');" would be better than "hide", but your fiddle bootstrap version doesn't support destroy yet. Also, you can set $("#users") instead of $(document) as handler for this event if you want, so long as the delete-row buttons are children of the handler the event gets delegated properly.
To add a line the answer of BenM should work perfect.
PS:
.parents(selector) function travels more than one level up the DOM tree, while .parent() travels a single level up the DOM tree.
.parents(selector) function selects all parents that match the selector, so in case there is a change you end up putting a table inside a table (accidentally im sure) you should use .first(), ensuring you dont remove the wrong row.
Edit: As mentioned by BenM, the previous code would not work with new lines, forgot the add part of the question, the new code should work.
I would suggest you yo use following jQuery functions:
on(), click(), remove(), append()
Please do research on this, also look at the jQuery selectors in order to find how to select proper row.

Converting pairs of input elements into json

I have a simple ui which has a link that says "add item". When this is clicked, a pair of input boxes appears below it. If it is clicked again, yet another pair appears. I'm trying to think of the best way to generate these elements and turn it into some sort of json array of key value pairs (the first input element in each pair being the key and the second input element being the value).
Right now I just have a counter and I generate the ids using it, such as (in the click event of the "add item" link):
$('#features').append('<input id="feature-name-' + self.featureCount + '" type="text" name="asdf" /><a class="delete-feature" data-id="' + self.featureCount + '">Delete</a><input id="feature-description-' + self.featureCount + '" type="text" name="asdf" />');
I don't know what to use as the "name" attributes in order to make it easy to create a json array from them.
you can do something like this without using id attributes.
$('#features').append('<div><input type="text" />
<a class="delete-feature" data-id="' + self.featureCount + '">Delete</a><input type="text" /></div>');
And your javascript,
var yourArray=[];
$('#yourButton').click(function(){
$('#features div').each(function(){
var div=$(this);
var k=$('input:first',div).val();
var v=$('input:first',div).next().val();
yourArray.push({key:k, value: v});
});
});
It doesn't matter what you use for a name attribute, so long as there name and description names are different. Let's say that these elements are all appended to a form with the id myform. Give each pair its own wrapper object. Here, I've used a div, but a fieldset is equally appropriate.
$('#features').append(
'<div class="feature-div">
'<input id="feature-name-' + self.featureCount + '" type="text" name="asdf" />' +
'<a class="delete-feature" data-id="' + self.featureCount + '">Delete</a>' +
'<input id="featurena-description-' + self.featureCount + '" type="text" name="asdf" />' +
'</div>');
Now, it's possible to extract each pair sensibly:
var myarray = [];
$('#myform .feature-div').each(function(i, v) {
myarray.push([
$('input[name=name]', v).val(), $('input[name=description]', v).val()]);
});
Or however you want the data to be presented.

Categories