Angular JS Multiple ngRepeat - javascript

I'm trying to do the following : When you click on "Add Package" its pushes to an array a package where I can specify e.g. Package one, but within that I want to push multiple items (products) "Add Item". The problem is when I create a new package it works, but the items in each package is the same so when I add more to either dynamic package the items within is the same. I assume that's because the array is the same each time, how to I track that by index?
HTML:
<div class="col-12 order-box" ng-repeat="orderpackage in orderproductspackages track by $index">
<div class="col-12">
<label for="name_{{$index}}">Package Name</label>
<input type="text" ng-model="orderpackage.orderpackagename" name="name_{{$index}}" required>
</div>
<div class="col-12" ng-repeat="ordercontent in orderproductscontents track by $index">
<div class="col-2">
<label for="name_{{$index}}">Product</label>
<select ng-model="ordercontent.ordercontentname" name="name_{{$index}}" ng-change="onProductChange(ordercontent.ordercontentname,$index)">
<option ng-repeat="product in productResponse | orderBy:'productname'" value="{{product.productname}}">{{product.productname}}</option>
</select>
</div>
<div class="col-2">
<label for="name_{{$index}}">Quantity</label>
<input type="text" ng-model="ordercontent.ordercontentquantity" name="name_{{$index}}" ng-keyup="onProductChange(ordercontent.ordercontentname,$index)" required>
</div>
<div class="col-2">
<label for="name_{{$index}}">Price</label>
<input type="text" ng-model="ordercontent.ordercontentprice" name="name_{{$index}}" ng-change="onPriceChange(ordercontent.ordercontentname,$index)" disabled required>
</div>
<div class="col-2">
<label for="name_{{$index}}">Per {{ordercontent.ordercontentmeasurement}}</label>
<input type="text" ng-model="ordercontent.ordercontentpriceper" name="name_{{$index}}" disabled required>
</div>
<div class="col-2">
<label for="name_{{$index}}">Total</label>
<input type="text" ng-model="ordercontent.ordercontenttotal" name="name_{{$index}}" required disabled>
</div>
<div class="col-2">
<label for="name_{{$index}}">Options</label>
<a class="button critical small" ng-click="removeOrderContent($index)"><span class="fa fa-minus"></span> Remove</a>
</div>
</div>
<div class="col-12 m20-top p15 text-center add-api" ng-click="addOrderContent()">
<span class="fa fa-plus"></span> Add Item</a>
</div>
</div>
<div class="col-12 m20-top p15 text-center add-api" ng-click="addOrderPackage()">
<span class="fa fa-plus"></span> Add Package</a>
</div>
CODE SNIPPETS :
_this.addOrderPackage = function() {
_this.orderproductspackages.push({ ordernumber:_this.order.ordernumber });
}
_this.addOrderContent = function() {
_this.orderproductscontents.push({
ordercontentname:'',
ordercontentquantity:'1',
ordercontentprice:'',
ordercontentpriceper:'',
ordercontenttotal:''
});
}

Of course, all items in your packages are the same, because you use the same content array inside packages: ng-repeat="ordercontent in orderproductscontents". If I understand you right, you need this array orderproductscontents to be distinctive in each package. To do this store this array in package object, like this:
_this.addOrderPackage = function() {
_this.orderproductspackages.push({
ordernumber: _this.order.ordernumber,
contents: []
});
}
and then just ng-repeat="ordercontent in orderpackage. contents"

Related

Add same form element below by clicking add button. using Angular Js

I have a form1 and a add button. The thing I want is to add same form as form2 below form1 on clinking add button. As I am new to Angular Js it will be very helpful if someone can help me out.
HTML
<div class="row">
<header class="panel-heading">
<h5 class="panel-title" style="padding-left: 1.5rem;">
<b>APPLICANTS</b>
<input class="btn btn-primary" style="float:right " type="button" value="Add" />
</h5>
<hr>
</header>
<div class="panel-body">
<div class="container">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label class="control-label">Name</label>
<div>
<input type="text" class="form-control" id="inputDefault" ng-model="txtFullName">
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label class="control-label">Nationality</label>
<div>
<input type="text" class="form-control" id="inputDefault" ng-model="txtNationality">
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4">
<div class="form-group">
<label class="control-label">Pin Code</label>
<div>
<input type="text" class="form-control" id="inputDefault" ng-model="txtPincode">
</div>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<label class="control-label">House No.</label>
<div>
<input type="text" class="form-control" id="inputDefault" ng-model="txtHouseNo">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
You need to create an array of applicants model objects, let's call it applicantsArray, where every object will represent a single applicant form.
You need to initialize this array with one model empty on page load.
Then you need to wrap your form with ng-for and iterate over every applicant model. So the n-th form will be binded with the n-th model in the applicantsArray.
Last step will be to push an empty applicant model to applicantsArray when 'Add' is clicked. Then a new model is added and the DOM will render additional form for the new model.

this.validator is not a function with formarray. Angular2

I'm working on a page which has a nested Formarray.
constructor(private fb: FormBuilder) {
this.buildForm();
}
private buildForm() {
this.trialBudgetForm = this.fb.group({
clients: this.fb.array([])
})
}
addCustomer() {
this.clients.push(this.initCustomer());
}
initCustomer() {
return this.fb.group({
earnedIncomes: this.fb.array([this.initIncome()]),
thirtyAndOneThirdYN: [],
thirtyYN: [],
earnedIncomeExpenseType: [],
earnedIncomeExpense: [],
dependentCareExpense: []
})
}
initIncome() {
return this.fb.group(new ScrAmountType());
}
ngOnInit() {
this.populateData();
}
populateData() {
const clients = this.TrialBudgetData.clients;
const customerFGs = clients.map(customer => this.fb.group({
earnedIncomes: this.populateIncome(customer.earnedIncomes),
thirtyAndOneThirdYN: [this.utilService.YNConvert(customer.thirtyAndOneThirdYN)],
thirtyYN: [this.utilService.YNConvert(customer.thirtyYN)],
earnedIncomeExpenseType: [customer.earnedIncomeExpenseType],
earnedIncomeExpense: [customer.earnedIncomeExpense],
dependentCareExpense: [customer.dependentCareExpense]
}));
const customerFormArray = this.fb.array(customerFGs);
this.trialBudgetForm.setControl('clients', customerFormArray);
}
for demo purpose, i didn't post the entire ts file, coz there are almost 600 lines. But i can provide more detail if needed.
here's the html page (also only a snippet)
<form novalidate [formGroup]="trialBudgetForm" (ngSubmit)="save(trialBudgetForm)">
<div class="settingsPage-box">
<h3 class="box-border-bottom">Earned Income
<span class="float_right add-field add-margin hand" (click)="addCustomer()">
<i class=" fa fa-plus-circle fa-lg plusIconColor"></i>
<span>
Add Earned Income
</span>
</span>
</h3>
<div formArrayName="clients">
<div *ngFor="let earnedIncomeCustomer of clients.controls; let i = index" [formGroupName]="i" class="row-view box-border-bottom">
<div class="box-border-bottom row-view">
<div class="col-sm-3 padding0">
<label for="customer{{i+1}}" class="pushDown">Customer {{i+1}}:</label>
</div>
<div class="col-sm-9 grid-block padding0">
<div class="col-sm-1 float_right" (click)="deleteCustomer(i)">
<span class="delete-row hand">
<i class="fa fa-trash-o"></i>
</span>
</div>
</div>
<div class="col-sm-3">
<label class="pushDown">Earned Income</label>
</div>
<div class="col-sm-9 grid-block">
<div class="row">
<div class="col-sm-6 u-justifyEnd">
<span class="add-margin float-left hand" (click)="addEarnedIncome(i)"><i class=" fa fa-plus-circle fa-lg plusIconColor"></i><span> Add Income</span></span>
</div>
</div>
<div class="row grid-block pd-left amount-grid" formArrayName="earnedIncomes" >
<div class="row-view" *ngFor="let earnedIncome of earnedIncomeCustomer.controls.earnedIncomes.controls; let j = index"
[formGroupName]="j">
<div class="col-sm-5 padding5">
<span class="label-type" *ngIf="j==0">Type</span>
<select class="form-control" formControlName="type" (change)="checkForDuplicateEarnedIncomeType(this.trialBudgetForm.controls.clients.controls[i].controls.earnedIncomes.controls[j].value.type)">
<option value="">Select</option>
<option *ngFor="let optionEntity of this.constantsService.getDropDownFromLookup(this.constantsService.getText('EarningType'))"
value="{{optionEntity.lookupBean.code}}">{{optionEntity.lookupBean.longLabel}}</option>
</select>
</div>
<div class="col-sm-6 pd-left padding5 amount-bg">
<span class="label-type" *ngIf="j==0">Amount</span>
<div class="search-container">
<input (keypress)="this.customValidatorsService.validateNumberOnly($event)" formControlName="amount" class="form-control amount-input search-box"
placeholder="$0.00" currencyMask [options]="{ allowNegative: false,prefix: '$',hundreds: ',' }" maxlength="12"
(keyup)="calculateTotalIncome(earnedIncomeCustomer, i)" />
</div>
<div class="clearfix"></div>
</div>
<div class="col-sm-1 pd-left">
<span class="label-type" *ngIf="j==0"> </span>
<span class="delete-row hand" (click)="deleteIncome(earnedIncomeCustomer, i, j)"> <!-- G.S Income.controls.amount -->
<i class="fa fa-trash-o"></i>
</span>
</div>
</div>
<div class="row-view">
<div class="col-sm-5">
<span class="total-info text-right">Total Earned Income</span>
</div>
<div class="col-sm-6 pd-left amount-bg">
<span class="total-info text-right">${{ earnedIncomeCustomer.totalEarnedIncome | number : '1.2-2'}}
</span>
<div class="clearfix"></div>
</div>
</div>
<div class="row-view">
<div class="col-sm-12 text-center">
<div class="clearfix"></div>
</div>
</div>
</div>
<span *ngIf="duplicateEarnedIncomeType" class="red-font-color">Choose a different use type</span>
</div>
<div class="clearfix"></div>
</div>
<div class="box-border-bottom row-view">
<div class="col-sm-3">
<label class="pushDown">Earned Income Options</label>
</div>
<div class="col-sm-8 grid-block">
<div class="col-sm-5 form-group label-check display-check">
<input type="checkbox" id="check-1" formControlName="thirtyAndOneThirdYN">
<label for="check-1">30+1/3</label>
</div>
<div class="col-sm-6 form-group label-check display-check">
<input type="checkbox" id="check-2" formControlName="thirtyYN">
<label for="check-2">$30</label>
</div>
</div>
<div class="clearfix"></div>
</div>
<div class="box-border-bottom row-view">
<div class="col-sm-3">
<label class="pushDown">Earned Income Expenses</label>
</div>
<div class="col-sm-8 grid-block">
<div class="col-sm-5 form-group padding_right">
<div class="control-label">Type</div>
<select class="form-control" formControlName="earnedIncomeExpenseType">
<option value="-1">Select</option>
<option *ngFor="let optionEntity of this.constantsService.getDropDownFromLookup(this.constantsService.getText('EIexpenseType'))"
value="{{optionEntity.lookupBean.code}}">{{optionEntity.lookupBean.longLabel}}</option>
</select>
</div>
<div class="col-sm-6 padding0 padding_custom">
<div class="control-label">Amount</div>
<input formControlName="earnedIncomeExpense" currencyMask (keypress)="numberOnly($event)" class="form-control" [options]="{ allowNegative: false, prefix: '$',hundreds: ',' }"
placeholder="$0.00" maxlength="10" />
</div>
</div>
<div class="clearfix"></div>
</div>
<div class="row-view">
<div class="col-sm-3">
<label class="pushDown">Dependent Care Expenses</label>
</div>
<div class="col-sm-8 grid-block">
<div class="col-sm-5">
<div class="control-label">Expenses</div>
<input (keypress)="numberOnly($event)" currencyMask formControlName="dependentCareExpense" class="form-control" maxlength="10"
placeholder="$0.00" [options]="{ allowNegative: false, prefix: '$',hundreds: ',' }" />
</div>
</div>
<div class="clearfix"></div>
</div>
</div>
</div>
</div>
</form>
I have been trying to debug this for couple days now. The issue happens after constructor executed and before ngOnInit was called. this error only occur when I added more than one customer, and come back to this page. (adding customer won't cause any problem, only when I comeback to this page that's when the error this.validator is not a function is shown.
It's strange because the error happen between constructor and ngOnInit, and populateData is called in ngOnInit, which means error occured before the page know how many customers will I load. But if only the error occur because I add more than one customer, it seems that applicaiton has to get that info within constructor, in which i didn't load the data yet.
Update 1: Sept 25 3:39PM EST
updated with populateData function
Update 2: full stack error: Sept 25 4:09PM EST
TrialBudgetComponent_Host.html:1 ERROR TypeError: this.validator is not a function
at FormControl.webpackJsonp.../../../forms/#angular/forms.es5.js.AbstractControl._runValidator (forms.es5.js:2645)
at FormControl.webpackJsonp.../../../forms/#angular/forms.es5.js.AbstractControl.updateValueAndValidity (forms.es5.js:2613)
at new FormControl (forms.es5.js:2936)
at FormBuilder.webpackJsonp.../../../forms/#angular/forms.es5.js.FormBuilder.control (forms.es5.js:5780)
at FormBuilder.webpackJsonp.../../../forms/#angular/forms.es5.js.FormBuilder._createControl (forms.es5.js:5822)
at forms.es5.js:5804
at Array.forEach (<anonymous>)
at FormBuilder.webpackJsonp.../../../forms/#angular/forms.es5.js.FormBuilder._reduceControls (forms.es5.js:5803)
at FormBuilder.webpackJsonp.../../../forms/#angular/forms.es5.js.FormBuilder.group (forms.es5.js:5762)
at TrialBudgetComponent.webpackJsonp.../../../../../src/app/trial-budget/trial-budget.component.ts.TrialBudgetComponent.toFromGroup (trial-budget.component.ts:102)
Update 3 question closed: thanks to #yurzui's comment
I just realized that the architecture is messed up for this page. This component has a parent which only has (current component selector) in its template. The two component has exactly the same name just under different folder. The parent is at /trial-budget and children is at /trial-budget/trial-budget-main. The TrialBudgetComponent.toFromGroup is actually a function inside the parent. For some reason, it's being called inside ngInit instead of constructor. Still haven't figure out why error only happen with 2 customer.
But lesson learned:
1. read error message carefully especially first and last couple lines. I didn't read the last line.
2. always construct form inside constructor and populate data inside ngOnInit()

Disable textbox inside an AngularJS Dynamic form

I need to disable the textbox inside my angularJS dynamic form after I clicked the button. my code seems to be working fine if I am going to disable textbox outside the dynamic form but when I get the ID of the textbox inside the dynamic form it is not working. What could be the problem.
$scope.copyText = function () {
document.getElementById('copyText').disabled=true;
document.getElementById('bName').disabled=true;
document.getElementById('pName').disabled=true;
// $('#bName').attr('disabled', true);
//alert('#bName');
$scope.LanguageFormData.language = [
{ bName: document.getElementById('brandName').value, pName: document.getElementById('prodName').value, pNameSub: document.getElementById('prodNameSub').value, lFeature: document.getElementById('pfeatureNew').value, lIngredient: document.getElementById('pingredientNew').value, lInstruction: document.getElementById('pinstructionNew').value, languageCat: null }
];
My View looks like this
<div class="col-md-12" class="pull-right" >
<button class="btn btn-primary pull-right" type="button" ng-click="copyText()" id="copyText" value="">COPY</button>
</div>
</div>
<div id="web" ng-repeat="languageItem in LanguageFormData.language">
<div class="row col-xs-12">
<div class="col-xs-6">
<br/><br/>
<div class="form-group">
<label class="col-md-6 control-label">Brand Name: </label>
<div class="col-md-6">
<input type="text" class="form-control" ng-required="true" name="bName" id="bName" class="form-control" ng-model="languageItem.bName" required/>
</div>
</div><br/><br/><br/>
<div class="form-group">
<label class="col-md-6 control-label">Product Name: </label>
<div class="col-md-6">
<input type="text" class="form-control" name="pName" ng-required="true" id="pName" ng-model="languageItem.pName" required/>
</div>
</div><br/><br/><br/>
Why not use ng-disabled. You need to change $scope.disableThis=false; back to false to re-enable the text somewhere else inside the controller code.
$scope.copyText = function () {
$scope.disableThis=true;
$scope.LanguageFormData.language = [
{ bName: document.getElementById('brandName').value, pName: document.getElementById('prodName').value, pNameSub: document.getElementById('prodNameSub').value, lFeature: document.getElementById('pfeatureNew').value, lIngredient: document.getElementById('pingredientNew').value, lInstruction: document.getElementById('pinstructionNew').value, languageCat: null }
];
Suggestions:
I have some doubts on the above code, you can just use the $scope.LanguageFormData.language as is, since you are using ng-model in the input fields, the data of the variable is updated dynamically, you can check this by {{LanguageFormData.language}} printing the output in the HTML
HTML:
<div class="col-md-12" class="pull-right" >
<button class="btn btn-primary pull-right" type="button" ng-click="copyText()" id="copyText" ng-disabled="disableThis" value="">COPY</button>
</div>
</div>
<div id="web" ng-repeat="languageItem in LanguageFormData.language">
<div class="row col-xs-12">
<div class="col-xs-6">
<br/><br/>
<div class="form-group">
<label class="col-md-6 control-label">Brand Name: </label>
<div class="col-md-6">
<input type="text" class="form-control" ng-required="true" name="bName" id="bName" ng-disabled="disableThis" class="form-control" ng-model="languageItem.bName" required/>
</div>
</div><br/><br/><br/>
<div class="form-group">
<label class="col-md-6 control-label">Product Name: </label>
<div class="col-md-6">
<input type="text" class="form-control" name="pName" ng-required="true" id="pName" ng-model="languageItem.pName" ng-disabled="disableThis" required/>
</div>
</div><br/><br/><br/>
Suggestions:
It would be good if you restrict the ID for one particular element alone, its a good practice to follow in general!

Adding a new object to an array through ngFor directive with angular

i'm traying to display n filds through ngFor directive(user imput) that correspand to a User instance But my question is what is the best way to put this object values in this array after validation click buttom.
<ul style="list-style-type: none">
<li *ngFor="let number of nbCollaborateur">
<div class="row" >
<div class="col-md-3">
<label class="control-label">Nom et prenom </label>
<input type="text" class="form-control">
<div class="col-md-3">
<div class="form-group form-black label-floating is-empty">
<label class="control-label">telephone</label>
<input type="text" class="form-control">
</div>
</div>
<div class="col-md-3">
<div class="form-group form-black label-floating is-empty">
<label class="control-label">adresse</label>
<input type="text" class="form-control">
</div>
</div>
<div class="col-md-3">
<div class="form-group form-black label-floating is-empty">
<label class="control-label">commantaire</label>
<input type="text" class="form-control">
</div>
</div>
</div>
</div>
</li>
</ul>
My array will look like this:
users: User[];
this.users.push(new User());
I am not seeing any button in your html. But you can handle validation logic in component and then push to array.
If you add a new item to array, it automatically will get added to the template as you have *ngFor loop.
Here are some useful links for your use case:
https://www.youtube.com/watch?v=xYv9lsrV0s4&t=804s
https://scotch.io/tutorials/how-to-build-nested-model-driven-forms-in-angular-2
https://blog.thoughtram.io/angular/2016/03/21/template-driven-forms-in-angular-2.html

ng-repeat not updated inside bootstrap modal

I just take a simple array and there is add more button in which i just push one more object to that array.
The array is ng-repeat which renders all the fields. My code are given below.
<div ng-init="core.iv=[{email:'',name:''}];">
<div ng-repeat="n in core.iv track by $index">
<div class="col-sm-6 pad0">
<div class="form-group">
<input type="email" class="form-control mIn" ng-model="n.email" placeholder="Email id" />
<span class="bar"></span>
</div>
</div>
<div class="col-sm-6 pad0">
<div class="form-group">
<input type="text" class="form-control mIn" ng-model="n.name" placeholder="Name" />
<span class="bar"></span>
</div>
</div>
</div>
<div class="col-xs-12 pad0 text-right">
<button class="btn btn-t-primary btn-sm" ng- click="core.iv.push({email:'',name:''});">add more</button>
</div>
</div>

Categories

Resources