I am trying to use inifinite-scroll directive for angularJS. The examples show usage of div inside the div, but in my case I'm trying to use it in a table. Here is my html:
<div class="scrolling-table-body">
<table class="table table-bordered table-hover table-list">
<thead search-table-header data-table="duplicatesTable"
data-search="sort(column)"
data-show-row-selector="true"
data-hide-sorting-indicator="true"
data-row-selector-click="selectAllRows(allSelected)"
data-column="column">
</thead>
<tbody infinite-scroll="loadMore()">
<tr ng-repeat="row in duplicatesArray"
ng-click="selectedDuplicateIndex=$index;"
ng-class="{selected: $index === selectedDuplicateIndex}">
<td style="text-align:center;">
<input type="checkbox"
name="checkRow"
ng-model="row.isSelected"
ng-change="selectRow(row, $index);" />
</td>
<td>
<span ng-if="row.barcode>0">{{row.barcode}}</span>
<span>{{$index}}</span>
<span class="pull-right">
<i class="fa fa-trash"
style="color:red;"
ng-click="removeRow($index)"
title="#Labels.delete"></i>
</span>
</td>
<td>
<div class="col-xs-12">
<input type="text"
name="assetNo"
id="assetNo"
ng-model="row.assetNo"
class="form-control"
ng-change="checkAssetNo(row)"
ng-maxlength="100"
sm-duplicate-validator
validate-duplicates="true"
error-message="row.errorMessage"
api-method="api/rentalEquipments/checkForDuplicate"
primary-key-value="row.equipmentId"
ng-model-options="{ debounce: { default : 500, blur: 0 }}" />
</div>
</td>
<td>
<input type="text"
name="serialNo1"
id="serialNo1"
ng-model="row.serialNo1"
class="form-control"
ng-maxlength="100" />
</td>
The above is used inside the modal form (bootstrap modal).
I initially load 10 rows into my duplicatesArray and I have the following code for loadMore function:
$scope.loadMore = function () {
const last = $scope.duplicatesArray.length;
if (last < $scope.numberOfDuplicates) {
for (let i = 1; i <= 10; i++) {
self.logInfo("Loading more duplicates...");
const newEquipment = {
equipmentId: (last + i) * -1,
descrip: self.model.descrip,
homeShopId: self.model.homeShopId,
ruleId: self.model.ruleId,
manufacturerId: self.model.manufacturerId,
modelId: self.model.modelId,
typeId: self.model.typeId,
levelId: self.model.levelId,
equipSize: self.model.equipSize,
bootMm: self.model.bootMm,
bindingManufacturerId: self.model.bindingManufacturerId,
bindingModelId: self.model.bindingModelId,
cost: self.model.cost,
bindingCost: self.model.bindingCost,
unitCost: self.model.unitCost,
errorMessage: "",
duplicateForm: true,
duplicatedId: self.model.equipmentId,
isDuplicate: true,
barcode: 0,
assetNo: "",
serialNo1: "", serialNo2: "", serialNo3: "", serialNo4: "",
isSelected: false
};
$scope.duplicatesArray.push(newEquipment);
}
}
};
There is currently an issue in this js code (I moved check for last < numberOfDuplicates before the loop thinking it may be the issue).
When I open my modal I see 20 items in the list and when I scroll I don't see more items.
Do you see what am I doing wrong?
Also, does it matter that I have the following markup for the modal:
<ng-form name="equipmentDuplicatesForm">
<div class="modal-body">
<div id="fixed-header-table">
<div class="fixed-header-bg">
</div>
<div class="scrolling-table-body">
table goes here
</div>
<div class="modal-footer hundred-percent padTop padBottom">
<button type="button" class="btn btn-warning"
data-dismiss="modal" aria-hidden="true"
ng-click="$dismiss()">
#Labels.cancel
</button>
</div>
</ng-form>
Related
What am I doing wrong here. Need help.
When I click on "Add" button, the data I selected in the rows of table are becoming blank. But When I select Delete button and then click on Add button, then it not emptying of one time only. If I see console, I can see data there, but it is not showing up on the screen.
Here is my code:
html:
<div class="container">
<div class="row" style="margin-bottom: 10px;">
<div class="col">
<div class="row111">
<label for="Select Image" class="col-sm-311 col-form-label111">Add Threshold and Notification for this Inspection: </label>
<div class="col-sm-9">
</div>
</div>
</div>
<div class="col">
<div class="float-right">
<button class="btn btn-default" type="button" (click)="addNotification()">Add</button>
</div>
</div>
</div>
<table class="table table-striped table-bordered">
<thead>
<tr>
<th>#</th>
<th>Threshold</th>
<th>Notification Level</th>
<th>Message</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<!-- <tr> -->
<tr *ngFor="let notification of notificationArray; let i = index">
<td>{{i+1}}</td>
<td>
<select class="form-control" maxlength="50" readonly
required
id="threshold"
name="notification.thresholdId"
[(ngModel)]="notification.thresholdId"
#threshold="ngModel" >
<option value="0" selected> Select </option>
<option *ngFor="let threshold of thresholdList" value="{{threshold.thresholdId}}" >
{{threshold.threshold}}
</option>
</select>
</td>
<td>
<input [(ngModel)]="notification.notificationLevel" required class="form-control" type="text" name="notification.notificationLevel" />
</td>
<td>
<input [(ngModel)]="notification.message" required class="form-control" type="text" name="notification.message" />
</td>
<td>
<button class="btn btn-default" type="button" (click)="deleteNotification(i)">Delete</button>
</td>
</tr>
</tbody>
</table>
</div>
component.ts:
notificationArray: Array<NotificationLevel> = [];
newNotification: any = {};
ngOnInit(): void {
this.newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
this.notificationArray.push(this.newNotification);
}
addNotification(index) {
this.newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
this.notificationArray.push(this.newNotification);
console.log(this.notificationArray); // I can see all entered data in console
return true;
}
deleteNotification(index) {
if(this.notificationArray.length ==1) {
alert("At least one Notification Required for an Inspection");
return false;
} else {
this.notificationArray.splice(index, 1);
return true;
}
}
Ok, solve the problem:-
The main problem is in name="" attribute. name="" must differ in each row .We can solve it in two ways:
1) Either Change the name="" attributes name dynamically so that for every row it has a different name, i did it to add index number with it as
<input [(ngModel)]="notification.notificationLevel" name="notificationThreshold{{i}}" required class="form-control" type="text" />
2) Or avoid name="" and so We can avoid [(ngModel)] By [value] and (input) and can use as like :-
<input [value]="notification.notificationLevel" (input)="notification.notificationLevel=$event.target.value" required class="form-control" type="text"/>
In fact, all of your notificationArray elements is the same instance of newNotification. By doing this : this.newNotification = {thresholdId: "0", notificationLevel: "", message: ""}; you actually reset the first line too because of it.
Try to store newNotification in a var instead :
notificationArray: Array<NotificationLevel> = [];
newNotification: any = {};
ngOnInit(): void {
var newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
this.notificationArray.push(newNotification);
}
addNotification(index) {
console.log(this.notificationArray);
// here is the correction
var newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
this.notificationArray.push(newNotification);
console.log(this.notificationArray);
return true;
}
deleteNotification(index) {
if(this.notificationArray.length ==1) {
alert("At least one Notification Required for an Inspection");
return false;
} else {
this.notificationArray.splice(index, 1);
return true;
}
}
update :
I don't know if it's related but you'll have duplicate threshold id on your select. Use your i to make it unique.
It's the same for your input names. You should add [] after the field name otherwise only the last row will be submit.
I added a console.log of you array after the push. Can you tell in comment if the first index is reset at this point ?
Of course the row is cleared because you are clearing it:
this.newNotification = {thresholdId: "0", notificationLevel: "", message: ""};
So on clicking the add button, the bound values are overridden and then you are pushing it into the array. Thus they are cleared :)
Hi guys I'm using angular2 in my project and I'm trying to add an input text dymanically, and it works heres the code :
TS:
initArray() {
return this._fb.group({
title: ['', Validators.required]
})
}
addArray() {
const control = <FormArray>this.myForm.controls['myArray'];
//this.myGroupName.push(newName);
control.push(this.initArray());
}
HTML:
<div formArrayName="myArray">
<div *ngFor="let myGroup of myForm.controls.myArray.controls; let i=index">
<div [formGroupName]="i">
<span *ngIf="myForm.controls.myArray.controls.length > 1" (click)="removeDataKey(i)" class="glyphicon glyphicon-remove pull-right" style="z-index:33;cursor: pointer">
</span>
<!--[formGroupName]="myGroupName[i]"-->
<div [formGroupName]="myGroupName[i]">
<div class="inner-addon left-addon ">
<i class="glyphicon marker" style="border: 5px solid #FED141"></i>
<input type="text" style="width:50% !important" formControlName="title" class="form-control" placeholder="Exemple : Maarif, Grand Casablanca" name="Location" Googleplace (setAddress)="getAddressOnChange($event,LocationCtrl)">
<br/>
</div>
</div>
<!--[formGroupName]="myGroupName[i]"-->
</div>
<!--[formGroupName]="i" -->
</div>
</div>
<br/>
<a (click)="addArray()" style="cursor: pointer">+ add text Field</a>
it gives me an error when i add a new text field, any suggestions please??
ERROR Error: Cannot find control with path: 'myArray -> 1 ->
Do not manupulate DOM with AngularJS
In controller create array of inputs
$scope.inputs = [];
$scope.inputs.push({ id: 'input1', value: 'input1' });
$scope.inputs.push({ id: 'input2', value: 'input2' });
$scope.inputs.push({ id: 'input2', value: 'input2' });
<input ng-repeat="input in inputs" ng-model="input.value">
Example
When I press accept button task should be updated with new value which I wrote in input.Sad thing it doesnt work like I want.Do i need to add id`s to array with objects?
or maybe there is some good method to send a object to function.Here`s the code:
<tbody>
<tr ng-repeat="task in tasks">
<td>
<button class="btn btn-danger" ng-click="deleteTask(task)">Delete</button>
<!-- $index-->
</td>
<td>{{task.taskName}}</td>
<td>
<input type="checkbox" ng-model="statusCheck"> </td>
<td style="{{setStyleToTd(statusCheck)}}">{{statusChecker(statusCheck)}}</td>
<td>
<button class="btn btn-primary" ng-click="editTask(task)">Edit</button>
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-md-offset-8 edit-box" ng-show="editBoxShow">
<form action="" class="form-inline">
<div class="form-group">
<lable>Edit task here:</lable>
<div class="input-group">
<input type="text" class="form-control" ng-model="editTaskInput"> </div>
<button type="button" class="btn btn-success" ng-click="acceptEdit()">Accept</button>
</div>
</form>
</div>
$scope.editTask = function(taskToEdit) {
$scope.editBoxShow = true;
$scope.editTaskInput = taskToEdit.taskName;
}
$scope.acceptEdit = function() {
$scope.editBoxShow = false;
$scope.taskToEdit = $scope.editTaskInput;
}
You can capture the index of your table data while clicking edit button and then update the table data by using this index in acceptEdit function.
$scope.editTask = function (taskToEdit) {
$scope.selectedIndex=$scope.tasks.indexOf(taskToEdit);
$scope.editBoxShow = true;
$scope.editTaskInput = taskToEdit.taskName;
}
$scope.acceptEdit = function () {
$scope.editBoxShow = false;
$scope.tasks[$scope.selectedIndex].taskName=$scope.editTaskInput;
}
Ok, so i built a little app to exercise what i've learned so far with vue, but theres some things that i want to do but have no idea HOW yet
<div class="container" id="app">
<div class="row">
<div class="col-xs-6 jumbotron">
<form class="form-horizontal" #submit.prevent>
<p>
<label>Name</label>
<input id="inputName" type="text" class="form-control" v-model="dataToArray.name">
</p>
<p>
<label>Sex</label>
<input type="radio" name="sex" value="male" v-model="dataToArray.sex"> Male
<input type="radio" name="sex" value="female" v-model="dataToArray.sex"> Female
</p>
<p>
<label>Select a Color</label>
<select id="selectColor" class="form-control" v-model="dataToArray.color">
<option value="red">Red</option>
<option value="blue">Blue</option>
</select>
</p>
<p>
<button class="btn btn-primary" #click="addToArray()">Add to Array</button>
</p>
</form>
</div>
<div class="col-xs-6">
<table id="table" class="table table-bordered" v-if="savedData.length > 0">
<thead>
<th>Name</th>
<th>Sex</th>
<th>Color</th>
<th></th>
</thead>
<tbody id="test">
<tr v-for="(data, index) in savedData" v-if="savedData[index].status">
<td>{{ data.name }}</td>
<td>{{ data.sex }}</td>
<td>{{ data.color }}</td>
<td class="text-center">
<button #click="editThis(index)" class="btn btn-warning">Edit</button>
<button #click="saveEdit(index)" class="btn btn-default">Save</button>
<button class="btn btn-danger" #click="deleteThis(index)">Delete</button>
</td>
</tr>
</tbody>
</table>
{{ dataToArray.id }} <br>
{{ dataToArray.name }} <br>
{{ dataToArray.sex }} <br>
{{ dataToArray.color }} <br>
{{ savedData }}
</div>
</div>
</div>
new Vue({
el: '#app',
data:{
dataToArray: {
id: null,
name: '',
sex: '',
color: '',
status: true
},
savedData: []
},
methods: {
addToArray(){
this.dataToArray.id = this.savedData.lenth;
this.savedData.push(Object.assign({}, this.dataToArray));
},
deleteThis(index){
this.savedData[index].status = false;
},
editThis(index, event){
document.getElementById("inputName").value = this.savedData[index].name;
document.getElementById("selectColor").value = this.savedData[index].color;
//check the form radio according to the current sex of the object
},
saveEdit(index){
this.savedData[index].name = document.getElementById("inputName").value;
this.savedData[index].color = document.getElementById("selectColor").value;
//this.savedData[index].sex = get the new radio value
}
}
});
This is the app:https://jsfiddle.net/myrgato/10uqa1e1/5/
The edit and save button, i wanted to hide the edit button and show the saved button when the edit button is clicked, and the otherway around when the save button is clicked.
Editing the sex value of the object, i cant get the new radio value (the checked one after i click edit and select a new one)
Hiding the table if there are no rows, i am able to do that at the first time by comparing it to the size of the looping array, but when i delete rows, i dont delete the objects from the array, i just change the status, so if add one object to the array and delete it, the row will be gone (shows only if status = true) but the table will not (because even tho there are no rows, the object still exists inside the array)
Can someone help me understand how to achieve this?
Edit: Updated the code with what we got so far:
https://jsfiddle.net/myrgato/rcj3kef7/
As you can see, if i add two items to the table, and edit ONE, all the rows show the save button, how can i only show the save button of the row that i clicked?
and another one, check the following code: https://jsfiddle.net/myrgato/rcj3kef7/1/
In this one, i put the save button outside the table, in the form itself, so when the user clicks edit on a row, the save button and the current values show on the form.
The problem is, how will i get the index thats inside the v-for to my saveThis function that is outside?
You want to have an editing mode. When you're in editing mode, the Save button appears and the Edit button disappears; otherwise, the reverse. That's just a variable that you set to the index of the row being edited, or null when not editing.
For copying values between dataToArray and savedData, Object.assign is handy.
Since you want to hide the table when it's empty and it's empty when there are no items with a true status member, create a computed that uses find to tell you if there are any such items.
new Vue({
el: '#app',
data: {
dataToArray: {
id: null,
name: '',
sex: '',
color: '',
status: true
},
savedData: [],
editing: false
},
computed: {
hasVisibleData() {
return this.savedData.find(d => d.status);
}
},
methods: {
addToArray() {
this.dataToArray.id = this.savedData.lenth;
this.savedData.push(Object.assign({}, this.dataToArray));
},
deleteThis(index) {
this.savedData[index].status = false;
},
editThis(index, event) {
this.editing = index;
Object.assign(this.dataToArray, this.savedData[index]);
},
saveEdit(index) {
this.editing = null;
Object.assign(this.savedData[index], this.dataToArray);
}
}
});
.jumbotron {
background-color: ;
}
label {
color: ;
}
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet"/>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div class="container" id="app">
<div class="row">
<div class="col-xs-6 jumbotron">
<form class="form-horizontal" #submit.prevent>
<p>
<label>Name</label>
<input id="inputName" type="text" class="form-control" v-model="dataToArray.name">
</p>
<p>
<label>Sex</label>
<input type="radio" name="sex" value="male" v-model="dataToArray.sex"> Male
<input type="radio" name="sex" value="female" v-model="dataToArray.sex"> Female
</p>
<p>
<label>Select a Color</label>
<select id="selectColor" class="form-control" v-model="dataToArray.color">
<option value="red">Red</option>
<option value="blue">Blue</option>
</select>
</p>
<p>
<button class="btn btn-primary" #click="addToArray()">Add to Array</button>
</p>
</form>
</div>
<div class="col-xs-6">
<table id="table" class="table table-bordered" v-if="hasVisibleData">
<thead>
<th>Name</th>
<th>Sex</th>
<th>Color</th>
<th></th>
</thead>
<tbody id="test">
<tr v-for="(data, index) in savedData" v-if="savedData[index].status">
<td>{{ data.name }}</td>
<td>{{ data.sex }}</td>
<td>{{ data.color }}</td>
<td class="text-center">
<button v-if="editing!==index" #click="editThis(index)" class="btn btn-warning">Edit</button>
<button v-if="editing===index" #click="saveEdit(index)" class="btn btn-default">Save</button>
<button class="btn btn-danger" #click="deleteThis(index)">Delete</button>
</td>
</tr>
</tbody>
</table>
{{ dataToArray.id }} <br> {{ dataToArray.name }} <br> {{ dataToArray.sex }} <br> {{ dataToArray.color }} <br> {{ savedData }}
</div>
</div>
</div>
You would want to set a flag when one or the other is clicked that way you can change both accordingly.
new Vue ({
data: {
edit:[] //0 means that neither button is clicked.
},
methods:{
editThis(index, event){
this.edit[index] = 1;
this.dataToArray.name = this.savedData[index].name;
this.dataToArray.color = this.savedData[index].color;
this.dataToArray.color = this.saveData[index].sex;
},
saveEdit(index){
this.edit[index] = -1
this.savedData[index].name = this.dataToArray.name
this.savedData[index].color = this.dataToArray.color
this.savedData[index].sex = this.dataToArray.sex
//since we have bound the dataToArray values with v-model we can modify them from here.
},
addToArray(index){
this.dataToArray.id = this.savedData.lenth;
this.edit[index] = 0;
this.savedData.push(Object.assign({}, this.dataToArray));
},
})
Then in your template you want to have a "v-if" property to show and hide based on the value of the flag.
<button #click="editThis(index)" v-if="edit[index] && edit[index] > -1" class="btn btn-warning">Edit</button>
<button #click="saveEdit(index)" v-if='edit[index] && edit[index] < 1' class="btn btn-default">Save</button>
Also, in order to hide the table when there is no data you also have to use a v-if on the table itself. You can also do a computed that returns the number of elements in the array that return a status that is not equal to false like so.
new Vue({
computed:{
elements(){//using the ES6 arrow function syntax and Array.reduce
return this.savedData.reduce((accum, iter) => {
if(iter.status != false) accum += 1
}, 0);
}
}
})
Then in your template you can place your table element like so:
<table id="table" class="table table-bordered" v-if="elements">
I am following an AngularJS tutorial, and I wanted to validate my form. I decided to add a default option to the select element.
However, even after adding selected="", the browser won't show it as default.
I have tried this without AngularJS and it works fine, so I'm guessing the script is blocking something.
How can I define a default option for my select element?
PS: I'm using Google Chrome Version 44.0.2403.157 m
var controllers = angular.module('formsApp.Controllers', []);
controllers.controller('todoCtrl', function($scope) {
$scope.todoList = [{
action: 'Get groceries',
complete: false
}, {
action: 'Call plumber',
complete: false
}, {
action: 'Buy running shoes',
complete: true
}, {
action: 'Buy flowers',
complete: false
}, {
action: 'Call family',
complete: false
}];
$scope.addNewItem = function(newItem) {
$scope.todoList.push({
action: newItem.action + ' (' + newItem.location + ')',
complete: false
});
};
});
var app = angular.module('formsApp', ['formsApp.Controllers']);
form input.ng-invalid.ng-dirty {
background-color: lightpink;
}
<!DOCTYPE html>
<html data-ng-app="formsApp">
<head>
<title>Forms</title>
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
</head>
<body>
<div id="todoPanel" class="panel" data-ng-controller="todoCtrl">
<h3 class="panel-header">
To Do List
<span class="label label-info">
{{(todoList | filter: {complete: false}).length }}
</span>
</h3>
<div class="row">
<div class="col-xs-4">
<div class="well">
<form name="todoForm" novalidate data-ng-submit="addNewItem(newTodo)">
<div class="form-group row">
<label for="actionText">Action:</label>
<input type="text" id="actionText" class="form-control" data-ng-model="newTodo.action" required="" />
</div>
<div class="form-group row">
<label for="actionLocation">Location:</label>
<select id="actionLocation" class="form-control" data-ng-model="newTodo.location" required="">
<option selected="">Home</option>
<option>Office</option>
<option>Mall</option>
</select>
</div>
<button type="submit" class="btn btn-primary btn-block" data-ng-disabled="todoForm.$invalid">
Add
</button>
</form>
</div>
</div>
<div class="col-xs-8">
<table class="table">
<thead>
<tr>
<th>#</th>
<th>Action</th>
<th>Done</th>
</tr>
</thead>
<tbody>
<tr data-ng-repeat="item in todoList">
<td>
{{$index + 1}}
</td>
<td>
{{item.action}}
</td>
<td>
<input type="checkbox" data-ng-model="item.complete" />
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>
From the dev guide for ngSelected;
The HTML specification does not require browsers to preserve the
values of boolean attributes such as selected. (Their presence means
true and their absence means false.) If we put an Angular
interpolation expression into such an attribute then the binding
information would be lost when the browser removes the attribute. The
ngSelected directive solves this problem for the selected attribute.
This complementary directive is not removed by the browser and so
provides a permanent reliable place to store the binding information.
In your controller add another property and reference it from there:
{
action: 'Call family',
complete: false,
selected: 'selected'
}];
{
action: 'Call family',
complete: false,
selected: ''
}];