Remove item in *ngFor from *ngFor with Angular - javascript

I would like to remove item in *ngFor from *ngFor.
When I removed the reply 'test2',
and after I added an other reply, the 'test3' became empty.
<hello name="{{ name }}"></hello>
<form #form="ngForm" (ngSubmit)="submit()" ngNativeValidate class="mt-4">
<div *ngFor="let content of contents; let indexContent = index; let firstContent = first;">
<div *ngFor="let message of content.messages; let indexMessage = index; let firstMessage = first;">
<table>
<thead>
<tr>
<th>Id</th>
<th>Text</th>
<th class="text-right">Action</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let reply of message.replies; let indexReply = index; let firstReply = first;">
<td [innerHtml]='reply.id'></td>
<td>
<input type="text"
id="{{indexContent}}-{{indexMessage}}-{{indexReply}}-reply-text"
[(ngModel)]=content.messages[indexMessage].replies[indexReply].text
name="[[indexContent]]-[{{indexMessage}}]-[{{indexReply}}]-reply-text">
<br>
<span [innerHtml]="contents[indexContent].messages[0].replies[indexReply].text"></span>
</td>
<td>
<span (click)="message.removeReply(reply)">Remove Reply</span>
</td>
</tr>
</tbody>
</table>
<br>
<span (click)="message.addNewReply()">
Add Reply
</span>
</div>
</div>
<br>
<button type="submit" class="btn btn-primary">Save</button>
</form>
And my message model with different function to add reply, remove reply
message.model.ts
import { Reply } from "./reply";
export class Message {
constructor(public id: number = 0,
public text: string = '',
public replies: any[] = []) {
}
public setModel(obj) {
Object.assign(this, obj);
}
addReply(new_reply) {
this.replies.push(new_reply);
}
addNewReply() {
let new_reply = new Reply();
this.replies.push(new_reply);
}
removeReply(reply) {
this.replies.splice(this.replies.indexOf(reply), 1);
}
}
I reproduce my problem just here: Remove object from array in *ngFor in Angular
https://stackblitz.com/edit/angular-clmi7d

I would use trackBy option to avoid unexpected situations
html
<tr *ngFor="let reply of message.replies; trackBy: trackByFn;
^^^^^^^^^^^^^^^^^^
app.component.ts
trackByFn(i: number) {
return i
}

What you need here, is standalone ng-model option. Also, I would simplify ngModel and innerHtml bindings
<input type="text"
id="{{indexMessage}}-{{indexReply}}-reply-text"
[(ngModel)]="reply.text"
[ngModelOptions]="{standalone: true}"
name="{{indexMessage}}-{{indexReply}}-reply-text" />
<span [innerHtml]="reply.text"></span>
Another option would be using ngFor trackBy as it was suggested by #yurzui, in that case standalone is not needed.
You also have an issue with Reply.id. As a temporary workaround you may try following approach:
let maxId = 0;
export class Reply {
constructor(public id: number = 0, public text: string = '') {
this.id = this.id || ++maxId;
}
}

Related

Validation of HTML table cell and changing background color using Javascript

This is HTML table and I want to validate it in such a way that if user clears entry, the background color of particular cell should be turned red. Code for model should be in JavaScript or Typescript. Please don't provide jQuery solutions
app.component.html
<table class="material-table">
<thead>
<tr>
<th></th>
<!-- <th *ngFor="let schema of tableSchema">
{{ schema.field }}
</th> -->
</tr>
</thead>
<tr *ngFor="let rowData of tableData">
<td value="Delete" (click)="deleteRow(rowData)">X</td>
<td
*ngFor="let schema of tableSchema"
[class.red-text]="!rowData[schema.field].valid"
>
<span
#el
contenteditable
(blur)="rowData[schema.field].value = el.innerText"
>
{{ rowData[schema.field].value }}
</span>
</td>
</tr>
</table>
You can use Attribute directives:
JS
import { Directive, ElementRef, HostListener, KeyValueDiffers } from '#angular/core';
#Directive({
selector: '[requiredHighlight]'
})
export class HighlightDirective {
constructor(private el: ElementRef) { }
color = "red";
#HostListener('input') onChange() {
this.highlight();
}
private highlight() {
const color = this.el.nativeElement.innerHTML ? null: this.color;
this.el.nativeElement.style.backgroundColor = color;
}
}
HTML Template:
<td *ngFor="let schema of tableSchema">
<span #el contenteditable requiredHighlight (blur)="rowData[schema.field].value = el.innerText" >
{{ rowData[schema.field].value }}
</span>
</td>
Use NgClass.
<td *ngFor="let schema of tableSchema" [ngClass]="{'red-text':!rowData[schema.field].valid}">
<span #el contenteditable (blur)="rowData[schema.field].value = el.innerText">
{{ rowData[schema.field].value }}
</span>
</td>

save table data angular 2 created from ngFor

I am creating an editable table from the data that I am getting from the back end now I want to save the data that has been updated.
I have tried using formControl but it only save the data that is in the last column
Here is my code
<form [formGroup]="pagesForm">
<tr *ngFor="let data of pagesArray; let i = index; trackBy: trackByFn">
<td style="text-align: center;" >
<input type="text" formControlName="nameControl" value=[data.name]>
</td>
<td style="text-align: center;">
<input type="text" formControlName="descriptionControl"
vaue=[data.description]>
</td>
</tr>
<button class="btn btn-common" (click)="submit(pagesForm)">Save</button>
</form>
Can anyone help me to save this table data in bulk
In case of reactive form, which I suggest, especially when dealing with an array... with that you need a FormArray to which you push your values when you get them from the backend.
So you can build your form:
constructor(private fb: FormBuilder) {
this.pagesForm = this.fb.group({
arr: this.fb.array([])
})
}
and when you receive your data, in the callback (subscribe or then if you are using promises) call a method, in this example setFormArray() that populates your form array:
setFormArray() {
let arr = this.pagesForm.controls.arr;
this.pagesArray.forEach(x => {
arr.push(this.fb.group({
name: x.name,
description: x.description
}))
})
}
Then you can modify your template to iterate the formarray:
<form [formGroup]="pagesForm" (ngSubmit)="submit(pagesForm.value)">
<div formArrayName="arr">
<tr *ngFor="let page of pagesForm.controls.arr.controls; let i = index"
[formGroupName]="i" >
<td>
<input type="text" formControlName="name">
</td>
<td>
<input type="text" formControlName="description">
</td>
</tr>
</div>
<button type="submit">Save</button>
</form>
Now you end up with an form object that contains property arr, which is an array of your data.
Here's a demo: http://plnkr.co/edit/zfpbUzkvMLOn8CCermGD?p=preview
Hope this helps! :)

how to create dynamic row in a table javascript angular 2

I am creating a table based on dropdown selection. I am able to display the data for a single selection. I want to create a function for "new button" which will add a row and selected value will be display in new generated row. how can I achieve this using javascript or angular 2.
P.S.I am just a beginner. thanks in advance.
Screenshot
import { NgModule } from '#angular/core';
import { Component, OnInit } from '#angular/core';
import {SelectItem} from 'primeng/primeng';
import { FormsModule } from '#angular/forms';
import {ButtonModule} from 'primeng/primeng';
import {DataTableModule,SharedModule} from 'primeng/primeng';
#Component({
selector: 'app-test',
templateUrl: 'app/test/test.component.html',
styleUrls: ['app/test/test.component.css']
})
export class TestComponent implements OnInit {
makes: SelectItem[];
selectedMake: string;
motors: SelectItem[];
selectedMotorType: string;
poles: SelectItem[];
selectedPole: string;
}
constructor() {
this.makes = [];
this.makes.push({label:'Select makes', value:null});
this.makes.push({label:'Siemens', value:{id:1, name: 'Siemens', code: 'Siemens'}});
this.makes.push({label:'ABS', value:{id:2, name: 'ABS', code: 'ABS'}});
this.motors = [];
this.motors.push({label:'Select Motor Type', value:null});
this.motors.push({label:'IE1', value:{id:11, name: 'IE1', code: 'IE1'}});
this.motors.push({label:'IE2', value:{id:12, name: 'IE2', code: 'IE2'}});
this.motors.push({label:'IE3', value:{id:13, name: 'IE3', code: 'IE3'}});
this.poles = [];
this.poles.push({label:'Select Pole Type', value:null});
this.poles.push({label:'2 Pole', value:{id:21, name: '2Pole', code: '2Pole'}});
this.poles.push({label:'4 Pole', value:{id:22, name: '4Pole', code: '4Pole'}});
this.poles.push({label:'6 Pole', value:{id:23, name: '6Pole', code: '6Pole'}});
}
//code for button click new row generate
rows = [{name: ''}];
name = "new";
addRow() {
this.rows.push({name: this.name});
}
//=================
private textValue = "initial value";
private log: string ='result';
private kw: string = 'kw';
private frame: number = 0;
DisplayResult(){
if(this.selectedMake.name=='ABS' && this.selectedMotorType.name=='IE1' ){
alert(this.selectedMake.name);
this.log = 'IABVC5Z' '\n'
this.kw = 'new' '\n'
}}
<div class="container row">
<div class="col-sm-6">
<p class="col-sm-3" >Makes :</p>
<p-dropdown class="col-sm-4" [options]="makes" [(ngModel)]="selectedMake" [style]="{'width':'200px'}" ></p-dropdown>
</div>
</div>
<br>
<div class="container row">
<div class="col-sm-6">
<p class="col-sm-3" >Motor Type :</p>
<p-dropdown class="col-sm-4" [options]="motors" [(ngModel)]="selectedMotorType" [style]="{'width':'200px'}" ></p-dropdown>
</div>
</div>
<br>
<div class="container row">
<div class="col-sm-6">
<p class="col-sm-3" >Pole Type :</p>
<p-dropdown class="col-sm-4" [options]="poles" [(ngModel)]="selectedPole" [style]="{'width':'200px'}" ></p-dropdown>
</div>
</div>
<div class="col-sm-4">
<button class="" pButton type="button" class="ui-button-danger" (click)="addRow()" label = " Add New Motor"></button>
<button class="" pButton type="button" (click)="DisplayResult()" label="Display Result"></button>
</div>
<table id="t01">
<tr>
<th>S.No.</th>
<th>Qty</th>
<th>Type Refrence</th>
<th>KW Rating</th>
<th>Frame Size</th>
<th>Voltage</th>
<th>Frequency</th>
<th>Features</th>
</tr>
<tr *ngFor=" let row of rows">
<td>1</td>
<td><input type="qty" name="qty"></td>
<td>{{log}}</td>
<td>{{kw}}</td>
<td>{{frame}}</td>
<td>415 v</td>
<td>50 Hz</td>
<td></td>
</tr>
</table>
All you need to do is write a function/method inside the component and then call that function/method in the click event if you select the add button
#Component({...})
export class TestComponent {
addRow() {
this.rows.push({
make : this.make,
model: this.model,
pole: this.pole
});
}
The addRow fires when the button is clicked
<button class="" pButton type="button" class="ui-button-danger" (click)="addRow()" label = " Add New Motor">Add New Motor</button>
I also added text between the button tags for display. You must update your table to select the appropriate values to display
<table id="t01">
<tr>
<th>S.No.</th>
<th>Qty</th>
<th>Type Refrence</th>
<th>KW Rating</th>
<th>Frame Size</th>
<th>Voltage</th>
<th>Frequency</th>
<th>Features</th>
</tr>
<tr *ngFor=" let row of rows">
<td>{{ row.make.name }}</td>
<td><input type="qty" name="qty" [row.model]></td>
<td>{{ row.model.log }}</td>
<td>{{ row.model.kw}}</td>
<td>{{ row.model.frame }}</td>
<td>{{ row.model.somethingElse }}</td>
<td>{{ row.pole.simething }}</td>
<td>{{ row.pole.etc }}</td>
</tr>
</table>
I didn't know your data, so just us m selected values from random fields, but that is how you would typically do that

Ng-repeat over localStorage data

This is my partial view
<table class="table table-hover" ng-controller="emailViewController">
<tbody>
<tr >
<td><input type="checkbox" ng-checked="checkAllEmail" ng-model="selectedEmail"/>
<a href="#">
<span class="glyphicon glyphicon-star-empty"></span>
</a></td>
<td><label ng-bind="add"></label></td>
<td><label ng-bind="subject"></label></td>
<td><label ng-bind="emailContent" ></label></td>
</tr>
</tbody>
</table>
I have this data stored in localStorage:
I want to ng-repeat over the values of the keys ngStorage-add and ngStorage-subject. I tried the following:
1) <td><label ng-bind="add" ng-repeat="item in localStorage.getItem('ngStorage-add')"></label></td>.
2) ng-repeat="item in localStorage.getItem('ngStorage-add') track by value"
It did not work however. Does anyone have ideas on how to achieve this?
EDIT
emailViewController:
(function() {
'use strict';
var emailViewController = function (fetchDataService, $scope,$filter,$timeout, $localStorage) {
$scope.to = [];
var url = 'app/mock/emails.json';
fetchDataService.getContent(url)
.then(function(response){
$scope.emails = response.data;
$scope.loadEmails('Primary');
angular.forEach($scope.emails, function(key) {
$scope.to.push(key.to);
});
});
$scope.information = {
add: [],
subject: [],
emailContent: []
};
$scope.typeaheadOpts = {
minLength: 1
};
$scope.$on("decipher.tags.added", function(info, obj) {
$timeout(function(){
tagAdded(info, obj);
});
});
function tagAdded(info, obj) {
for (var i = 0; i < $scope.to.length; i++) {
if ($scope.to[i] === obj.tag.name) {
$scope.to.splice(i, 1);
}
}
}
$scope.close = function(){
//console.log("hide");
$('.modal').modal('hide');
};
$scope.loadEmails = function(searchCriteria){
$scope.filteredEmails = $filter('filterByCategory')
($scope.emails,searchCriteria);
};
$scope.submit = function (add, subject, emailContent) {
if (! ($localStorage.add instanceof Array) ) {
$localStorage.add = [];
}
$localStorage.add.push(add);
if (! ($localStorage.subject instanceof Array) ) {
$localStorage.subject = [];
}
$localStorage.subject.push(subject);
if (! ($localStorage.emailContent instanceof Array) ) {
$localStorage.emailContent = [];
}
$localStorage.emailContent.push(emailContent);
//$scope.update();
};
$scope.clear = function() {
$scope.information.add = [];
$scope.information.subject = '';
$scope.information.emailContent = '';
}
$scope.$on('loadEmail',function(event,data){
$scope.loadEmails(data);
});
};
angular.module('iisEmail')
.controller ('emailViewController',
['fetchDataService', '$scope','$filter', '$timeout', '$localStorage', emailViewController]);
}());
ATTEMPT 1
This is returning the array - $localStorage.add
This is returning the first element of the array (a in this case) - $localStorage.add[0][0]
ATTEMPT 2
I injected $localStorage in the directive that was loading the template. It still does not work.
(function() {
'use strict';
var drafts = function ($localStorage) {
return {
templateUrl : "app/partials/draftsView.html"
};
};
angular.module('iisEmail').directive("drafts", ['$localStorage', drafts]);
}());
ATTEMPT 3
I stored the $localStorage data in a controller variable and got ng-repeat to iterate over the variable.
<td><label ng-repeat="item in addition track by $index">
{{item}}
</label></td>
Doing so produces a result, but the entire array is appearing in one line. I want a to be displayed in one line, and b to be displayed in the next line.
ATTEMPT 3 UPDATE
This is the updated partial view
<table class="table table-hover" ng-controller="emailViewController">
<tbody>
<tr >
<td><input type="checkbox" ng-checked="checkAllEmail" ng-model="selectedEmail"/>
<a href="#">
<span class="glyphicon glyphicon-star-empty"></span>
</a></td>
<td><label ng-repeat="item in addition track by $index">
{{item}}
</label></td>
<td><label ng-bind="subject"></label></td>
<td><label ng-bind="emailContent" ></label></td>
</tr>
</tbody>
</table>
ATTEMPT 4
I modified the partial view as follows, and achieved exactly what I was looking for. Now, values of the keys are displayed in new lines. However, they are being displayed like so:
`[a]
[b]
[c]`
I dont want the array symbol to be shown. Here is the modified partial view.
<table class="table table-hover" ng-controller="emailViewController">
<tbody>
<tr ng-repeat = "(key, value) in addition" >
<td><input type="checkbox" ng-checked="checkAllEmail" ng-model="selectedEmail"/>
<a href="#">
<span class="glyphicon glyphicon-star-empty"></span>
</a></td>
<td> {{ value }} </td>
<td><label ng-bind="subject"></label></td>
<td><label ng-bind="emailContent" ></label></td>
</tr>
</tbody>
</table>
SOLUTION
<table class="table table-hover" ng-controller="emailViewController">
<tbody>
<tr ng-repeat = "(key, value) in localStorage.add" >
<td><input type="checkbox" ng-checked="checkAllEmail" ng-model="selectedEmail"/>
<a href="#">
<span class="glyphicon glyphicon-star-empty"></span>
</a></td>
<td ng-repeat = "value in value"> {{value }} </td>
<td><label ng-bind="subject"></label></td>
<td><label ng-bind="emailContent" ></label></td>
</tr>
</tbody>
</table>
LocalStorage can only store string values, i believe you saved the JSON object into local storage by serializing it using JSON.stringify()
so, in order to get the JSON object from localstorage, you can use JSON.parse() function like below,
var add = JSON.parse(localStorage.getItem('ngstorage-add'))
var subject = JSON.parse(localStorage.getItem('ngstorage-subject'))
then you can iterate over it.
Read more about LocalStorage
In order your angular directive should work, you have to make it available to the scope, so you have to do in your controller, something like this:
.controller('Ctrl', function(
$scope,
$localStorage
){
$scope.localStorage = $localStorage;
});

get which are checked in list of checkboxes AngularJS

I would like to get which checkbox are selected by the user, i have this table but it dosen't work. is there any alternative ?
<table class="table table-bordered table-hover" style="max-height: 500px; overflow-y: auto" border="1">
<tr>
<th> Nom Exigence</th>
<th> Verifier</th>
</tr>
<tr data-ng-repeat="item in list" style="background-color: #F5F5F5">
<td>
{{item.Nom}}
</td>
<td>
<input type="checkbox" checklist-model="user.list" />
</td>
</tr>
</table>
verify
Close
when i try to log the $scoepe.user.list it shows me []
this is the modal controller
app.controller('ModalInstanceExigencesCtrl', function ($scope, $modalInstance, list) {
$scope.list = [];
$scope.user = [];
for (var i = 0; i < list.length; i++) {
$scope.list.push(list[i]);
}
console.log($scope.list);
$scope.ok = function () {
$modalInstance.close();
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$scope.verify = function () {
console.log($scope.user);
};
});
this Fiddle should do the job for u: jsfiddle example using checkboxes
Html-Code (pretty similiar to ur code):
<div ng-controller="MainCtrl">
<ul>
<li ng-repeat="item in items">
<label class="checkbox">
<input type="checkbox" ng-model="items[$index].checked" />
{{item.name}}
</label>
</li>
</ul>
<hr class="space clearfix" />
{{items | json}}
JS-Code:
var app = angular.module('angularjs-starter', []);
function MainCtrl( $scope )
{
$scope.items = [
{ name:'foo', checked: true },
{ name:'bar' },
{ name:'baz' }
];
}
I just define one $scope Object called items. In my example each item has a name and optional a value checked, which determines wether a checkbox is checked or not.
Html is pretty forward, we repeat over all items and then bind our checkbox model ng-model="items[$index].checked". $index gives us the number of iteration, for example our first iteration binds to ng-model="items[0].checked"
Hope that helps.
You can try by using this way also
Html-Code:
$scope.collectNumbers = function (contact, index) {
if (contact.IsChecked) {
}
else{
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<tr class="" ng-repeat="contact in Contacts">
<td>
<label>
<input type="checkbox" ng-model="contact.IsChecked" ng-change="collectNumbers(contact,$index)" ng-checked="contact.IsChecked">
</label>
</td>
<td>{{contact.Name}}</a></td>
</tr>

Categories