Populate dropdown value inside ng-repeat - javascript

I am facing an issue with my Angular code, while populating the dropdown inside a HTML table (Code given below).
Could you please help me with what should be done inside modify() to populate the dropdown ?
HTML Code:
<table class="table" ng-app="empApp" ng-controller="employeeController">
<thead>
<tr class="info">
<th>Emp Name</th>
<th>Status</th>
<th colspan="2"> </th>
</tr>
</thead>
<tbody>
<tr ng-repeat="emp in employees">
<td>
<div ng-hide="editingData[emp.id]">{{ emp.name }}</div>
<div ng-show="editingData[emp.id]"><input type="text" ng-model="emp.name" /></div>
</div>
</td>
<td>
<div ng-hide="editingData[emp.id]">{{ emp.status.name }}</div>
<select ng-show="editingData[emp.id]" class="form-control" ng-model="emp.status"
ng-options="status.id as status.name for status in statuses"></select>
</td>
<td colspan="2">
<div class="btn-group">
<button type="submit" class="btn btn-primary" ng-hide="editingData[employee.id]" ng-click="modify(emp)">Modify</button>
<button type="submit" class="btn btn-primary" ng-show="editingData[employee.id]" ng-click="update(emp)">Update</button>
</div>
</td>
</tr>
</tbody>
</table>
Javascript Code:
var empApp = angular.module("empApp", []);
empApp.controller('employeeController', function($scope, $http) {
$scope.statuses = [{"id":1,"name":"Active"}, {"id":1,"name":"Inactive"}];
$scope.employees = [{"id":1,"name":"Mark","status":{"id":1,"name":"Active"}},{"id":2,"name":"Sara","status":{"id":2,"name":"Inactive"}}];
$scope.editingData = {};
for (var i = 0, length = $scope.employees.length; i < length; i++) {
$scope.editingData[$scope.employees[i].id] = false;
}
$scope.modify = function(employee){
$scope.editingData[employee.id] = true;
//Set Employee Status correctly here to populate the dropdown
};
});
My problem is I am NOT able to populate the dropdown with the existing value, as show in the diagram below:

I made this plunker, check if it's what you need.
1: Both status are with id 1. Change them
From:
$scope.statuses = [{"id":1,"name":"Active"}, {"id":1,"name":"Inactive"}];
To:
$scope.statuses = [{"id":1,"name":"Active"}, {"id":2,"name":"Inactive"}];
2:Change your select ng-model to emp.status.id.
From:
<select ng-show="editingData[emp.id]" class="form-control" ng-model="emp.status"
ng-options="status.id as status.name for status in statuses"></select>
To:
<select ng-show="editingData[emp.id]" class="form-control" ng-model="emp.status.id"
ng-options="status.id as status.name for status in statuses"></select>
3: Change your buttons ng-hide/ng-show
From:
<div class="btn-group">
<button type="submit" class="btn btn-primary" ng-hide="editingData[employee.id]" ng-click="modify(emp)">Modify</button>
<button type="submit" class="btn btn-primary" ng-show="editingData[employee.id]" ng-click="update(emp)">Update</button>
</div>
To:
<div class="btn-group">
<button type="submit" class="btn btn-primary" ng-hide="editingData[emp.id]" ng-click="modify(emp)">Modify</button>
<button type="submit" class="btn btn-primary" ng-show="editingData[emp.id]" ng-click="update(emp)">Update</button>
</div>
Update:
As #Rajesh said below you can store the status_id instead of entire status object. Check his fiddle.

Just replace your select tag part with this code
<select ng-show="editingData[emp.id]" class="form-control" ng-model="emp.status"
ng-options="status as status.name for status in statuses track by status.id"></select>
This is because in ng-model you are passing the full object and you need the full object to be tracked by ID in order to fill the dropdown and relevant dropdown value to be selected
Also in your buttons:
<div class="btn-group">
<button type="submit" class="btn btn-primary" ng-hide="editingData[emp.id]" ng-click="modify(emp)">Modify</button>
<button type="submit" class="btn btn-primary" ng-show="editingData[emp.id]" ng-click="update(emp)">Update</button>
</div>
Because you are referencing it by 'emp' and not 'employee' inside ng-repeat as it will be dynamic

You are looping through
<tr ng-repeat="emp in employees">
But in the select list, you are toggling based on:
editingData[employee.id]
Try changing that to
editingData[emp.id]

use emp.id in your button and also in your modify function and loop
use $scope.employees[i].isVisible = false and ng-hide = $scope.employees.isVisible ng-show = $scope.employees.isVisible

Related

Angular2 Javascript Push - Add item to array

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>

AngularJS add row in table

I use angularJS and I have one table on my page, I made one button to add row with input fields. My solution work good for adding rows and value of input fields in form, but doesn't work well where I need to delete particular row. I use one function for form, and another for adding and deleting rows.
It's like this:
<div ng-init="tmplCtr.newPeople()">
<div class="col-lg-12">
<input name="postsubmit" class="btn btn-default btn-sm" type="submit" value="Save table" ng-click="tmplCtr.newTable(tmplCtr.table)" />
<button class="btn btn-default btn-sm" ng-click="tmplCtr.editRow()">Add row</button>
</div>
<form name="peopleForm" novalidate>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th class="place-name">Name</th>
<th class="place-value">Lastname</th>
<th class="place-options">Options</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="people in tmplCtr.peoples">
<td class="place-name"><input type="text" name="" class="form-control" autocomplete="off" ng-model="tmplCtr.peoples.values[$index].name"></td>
<td class="place-last"><input type="text" name="" class="form-control" autocomplete="off" ng-model="tmplCtr.peoples.values[$index].lastname"></td>
<td class="place-options"><button class="btn btn-danger btn-md btn-delete" ng-click="tmplCtr.editRow($index)">Delete</button></td>
</tr>
</tbody>
</table>
</div>
</form>
When I press button add row I get row, but when I press delete row I delete row from screen but last row in array, not by index. Beside that also value of that row is not deleted from form scope. Function is:
function editRow(item) {
if(item == undefined) {
vm.peoples.push({});
} else {
vm.peoples.splice(item,1);
}
}
Can anyone help me?
I think its better to make two functions, the first one is for adding items, and the second one is for deleting like below:
function addEmptyItem(){
vm.peoples.push({});
}
function deleteItem(index){
vm.peoples.splice(index, 1);
}
Then in your view you can change tmplCtr.editRow($index) --> tmplCtr.deleteItem($index)
Furthermore it is strongly advised to use this syntax person.name etc in your repeat directive.
EDIT:
This is not tested by the way...

how to submit a non-form element using angular2

<tbody>
<tr *ngFor="let gasType of staffConfig.gasTypes">
<td class="col-md-3">
<input class="gas-name form-control" type="text" [(ngModel)]="gasType.name" name="gasName"
[disabled]="!isStaffEnabled">
</td>
</tr>
</tbody>
</table>
</div>
<div class="panel panel-default">
<!-- Default panel contents -->
<div class="panel-heading">
<h3 class="panel-title">
<img src="/assets/brand-icon.png">
<span>Brands</span>
</h3>
</div>
<!-- Table -->
<table class="table">
<tbody>
<tr *ngFor="let brand of staffConfig.brands;let i = index;">
<td>
<input class="form-control" type="text" [(ngModel)]="brand.name" name="brands"
[disabled]="!isStaffEnabled">
</td>
</tr>
</tbody>
</table>
</div>
</tab>
<button id="saveChangesBtn" type="button" class="btn btn-primary" disabled>Save Changes</button>
I want to bind the "save" button to a method in the component. So I changed:
<button id="saveChangesBtn" type="button" (ngSubmit)="registerUser(registrationForm.value) class="btn btn-primary" disabled>Save Changes</button>
but then, if that's not a <form> how do I bind the fields to a model?
In other words how can I send these fields to the server?
I have to read them from the component and then assemble an object.
But how can I access the non-form model like registrationForm.value?
If you are using ngModel outside of the <form> you must specify [ngModelOptions]={standalone:true}.
Template
<div class="not-a-form">
<input type="text" [(ngModel)]="model.foo" [ngModelOptions]="{standalone: true}" />
<input type="text" [(ngModel)]="model.bar" [ngModelOptions]="{standalone: true}" />
<button type="button" (click)="save(model)"> Send </button>
</div>
Component
#Component({
selector: 'selector',
...
})
class SomeComponent {
model: any = {};
save(data) {
console.log(data);
}
}

ng-Click does not works in ng-repeat table

I have aproblem with angularjs ng-click does not works, my model is not updated.
When I want to read the model variables are empty.
I'm using bootstrap popup to show the model values(title, action is using for validation in a funciton inside controller).
HTML code
<button ng-click="title = 'Add Project'; action='Add'" data-toggle="modal" data-target="#myModal" id="btnOpenPopUpForAdding" class="btn btn-default" title="Add new project"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button>
<table class="table" id="tblProjects" style="display:none;">
<thead>
<tr>
<th>
</th>
<th>
Project Name
</th>
<th>
Project Description
</th>
</tr>
</thead>
<tr ng-repeat="project in projects" >
<td>
<button ng-click="title = 'Update Project'; action='Update'" data-toggle="modal" data-target="#myModal" class="btn btn-default" title="Update project">
<span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
</button>
</td>
<td>
<span>{{project.ProjectName}}</span>
</td>
<td>
<span>{{project.ProjectDescription}}</span>
</td>
</tr>
</table>
#Html.Partial("../ProjectView")
</div>
Partial view
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title">{{title}}</h4>
</div>
<div class="modal-body">
<label for="txtProjectName">Project Name</label>
<input ng-model="singleProject.ProjectName" type="text" class="form-control" style="width:65%" id="txtProjectName" placeholder="Type the project name" />
<br />
<label for="txtProjectDescription">Project Description</label>
<textarea ng-model="singleProject.ProjectDescription" class="form-control" style="width:65%" id="txtProjectDescription" placeholder="Type the project description" rows="4"></textarea>
</div>
<div class="modal-footer">
<button id="btnSave" type="button" class="btn btn-primary" ng-click="ThrowEvent()">Save</button>
<button id="btnCancel" type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
</div>
</div>
Controller code
$scope.ThrowEvent = function () {
if ($scope.action == 'Add')
$scope.AddProject($scope.singleProject);
if($scope.action == 'Update')
$scope.UpdateProject($scope.singleProject);
//if($scope.action == 'Delete')
}
The issue is that ng-repeat creates separate child scopes. In your case ng-click="title = 'Update Project'; action='Update'" where title and action are assigned to the child scope, not the parent.
To fix this you must prefix your model in your controller, for example
$scope.myActions = {title: 'Default Title', action: 'Default action'};
Then you can change ng-click="title = 'Update Project'; action='Update'" to ng-click="myActions.title = 'Update Project'; myActions.action='Update'"
ng-repeat will create a new scope for each iteration.
"title = 'Update Project'; action='Update'" will execute successful, but it will write the values to the sub-scope of ng-repeat and is not visible by the controller.
To solve the issue you can create a data container in the controller
$scope.data = {};
and write to the container
ng-click="data.title = 'Update Project'; data.action='Update'"`

form validation using angularjs

I have a form
<form name="formName">
<table>
<tr>
<td><input type="text" ng-model="validate" required/></td>
</tr>
</table>
</form>
<button type="button" class="btn btn-default" ng-click="validate()">save</button>
as you can see, the button is outside the form.. I want to validate the form when I click the button into $scope.validate();
the question is, how can I achieve that using angularjs ?
It does not matter if button is in or outside the form, the validation is performed always when any of the proprties of the model changes. So the only problem that remains is when to display error message.
btw required is from HTML5 ng-required is the attribute you should use.
The code below displays error message when any of the properties changes
<div ng-app="mod">
<div ng-controller='MCtrl'>
<form name="formName" novalidate>
<table>
<tr>
<td>
<input type="text" name="prop" ng-model="model.property" ng-required="true" />
<span ng-show="formName.prop.$error.required">Required</span>
</td>
</tr>
</table>
</form>
<button type="button" class="btn btn-default" ng-click="validate(formName)">save</button>
</div>
mod.controller('MCtrl', function ($scope) {
$scope.model = { property : ''};
$scope.validate = function(form){
alert(form.$valid);
}
});
If youd like to display the errors only when the form is submitted you add one variable to track it like it the code below (note additional variable in ng-show="formName.prop.$error.required && submitted"
<div ng-app="mod">
<div ng-controller='MCtrl'>
<form name="formName" novalidate>
<table>
<tr>
<td>
<input type="text" name="prop" ng-model="model.property" ng-required="true" />
<span ng-show="formName.prop.$error.required && submitted">Required</span>
</td>
</tr>
</table>
</form>
<button type="button" class="btn btn-default" ng-click="validate(formName)">save</button>
</div>
mod.controller('MCtrl', function ($scope) {
$scope.model = { property : ''};
$scope.submitted = false;
$scope.validate = function(form){
$scope.submitted = true;
alert(form.$valid);
}
});

Categories

Resources