I'm new to AngularJS, I have a form which has two numeric textboxes and I want to display sum of them:
<div ng-app>
#Html.TextBoxFor(model => model.PS_Fees, new { #ng_model = "PSFees", #class = "form-control DMPClientAccountNew", #type = "number", #step = "any" })
#Html.TextBoxFor(model => model.DMPFees, new { #ng_model = "DMPFees", #class = "form-control DMPClientAccountNew", #type = "number", #step = "any" })
<div> {{ PSFees + DMPFees }}</div>
</ div>
The output displays {{ PSFees + DMPFees }}
I don't understand why, because I don't want to add any more complicated script into this page?
Related
I have an issue while looping through and array, I'm getting all the index from this array correctly but when I use angular patchValue it updates all the inputs with the last index values and not with their respective values as shown :
I want every input to have theirs, for example, first input values should be "1" (left input => longueur) and "1" (right input => quantity)
I tried with .forEach but no success
CODE SAMPLE
component.ts .forEach
ngOnInit() {
this.requiredFields();
this.service.checkExistQuot().subscribe(res => {
this.quotDetails.forEach( (myArray, index) => {
this.dropForm.patchValue({
longueur: this.quotDetails[index].longueur,
quantity: this.quotDetails[index].quantity
})
console.log(index);
});
});
}
HTML, input example
<div class="products">
<div class="d-flex flex-row" *ngFor="let products of selectedDiam;let i = index">
<input class="number" formControlName="longueur" value="" (change)="postQuotationDatas(products.part_id)" type="number">
</a>
<input class="mb-1 flex1 checkbox" type="checkbox">
<a class="tac flex1"></a>
<a class="flex1 mb-1">
<input class="number" value="" formControlName="quantity" (change)="postQuotationDatas(products.part_id)" type="number">
</a>
<a class="flex1"></a>
</div>
</div>
Your problem is that you only have one form group,dropForm, with 2 controls: quantity and longueur. Even though you have multiple html inputs for longueur and quantity, they are share the same reference in the component
So, with your forEach loop, you are actually patching all your controls for each iteration. That's why you have the same value for all your controls, which is the value for the lasst object the loop went over.
Option #1
A possible solution is to have multiple form groups, like in this stackblitz example
component.ts
//dropForms initialisation
this.quotationDetails.map(() =>
{
let group = this.formBuilder.group(
{
longueur: [''],
quantity: [''],
});
this.dropForms.push(group)
}
this.quotationDetails.forEach( (myArray, index) => {
this.dropForms[index].patchValue({
longueur: this.quotationDetails[index].longueur,
component.html
<div class="d-flex flex-row" *ngFor="let products of quotationDetails; let index=index">
<form [formGroup]="dropForms[index]"> <!-- 1 form group per quotation -->
Option #2
The other solution, to have only 1 formGroup, is to give dynamic control names
component.ts
//Initialisation of dropForm
this.quotationDetails.forEach((val, index)=>
{
group[`longueur_${index}`] = '';
group[`quantity_${index}`] = ''
});
this.dropForm = this.formBuilder.group(
group
)
//Patch
this.quotationDetails.forEach( (myArray, index) => {
let patchValue = {};
patchValue[`longueur_${index}`] = this.quotationDetails[index].longueur;
patchValue[`quantity_${index}`] = this.quotationDetails[index].quantity;
this.dropForm.patchValue(patchValue);
component.html
<form [formGroup]="dropForm">
<div class="products">
<div class="d-flex flex-row" *ngFor="let products of quotationDetails; let index = index">
<a>
<input class="number" formControlName="longueur_{{index}}" value="" type="number">
Stackblitz example
Use FormArray and wrap inputs in arrays.
Example add FormControl to FormArray with FormBuilder:
FormArray - A FormArray aggregates the values of each child FormControl into an array.
in componenent ts:
const EMPLOYEE_FORM = {
firstName: ['', Validators.required],
lastName: ['', Validators.required],
isActive : [false, Validators.required]
}
const COMPANY_FORM = {
employees: new FormArray([], [Validators.required])
}
export class AppComponent {
form: FormGroup;
constructor(private fb: FormBuilder) {
this.form = this.fb.group(COMPANY_FORM);
}
get employees(): FormArray {
return this.form.get('employees') as FormArray;
}
addEmployee() {
const employee = this.fb.group(EMPLOYEE_FORM);
this.employees.push(employee);
}
}
in html
<div *ngFor="let item of employees.controls; let i = index;">
<form [formGroup]="item">
<input type="text" formControlName="firstName" class="form-control" placeholder="FirstName">
<input type="text" formControlName="lastName" class="form-control" placeholder="LastName">
<input class="checkbox" type="checkbox" formControlName="isActive">
</form>
</div>
<button (click)="addEmployee()">add new employee</button>
<div *ngIf="employees.length > 0">
{{employees.value | json}}
</div>
See this link: https://stackblitz.com/edit/add-input-to-formarray-with-frombuilder
I would appreciate your assistance on this challenge i'm having with retrieving the content of a database into more than one model. Three columns needed (InsBranchNo, PercentageCover and Leadcode) are available in Underwriting_InsurerPolicyDistribution table. However, Account_ClientReceiptDistribution needs the content of these 3 columns for calculation. How do I pass the content of the 1st to the second for a particular Id using the Foreach Loop.
While retrieving the data from the database for a particular ID, below is how I loaded the rows involved into the Model.Underwriting_InsurerPolicyDistribution model.
My problem is. How do i transfer these rows into Model.Account_ClientReceiptDistribution model?
Your assistance is anticipated and will be very much appreciated.
//Policy distribution
×
Insurer Risk Apportionment
Insurer Branch Code
Is Lead Insurer
Covered %
#{if (!string.IsNullOrEmpty(Model.Underwriting_PolicyFile.PolicyRefCode))
{
for (var i = 1; i <= Model.Underwriting_InsurerPolicyDistribution.Count; i++)
{
#{var n7 = string.Format("Underwriting_InsurerPolicyDistribution[X{0}].InsBranchCode", i);}
#{var n8 = string.Format("Underwriting_InsurerPolicyDistribution[X{0}].InsuerLeadCode", i);}
#{var n9 = string.Format("Underwriting_InsurerPolicyDistribution[X{0}].PercentageCover", i);}
#Html.DropDownListFor(model => model.Underwriting_InsurerPolicyDistribution[i - 1].InsBranchCode, new SelectList(Html.InsurerBranchDropDownList(), "InsBranchCode", "FullDescription", Model.Underwriting_InsurerPolicyDistribution[i - 1].InsBranchCode), new { id = n7, #class = "form-control input-sm" })
#Html.ValidationMessageFor(model => model.Underwriting_InsurerPolicyDistribution[i - 1].InsBranchCode, "", new { #class = "text-danger" })
</td>
<td>
#Html.EditorFor(model => model.Underwriting_InsurerPolicyDistribution[i - 1].InsuerLeadCode, new { id = n8, #class = "form-control input-sm" })
#Html.ValidationMessageFor(model => model.Underwriting_InsurerPolicyDistribution[i - 1].InsuerLeadCode, "", new { #class = "text-danger" })
</td>
<td>
#Html.EditorFor(model => model.Underwriting_InsurerPolicyDistribution[i - 1].PercentageCover, new { id = n9, #class = "form-control input-sm" })
#Html.ValidationMessageFor(model => model.Underwriting_InsurerPolicyDistribution[i - 1].PercentageCover, "", new { #class = "text-danger" })
</td>
</tr>
}
}
}
</table>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
</div>
I suggest you use select new model by linq, and define value of field based on the content values of the Underwriting_InsurerPolicyDistribution
var result = entityToEdit.Underwriting_InsurerPolicyDistribution.Select(a => new
Account_ClientReceiptDistribution {
InsBranchCode = a.InsBranchCode,
PercentageCover = a.PercentageCover,
InsuerLeadCode = a.InsuerLeadCode
}).ToList();
//pass the result into the model as shown in the line of code below
entityToEdit.Account_ClientReceiptDistribution = result;
I hope this will help someone out there.
I am using angular 2 form to populate and edit information in my app. When it comes to images for the data schema on the backend, it has looked like this:
media {
featured: "Url string", <!-- designated default image -->
other: {
img1: "Url string", <!-- secondary images -->
img2: "Url string",
img3: "Url string",
img4: "Url string",
img5: "Url string",
img6: "Url string"
}
}
However now it has been changed to look like this:
media: [
{
thumbs: {
default: "Url string",
}
primary: boolean, <!-- whether or not image is the default image -->
type: string,
raw: "Url string of image"
{
]
My current form.ts handles the image like this:
let featured = '';
let img1 = '';
let img2 = '';
let img3 = '';
let img4 = '';
let img5 = '';
let img6 = '';
if (this.otherMode) {
const pendingCards = this.pendingCardsComponent.getPendingCard(this.id);
featured = pendingCards.media.featured;
img1 = pendingCards.media.other.img1;
img2 = pendingCards.media.other.img2;
img3 = pendingCards.media.other.img3;
img4 = pendingCards.media.other.img4;
img5 = pendingCards.media.other.img5;
img6 = pendingCards.media.other.img6;
this.cardForm = new FormGroup({
'title': new FormControl(cardTitle),
'media': new FormGroup({
'featured': new FormControl(featured, Validators.maxLength(300)),
'other': new FormGroup({
'img1': new FormControl(img1, Validators.maxLength(300)),
'img2': new FormControl(img2, Validators.maxLength(300)),
'img3': new FormControl(img3, Validators.maxLength(300)),
'img4': new FormControl(img4, Validators.maxLength(300)),
'img5': new FormControl(img5, Validators.maxLength(300)),
'img6': new FormControl(img6, Validators.maxLength(300)),
}),
}),
private storeCardUrl = 'httpURL';
onSubmit(value: string){
let formData:Card = this.cardForm.value;
// let formData: Card[] = this.cardForm.value;
let body = JSON.stringify(formData);
let headers = new Headers({'Content-Type': 'application/json'});
return this.http.post(this.storeCardUrl, body, {headers: headers})
.map((response: Response) => response.json())
.subscribe(data => console.log(data))
// console.log(formData);
}
And the form.html section that handles the image rendering and edit looks like this:
<div formGroupName="media">
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<md-input-container class="mdcontainer">
<input
mdInput placeholder="Card Primary Image"
type="text"
id="featured"
formControlName="featured"
class="form-control"
#featured>
</md-input-container>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<img [src]="featured.value" class="img-responsive">
</div>
</div>
<!-- Secondary Images -->
<div formGroupName="other">
<div class="row">
<div class="col-xs-12">
<div class="form-group">
<md-input-container class="mdcontainer">
<input
mdInput placeholder="Secondary Image 1"
type="text"
id="img1"
formControlName="img1"
class="form-control"
#img1>
</md-input-container>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<img [src]="img1.value" class="img-responsive">
</div>
</div>
What I don't understand is handling Media as an array that can still be pulled into my form.html and be able to display the image that I want it to. The old model allowed calling img1/img2/etc. but new model as an array doesn't have any objects outside of the object that contains the Url and other fields. I know that I can create a formArray, with a formGroup and some formControls to get the correct structure but being able to get those images correctly on the html is giving me trouble.
Any help/suggestions/tips would be much appreciated.
I have to deal with a situation where there will be a question and its answers will be dynamically generated. The issue is when i add one question and add its answers then when i add another question then it already contains the same answers as above question.
For Example:
Q. Select ice cream flavour
A. Chocolate
B. Vanilla
Now When i Add another question
Q. Select ice cream company
Now, here it shows
A. Chocolate
B. Vanilla
Following is my code :
<div class="col-lg-12">
<div ng-controller="CustomizationCtrlr">
<form name="CustomizationForm" ng-submit="SaveCustomization(CustomizationForm.$valid)" novalidate>
<div>
<div class="inputDiv">
#Html.TextBoxFor(model => model.GroupTitle, new { name = "GroupTitle", ng_model = "QuestionGroup.GroupTitle", #class = "form-control", maxlength = "65", placeholder = "GroupTitle" })
<br />
</div>
<div class="formgroup" ng-repeat="Question in Questions">
<div class="inputDiv form-group" id="" ng-repeat="QuestionItem in QuestionItems" >
#Html.TextBoxFor(model => model.QuestionItemText, new { name = "QuestionItemText", ng_model = "QuestionItem.Text", #class = "form-control", placeholder = "Question Item Text", required = "required" })
<button ng-show="showAddQuestionItem(QuestionItem)" ng-click="AddQuestionItem($parent.$index)">Add question item</button>
<br />
</div>
<button ng-show="showAddQuestion(Question)" ng-click="AddQuestion()">Add question</button>
</div>
</div>
<button type="submit" name="btnPost" class="btn save-btn" onclick="ValidateForm()">Save Customizations</button>
</form>
</div>
</div>
And following is my script:
<script>
var app = angular.module('ProductCatalog.controllers', [])
.controller('CustomizationCtrlr', function ($scope, $http) {
$scope.AddQuestionItem = function (parentIndex) {
var newItemNo = $scope.QuestionItems.length + 1 + "-" + parentIndex;
$scope.QuestionItems.push({ 'id': 'qi' + newItemNo });
}
$scope.showAddQuestionItem = function (QuestionItem) {
return QuestionItem.id === $scope.QuestionItems[$scope.QuestionItems.length - 1].id;
};
$scope.QuestionItems = [{ id: 'qi1', Text: '' }];
$scope.AddQuestion = function () {
var newItemNo = $scope.Questions.length + 1;
$scope.Questions.push({ 'id': 'q' + newItemNo });
}
$scope.showAddQuestion = function (Question) {
return Question.id === $scope.Questions[$scope.Questions.length - 1].id;
};
$scope.Questions = [{ id: 'q1', Text: '' }];
})
</script>
You always iterate over the same reference of QuestionItems on your scope.
If you want to connect the answers to the question you need to somehow create unique answer arrays per question
One way to do it is save the answers in the question instance in a property and then ng-repeat that
<div class="formgroup" ng-repeat="Question in Questions">
<div class="inputDiv form-group" id="" ng-repeat="QuestionItem in Question.QuestionItems" >
#Html.TextBoxFor(model => model.QuestionItemText, new { name = "QuestionItemText", ng_model = "QuestionItem.Text", #class = "form-control", placeholder = "Question Item Text", required = "required" })
<button ng-show="showAddQuestionItem(QuestionItem)" ng-click="AddQuestionItem($parent.$index, Question)">Add question item</button>
<br />
</div>
And in the JS:
$scope.Questions = [{ id: 'q1', Text: '', QuestionItems: [{ id: 'qi1', Text: '' }] }];
$scope.AddQuestionItem = function (parentIndex, parentQuestion) {
var newItemNo = $scope.QuestionItems.length + 1 + "-" + parentIndex;
parentQuestion.QuestionItems.push({ 'id': 'qi' + newItemNo });
}
The approach you have contains different scope for Questions and QuestionItems. Whenever, you add a new Question, the Question Items is already populated with previous entries from the previous input.
There is a need to change the data structure here, keep an array of questions and a property within an array for the Question Items.
$scope.Questions = [{
"Id": "q1",
"QuestionItems": [{
"Id": "qi1",
"Text": ""
}]
}]
This way you can have Question and its items grouped together.
See the snippet below, I had to remove the .net controls for the demo purpose, you can replace the input with the razor controls you had earlier.
var app = angular.module("MyApp", []);
app.controller('CustomizationCtrlr', function($scope, $http) {
$scope.Questions = [{
"Id": "q1",
"QuestionItems": [{
"Id": "qi1",
"Text": ""
}]
}]
$scope.AddQuestionItem = function(ques) {
var newItemNo = ques.QuestionItems.length + 1
ques.QuestionItems.push({
'Id': 'qi' + newItemNo,
"Text": ""
});
}
$scope.showAddQuestionItem = function(QuestionItem) {
return QuestionItem.id === $scope.QuestionItems[$scope.QuestionItems.length - 1].id;
};
$scope.AddQuestion = function() {
var newItemNo = $scope.Questions.length + 1;
$scope.Questions.push({
"Id": "q" + newItemNo,
"QuestionItems": [{
"Id": "qi1",
"Text": ""
}]
});
}
$scope.showAddQuestion = function(Question) {
return Question.id === $scope.Questions[$scope.Questions.length - 1].id;
};
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="MyApp">
<div class="col-lg-12">
<div ng-controller="CustomizationCtrlr">
<form name="CustomizationForm" ng-submit="SaveCustomization(CustomizationForm.$valid)" novalidate>
<div>
<div class="inputDiv">
<input type="text" ng-model="QuestionGroup.GroupTitle" placeholder="GroupTitle" />
<br />
</div>
<div class="formgroup" ng-repeat="Question in Questions">
<div class="inputDiv form-group" id="" ng-repeat="QuestionItem in Question.QuestionItems">
<input type="text" ng-model="QuestionItem.Text" placeholder="Question Item Text" />
<button ng-click="AddQuestionItem(Question)">Add question item</button>
<br />
</div>
<button ng-click="AddQuestion()">Add question</button>
</div>
</div>
<button type="submit" name="btnPost" class="btn save-btn" onclick="ValidateForm()">Save Customizations</button>
</form>
<pre>{{Questions | json}}</pre>
</div>
</div>
</body>
Here I am using angular.js to show a list of people
<div class="recipient" ng-repeat="person in people">
<img src="{{person.img}}" /> person.name
<div class="email">person.email</div>
</div>
$scope.people = [{id:1}, {id:2}, {id:3}, {id:4}];
The looks is like below
What I want to do is I can select multiple items and by click a OK button, I can get a list of selected items. so If I select id 1 and id 2, then I want to get return a list of [{id:1},{id:2}]
How could I implement it in angular.js
Well I guess that if you're looping through a collection of people using a ng-repeat, you could add the ng-click directive on each item to toggle a property of you're object, let's say selected.
Then on the click on your OK button, you can filter all the people that have the selected property set to true.
Here's the code snippet of the implementation :
<div class="recipient" ng-repeat="person in people" ng-click="selectPeople(person)">
<img src="{{person.img}}" /> person.name
<div class="email">person.email</div>
</div>
<button ng-click="result()">OK</button>
function demo($scope) {
$scope.ui = {};
$scope.people = [{
name: 'Janis',
selected: false
}, {
name: 'Danyl',
selected: false
}, {
name: 'tymeJV',
selected: false
}];
$scope.selectPeople = function(people) {
people.selected = !people.selected;
};
$scope.result = function() {
$scope.ui.result = [];
angular.forEach($scope.people, function(value) {
if (value.selected) {
$scope.ui.result.push(value);
}
});
};
}
.recipient {
cursor: pointer;
}
.select {
color:green;
}
.recipient:hover {
background-color:blue;
}
<script src="https://code.angularjs.org/1.2.25/angular.js"></script>
<div ng-app ng-controller="demo">
<div class="recipient" ng-repeat="person in people" ng-click="selectPeople(person)" ng-class="{ select: person.selected }">
<div class="name">{{ person.name }}</div>
</div>
<button ng-click="result()">OK</button>
Result :
<ul>
<li ng-repeat="item in ui.result">{{ item.name }}</li>
</ul>
</div>
If you only want to show checked or unchecked you could just apply a filter, but you would need to toggle the filter value from undefined to true if you didn't wan't to get stuck not being able to show all again.
HTML:
<button ng-click="filterChecked()">Filter checked: {{ checked }}</button>
<div class="recipient" ng-repeat="person in people | filter:checked">
<input type='checkbox' ng-model="person.isChecked" />
<img ng-src="{{person.img}}" />{{ person.name }}
<div class="email">{{ person.email }}</div>
</div>
Controller:
// Apply a filter that shows either checked or all
$scope.filterChecked = function () {
// if set to true or false it will show checked or not checked
// you would need a reset filter button or something to get all again
$scope.checked = ($scope.checked) ? undefined : true;
}
If you want to get all that have been checked and submit as form data you could simply loop through the array:
Controller:
// Get a list of who is checked or not
$scope.getChecked = function () {
var peopleChkd = [];
for (var i = 0, l = $scope.people.length; i < l; i++) {
if ($scope.people[i].isChecked) {
peopleChkd.push(angular.copy($scope.people[i]));
// Remove the 'isChecked' so we don't have any DB conflicts
delete peopleChkd[i].isChecked;
}
}
// Do whatever with those checked
// while leaving the initial array alone
console.log('peopleChkd', peopleChkd);
};
Check out my fiddle here
Notice that person.isChecked is only added in the HTML.