I have created a textbox that has a "+" (Add button) and a "-" (delete button) . And when i click on + , i get one more text-box . And when i click on - , i delete that textbox with its value. To capture the value of the text-box , i use ngModel. I tried it without using a Form. Here the issues i am facing are -
[1.]
When i click on '+' button, i get the textbox successfully and i get its value also. But for subsequent additions when done using "+' button, i get the same value . And when i change its value, the value changes on every other text box done using " + " button.
[2.] I don't know how to delete the value of the text-box from the array-variable.
Please help
code -
app.component.html
<div *ngIf="addContainer">
<p style="margin-left: 200px; font-size:18px">Please enter the API
Object -</p>
<table align="center">
<tbody>
<tr >
<td >
<input type="text" placeholder="Enter a Node" [(ngModel)]= "firstValue">
</td>
<td >
<button type="button" style="margin-left: 10px" (click)="addOne(firstValue)" class="btn btn-success"> + </button>
</td>
<td>
<button type="button" style="margin-left: 10px" (click)="deleteOneMore()" class="btn btn-danger"> - </button>
</td>
</tr>
<tr *ngFor="let container of containers; let i = index;" #myElement>
<ng-container >
<td id="1myElement">
<input *ngIf="addMore" type="text" placeholder="Enter a Node" [(ngModel)]= "addedValue">
</td>
<td id="1myElement">
<button type="button" style="margin-left: 10px" (click)="addOneMore($event)" class="btn btn-success"> + </button>
</td>
<td>
<button type="button" style="margin-left: 10px" (click)="deleteOneMore()" class="btn btn-danger"> - </button>
</td>
</ng-container>
</tr>
<tr>
<td style="text-align:center">
<button type="button" (click)="showGraphs(firstValue,addedValue)" class="btn btn-dark">Search</button>
</td>
</tr>
</tbody>
</table>
</div>
app.component.ts
addOne(firstDropdValue) {
console.log("inside addOne = firstDropdValue = ",
firstDropdValue);
this.addMore = true;
this.containers.push(this.containers.length);
}
addOneMore(addedValue)
{
this.moreValues.push(addedValue);
console.log("Inside AddOneMore More Values = ",
this.moreValues);
}
deleteOneMore(){
this.containers.splice(this.index, 1);
}
showGraphs(firstV, addedV) {
console.log("inside showGraphs()");
console.log("firstValue =", firstV, "addedValue = ", addedV);
this.showEwayBill = true;
this.showCollection = true;
this.EwayBill();
this.Collection();
}
Image -
You should maintain an array for the newly added values like below and your add and remove should look like below
values = ["sometext"];
addOneMore() {
this.values.push("sivakumar");
}
deleteOneMore(index) {
this.values.splice(index, 1);
}
In the template file you can use that values or containers array to loop like below
<table>
<tr>
<td>
<input type="" [(ngModel)]='values[0]'>
</td>
<td>
<button type="button" style="margin-left: 10px" (click)="addOneMore(firstValue)" class="btn btn-success"> + </button>
</td>
<td>
<button type="button" style="margin-left: 10px" (click)="deleteOneMore(i)" class="btn btn-danger"> - </button>
</td>
</tr>
<ng-container *ngFor="let value of values; let i = index;">
<tr *ngIf="i > 0">
<td id="1myElement">
<input type="text" placeholder="Enter a Node" [(ngModel)]="values[i]">
</td>
<td id="1myElement">
<button type="button" style="margin-left: 10px" (click)="addOneMore()" class="btn btn-success"> + </button>
</td>
<td>
<button type="button" style="margin-left: 10px" (click)="deleteOneMore(i)" class="btn btn-danger"> - </button>
</td>
</tr>
</ng-container>
</table>
But, in this solution, still there is one issue that, in the textbox, we are allowing to enter one word at a time, I am not able to figure it out the reason, if anyone can, welcoming you to edit the answer ;-)
Working stackblitz is here
Related
I have a html form with two buttons on it:-
[1] One button is used to upload an image file (.jpg)
[2] and the second one is to submit the form.
The problem is that the upload image button seems to be refreshing the page after the method for uploading the image has completed. Below is my html:-
<div class="m-b-18px">
<div class="col-m-12">
<a (click)="readRecipes()" class="btn btn-primary pull-right">
<span class="glyphicon glyphicon-plus"></span>Read Recipes
</a>
</div>
</div>
<div class="row">
<div class="col-md-12">
<form [formGroup]="create_recipe_form" (ngSubmit)="createRecipe()">
<table class="table table-hover table-responsive table-bordered">
<tr>
<td>
Name
</td>
<td>
<input name="name" formControlName="name" type="text" class="form-control" required />
<div *ngIf="create_recipe_form.get('name').touched && create_recipe_form.get('name').hasError('required')"
class="alert alert-danger">Name is required
</div>
</td>
</tr>
<tr>
<td>
Description
</td>
<td>
<textarea name="description" formControlName="description" class="form-control" required>
</textarea>
<div *ngIf="create_recipe_form.get('description').touched && create_recipe_form.get('description').hasError('required')"
class="alert alert-danger">
Description is required
</div>
</td>
</tr>
<tr>
<td>
Image
</td>
<td>
<input name="selectFile" id="selectFile" type="file" class="form-control btn btn-success" />
<button type="button" class="btn btn-primary" (click)="uploadImage($event)" value="Upload Image">Upload Image</button>
<input type='hidden' id='image_id' name='img_id' value="6" formControlName="image_id" />
</td>
</tr>
<tr>
<td></td>
<td>
<button class="btn btn-primary" type="submit" [disabled]="!create_recipe_form.valid">
<span class="glyphicon glyphicon-plus"></span> Create
</button>
</td>
</tr>
</table>
</form>
</div>
</div>
My code for the uploadImage method is below:-
uploadImage(e) {
let files = this.elem.nativeElement.querySelector('#selectFile').files;
let formData = new FormData();
let file = files[0];
formData.append('selectFile', file, file.name);
this._imageService.uploadImage(formData)
.subscribe(
image => {
console.log(image);
this.addImageIdToHtml(image)
e.preventDefault();
e.stopPropagation();
},
error => console.log(error)
);
}
As soon as the above method has finished running the page appears to refreshing causing my app to go back to the land page. This is not the behaviour I want. What I actually want is the form page to be retained until the Submit form button is pressed. Can anyone help me please?
Use div tags instead of form tag.
Change the button type as button.
<button type="button">Upload Image</button>
Modify the code as follows.
<div class="m-b-18px">
<div class="col-m-12">
<a (click)="readRecipes()" class="btn btn-primary pull-right">
<span class="glyphicon glyphicon-plus"></span>Read Recipes
</a>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div [formGroup]="create_recipe_form" (ngSubmit)="createRecipe()">
<table class="table table-hover table-responsive table-bordered">
<tr>
<td>
Name
</td>
<td>
<input name="name" formControlName="name" type="text" class="form-control" required />
<div *ngIf="create_recipe_form.get('name').touched && create_recipe_form.get('name').hasError('required')"
class="alert alert-danger">Name is required
</div>
</td>
</tr>
<tr>
<td>
Description
</td>
<td>
<textarea name="description" formControlName="description" class="form-control" required>
</textarea>
<div *ngIf="create_recipe_form.get('description').touched && create_recipe_form.get('description').hasError('required')"
class="alert alert-danger">
Description is required
</div>
</td>
</tr>
<tr>
<td>
Image
</td>
<td>
<input name="selectFile" id="selectFile" type="file" class="form-control btn btn-success" />
<button type="button" class="btn btn-primary" (click)="uploadImage($event)" value="Upload Image">Upload Image</button>
<input type='hidden' id='image_id' name='img_id' value="6" formControlName="image_id" />
</td>
</tr>
<tr>
<td></td>
<td>
<button class="btn btn-primary" type="button" [disabled]="!create_recipe_form.valid">
<span class="glyphicon glyphicon-plus"></span> Create
</button>
</td>
</tr>
</table>
</div>
</div>
</div>
You should not upload files on Angular folders like (Assets) , cuz it will recompile every time new file added to Angular environment and that will cause you the page refreshment you didn't want.
If you are using button tag inside the form tag, add type="button" inside the button tag.
<button type="button"></button>
This will work perfectly
I'm building a form in Angular2 which contains a field that is an array of objects. I've so far built the table with a Delete Row button per row and an Add Row button. These use the JavaScript push() and slice() methods.
There is a big bug though:
When adding a new row, the content of the previous rows is deleted.
That is to say, the content of the row is deleted, not the row itself.
Any ideas why?
Component Code:
public addRow(): void {
this.table.push({});
}
public deleteRow(row: object): void {
this.table.splice(this.table.indexOf(row), 1);
}
HTML Template
<form #TimesheetForm="ngForm" (ngSubmit)="saveTimesheet()">
<div class="row">
<div class="col text-right">
<button type="button" class="btn" (click)="addRow()"><i class="fa fa-plus-square" aria-hidden="true"></i> Add Row</button>
</div>
</div>
<table class="table">
<thead>
<td class="table__header">Date</td>
<td class="table__header">Time</td>
<td class="table__header">Actions</td>
</thead>
<tbody>
<tr *ngFor="let row of table">
<td class="table__item">
<input class="input" [(ngModel)]="row.date" name="date">
</td>
<td class="table__item">
<input class="input" [(ngModel)]="row.time" name="time">
</td>
<td class="table__item">
<button type="button" class="btn btn--negative" (click)="deleteRow(row)"><i class="fa fa-times" aria-hidden="true"></i> Delete</button>
</td>
</tr>
<tr *ngIf="school.rows.length == 0">
<td colspan="3">No rows exist yet. Click Add Row to start logging your timesheet.</td>
</tr>
</tbody>
</table>
</div>
<div class="row">
<div class="col">
<button class="btn btn--positive" type="submit"><i aria-hidden="true" class="fa fa-check"></i> Save</button>
</div>
<div class="col text-right">
<button class="btn btn--negative"><i aria-hidden="true" class="fa fa-times"></i> Cancel</button>
</div>
</div>
</form>
With template driven forms, we need to remember that the name attribute needs to be unique, otherwise the fields will be evaluated as the same field. So what your form does now, is not adding new form controls when you add new rows, instead it manipulates the one and same form field. If you were to put something like <pre>{{TimesheetForm.value | json}}</pre> in your template, you can see, that despite pushing new rows, there is only one form control name date and one form control named time.
So what we need to do is to provide an unique name, we can do that by using the index of the items in your table array. So do the following:
<tr *ngFor="let row of table; let i = index">
<td>
<input [(ngModel)]="row.date" name="date{{i}}">
</td>
<td>
<input [(ngModel)]="row.time" name="time{{i}}">
</td>
<!-- more code here -->
</tr>
I get all products from database to my Asp.Net Mvc View. So far so good.
I just put textbox in every row with plus and minus buttons and then Ok button to update Quantity in database.
But every Click goes to the first textbox. Here is my code
<table class="table">
<tr>
<th>
Products
</th>
<th>
Quantity
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Product)
</td>
<td>
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td>
<input type='text' name='qty#(item.ComputerId)' id='qty#(item.ProductId)'/>
<Button class="btn btn-success btn-xs glyphicon glyphicon-plus" name="add" onclick='javascript: document.getElementById(qty#(item.ProductId)).value++;' value='+' />
<Button class="btn btn-warning btn-xs glyphicon glyphicon-minus" name="subtract" onclick='javascript: subtractQty(qty#(item.ProductId));' value='-' />
<button type="button" class="btn btn-primary" onclick="update();">Ok</button>
</td>
</tr>
}
</table>
And JavaScript is:
function subtractQty(name) {
if (document.getElementById(name).value - 1 < 0)
return;
else
document.getElementById(name).value--;
}
But now I get this Error: Uncaught TypeError: Cannot read property 'value' of null
Hi you can try with the following code:
View Code:
#int tempno=0;
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Product)
</td>
<td>
#Html.DisplayFor(modelItem => item.Quantity)
</td>
<td>
<input type='text' name='qty#(tempno)' id='qty#(tempno)' />
<Button class="btn btn-success btn-xs glyphicon glyphicon-plus" name="add" onclick='javascript: document.getElementById("qty").value++;' value='+' />
<Button class="btn btn-warning btn-xs glyphicon glyphicon-minus" name="subtract" onclick='javascript: subtractQty();' value='-' /> |
<button type="button" class="btn btn-primary" onclick="update();">Ok</button>
</tr>
#temp++
}
jquery code:
var row = $(this).closest('tr');
var product = row.find('td:eq(0)').text();
var quantity= row.find('td:eq(1)').text();
Hope it will be helpful
Thanks
Karthik
EDIT
Well you're right, your textboxes probably have the same id. So you can start by giving them different ids to uniquely identify each textbox.
#{
int counter = 0;
foreach (var item in Model)
{
<input type='text' name='counter' id='counter' />
<Button class="btn btn-success btn-xs glyphicon glyphicon-plus" onclick='javascript: document.getElementById("counter").value++;' value='+' />
<Button class="btn btn-warning btn-xs glyphicon glyphicon-minus" onclick='javascript: subtractQty(counter);' value='-' />
counter ++;
}
}
Then you have to alter your JavaScript method subtractQty to know which textbox the increment or decrement should be applied to.
I might tweak your method a little to use the approach below:
function subtractQty(textboxId) {
if (document.getElementById(textboxId).value - 1 < 0)
return;
else
document.getElementById(textboxId).value--;
}
You should give unique names and ids for your text box, you can do this through your loop, like appending item id to the qty
like this
<input type='text' name='qty#Item.ID' id='qty#Item.ID' />
note that I assumed that your id field name is ID which is not correct, change it to the name of your field.
then in your javascript function, add one more param which will take the name which is qty#Item.ID, get the element by name using this param and update its value accordingly
<Button class="btn btn-warning btn-xs glyphicon glyphicon-minus" name="subtract" onclick="javascript: subtractQty(#Item.ID);" value='-' />
your js function
function subtractQty(id) {
if (document.getElementById("qty"+id.toString()).value - 1 < 0)
return;
else
document.getElementById("qty"+id.toString()).value--;
}
In my jQuery code, I want to be able to get the child element within a <tr> element. I have created a jQuery object and named the variable $trElement. However, for some reason calling $trElement.children(".sequence-edit") returns undefined so any further action done on that statement throws an error (since you are invoking a method on an undefined object). I have checked the HTML code of the parent element and it clearly contains a child element with the indicated class name. So why does it not work?
Here is the code I used to debug the issue.
console.log($trElement.html());
console.log($trElement.children(".sequence-edit"));
The first line console.log($trElement.html()); logs:
<td class="sequence-number">#1</td>
<td class="sequence-data">
<form action="editSequence.do" method="POST">
<textarea cols="50" rows="10" name="sequence" class="sequence-data-textarea"></textarea>
<input type="hidden" name="index" value="0">
</form>
</td>
<td class="button-first">
<!-- Element targeting through ".sequence-class" -->
<button type="button" class="btn btn-info sequence-edit center-block display-true">EDIT</button>
<button class="btn btn-info center-block edit-submit display-false" style="display: none;">SUBMIT</button>
</td>
<td class="button-second">
<button type="button" class="btn btn-danger delete-modal-appearance center-block display-true" data-toggle="modal" data-target="#modal-delete-confirmation">DELETE</button>
<button class="btn btn-warning center-block edit-cancel display-false" style="display: none;">CANCEL</button>
</td>
<td>
<input type="checkbox" class="checkbox-delete-selection center-block">
</td>
The second line console.log($trElement.children(".sequence-edit")); logs: undefined
.children() only travels one step into your selector's (trElement) DOM tree, (and those are your <TD>'s, not your <button>).
instead, use .find(".sequence-edit")
https://api.jquery.com/children/
https://api.jquery.com/find/
var $trElement = $("tr");
console.log( $trElement.find(".sequence-edit").html() ); // "EDIT"
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td class="sequence-number">#1</td>
<td class="sequence-data">
<form action="editSequence.do" method="POST">
<textarea cols="50" rows="10" name="sequence" class="sequence-data-textarea"></textarea>
<input type="hidden" name="index" value="0">
</form>
</td>
<td class="button-first">
<!-- Element targeting through ".sequence-class" -->
<button type="button" class="btn btn-info sequence-edit center-block display-true">EDIT</button>
<button class="btn btn-info center-block edit-submit display-false" style="display: none;">SUBMIT</button>
</td>
<td class="button-second">
<button type="button" class="btn btn-danger delete-modal-appearance center-block display-true" data-toggle="modal" data-target="#modal-delete-confirmation">DELETE</button>
<button class="btn btn-warning center-block edit-cancel display-false" style="display: none;">CANCEL</button>
</td>
<td>
<input type="checkbox" class="checkbox-delete-selection center-block">
</td>
</tr>
</table>
I've created a modal window, containing a table with rows of input boxes and buttons:
<table class="datatable tablesort selectable paginate full" width="100%">
<tbody>
<tr id="row_1">
<td><strong><input type="text" value="120040965" id="icpcode">
<button type="button" id="btnSave" class="btn btn-primary">Insert</button></strong>
<p>GRAND VOYAGER WIPER MOTOR REAR 04-08 £35.00</p>
</td>
</tr> <tr id="row_2">
<td><strong><input type="text" value="120040966" id="icpcode">
<button type="button" id="btnSave" class="btn btn-primary">Insert</button></strong>
<p>CHRYSLER GRAND VOYAGER WIPER MOTOR FRONT 01-08 £30.00</p>
</td>
</tr> <tr id="row_3">
<td><strong><input type="text" value="120040964" id="icpcode">
<button type="button" id="btnSave" class="btn btn-primary">Insert</button></strong>
<p>CHRYSLER GRAND VOYAGER MK2 01-08 2.8 CRD GEARBOX AUTOMATIC £500.00</p>
</td>
</tr> <tr id="row_4">
<td><strong><input type="text" value="120040963" id="icpcode">
<button type="button" id="btnSave" class="btn btn-primary">Insert</button></strong>
<p>CHRYSLER GRAND VOYAGER MK2 STOW £80.00</p>
</td>
</tr> <tr id="row_5">
<td><strong><input type="text" value="120040962" id="icpcode">
<button type="button" id="btnSave" class="btn btn-primary">Insert</button></strong>
<p>CHRYSLER GRAND VOYAGER MK2 01-08 WISHBONE DRIVER SIDE £15.00</p>
</td>
</tr> </tbody>
</table>
I then use jQuery to insert the value of the inputbox (icpcode) into the last row of another table and close the open modal and focus on that inputbox:
$('#btnSave').click(function() {
var value = $('#icpcode').val();
$('#tablemain tbody tr:last #itemlookup').val(value);
$('#tablemain tbody tr:last #itemlookup').focus();
$('#productlookup').modal('hide');
});
My problem is that only the first button works, so I need a solution that enables the selected row's value to pass back. I have incremented the tr id, but I'm not sure what I need to do... but I'm presuming it needs something involving $.(this) and also incrementing the inputbox/button. It might be easier to do away with the button and have the row itself to have an onclick? Either way I appreciate any help!
It is because your input boxes all share the same ID and all of your buttons share the same ID. Every element on your page must have a unique ID.
<input type="text" id="input1">
<input type="text" id="input2">
<input type="text" id="input3">
This is the reason only the first button works because it's only finding one element with that ID, and it's the first button, the rest are ignored.
So, to fix the problem, you can either add btnSave as a class to your buttons, like this:
<button type="button" class="btn btn-primary btnSave">
and change your JS to:
$('.btnSave').click(function() {
// do something
});
Or you could change your ID's very slightly, like this:
<button type="button" id="btnSave1" class="btn btn-primary">
<button type="button" id="btnSave2" class="btn btn-primary">
<button type="button" id="btnSave3" class="btn btn-primary">
and your JS would be:
$('button[id^="btnSave"]').click(function() {
// do something
});
What you can do id give them all unique ids and then give them all the same class:
<button type="button" id="row 1" class="btnSave btn btn-primary">Insert</button>
<button type="button" id="row 2" class="btnSave btn btn-primary">Insert</button>
<button type="button" id="row 3" class="btnSave btn btn-primary">Insert</button>
Then use the class as reference and the id for the value;
$('.btnSave').click(function() {
var value = this.id; // this equals 'row 1' | 'row 2' | 'row 3'
// your remaining code here
});
and to get the value of the selected row's text edit, you can reference it by using the button's id to grab the value as shown below and also be ablt to create your table rows using a loop easily and fast.
<table class="datatable tablesort selectable paginate full" width="100%">
<tbody>
<tr>
<td>
<strong>
<input type="text" value="120040965" id="data_1">
<button type="button" id="1" class="btnSave btn btn-primary">Insert</button>
</strong>
<p>GRAND VOYAGER WIPER MOTOR REAR 04-08 £35.00</p>
</td>
</tr>
<tr>
<td>
<strong>
<input type="text" value="120040965" id="data_2">
<button type="button" id="2" class="btnSave btn btn-primary">Insert</button>
</strong>
<p>GRAND VOYAGER WIPER MOTOR REAR 04-08 £35.00</p>
</td>
</tr>
<tr>
<td>
<strong>
<input type="text" value="120040965" id="data_3">
<button type="button" id="3" class="btnSave btn btn-primary">Insert</button>
</strong>
<p>GRAND VOYAGER WIPER MOTOR REAR 04-08 £35.00</p>
</td>
</tr>
</tbody>
</table>
<script>
$('.btnSave').click(function() {
var row = this.id;
var value = $( '#data_' + row ).val();
alert( value );
});
</script>