Populate Input Field using FormControl Angular - javascript

I have an input field where I need to populate array data inside it which is coming
from API, I have used FormControl to populate the data but not able to achieve the same.I am getting the response on console but not able to populate it on UI. Below is my code if any anyone could guide me as I have spent 2 entire days and new in Angular. Can anyone please help me here.
HTML Code:
<div formArrayName="ints" *ngFor="let inCompany of insurance.controls; let i = index">
<div [formGroupName] = "i">
<ion-card *ngFor="let eq of ef;let i=index;">
<ion-item>
<ion-input formControlName="iCompany"></ion-input>
</ion-item>
</ion-card>
</div>
</div>
TS Code:
ionViewWillEnter(){
this.loadData();
}
ngOnInit() {
this.sForm = this.formBuilder.group({
ints: this.formBuilder.array([]),
})
}
get ints(): FormArray {
return this.sForm.get('ints') as FormArray;
}
get formGroup(): FormGroup {
return this.formBuilder.group({
name: ['justTest'],
});
}
loadData(){
this.service.getefDetails(data).subscribe((response: any) => {
this.ef= response.data;
var formArray = this.sForm.get('ints') as FormArray;
for (let i = 0; i < this.ef.length; i++) {
console.log(this.ef.length, this.ef[i].percentage)
var chec=this.ef[i].percentage
formArray.push(this.formGroup);
formArray.controls[i].patchValue(chec);
}
)}
}
Array Type:
[{name:"test", percentage: "29"},{name:"abc", percentage: "45"}, {name:"def", percentage: "63"}]

First of all, I suggest you re-think your approach as mentioned in the earlier comment it seems you have made it unnecessarily complicated.
Also, I would think of renaming your variables it is quite confusing and will be a pain to maintain later on.
To answer your question and get the "ion-input" printed on the screen do the following changes to the HTML.
You can not assign <div [formGroupName] = "i"> i to the formGroup since it is not of type formGroup as it is assigned to the index.
The solution is to assign <div [formGroupName] = "insuranceCompany[0]">
So that a form group will be assigned.
Again I suggest that you rename the variable "insuranceCompany" for clarity purposes as there is a control named "insuranceCompany" as well.
Here is a working example of your code minus the ionic tags.
https://stackblitz.com/edit/angular-ivy-b3gtly?file=src/app/app.component.ts
Hope I made myself clear, and hope it helps.

You can use patchValue directly to an form control in order to do this.
Your current setup seems too complicated unless there are a bunch of other values in the form that's not displayed here.
However, when you get a response from API, you can simply get the reactive form element, and set value.
this.suitablityForm.insurance.insuranceCompany.patchValue('VAL_YOU_WANT');

Related

Angular directive ngIf is not working as expected

We are trying to pass data from one component to another and below is the approach we are taking. When there is no data we want to show the error message
<div *ngIf="showGlobalError">
<h6>The reporting project doesn't have any Shippable Items</h6>
</div>
and the component.ts is like
showGlobalError = true;
constructor(private psService: ProjectShipmentService, private pdComp: ProjectDetailsComponent) {
this.psService.tDate.subscribe(x => this.cachedResults = x);
}
ngOnInit() { }
ngDoCheck() {
if (this.cachedResults.length > 0 && this.count <= 1) {
this.showGlobalError = false;
this.populateArrays();
this.count++;
}
}
populateArrays() {
this.reportingProject = [this.pdComp.rProjectNumber];
this.projectSalesOrder = this.pdComp.rSalesOrder;
this.clearFilter();
........
The issue is Even though there is data in the this.cachedResults that is this.cachedResults.length not equal to '0' for few seconds 'The reporting project doesn't have any Shippable Items' is shown in the page and then shows the data I am not sure if this something with the ngDoCheck() is causing this. Any help is greatly appreciated
Since, the default value of showGlobalError is true, the page load shows the error message.
Please make it by default false and make it true when this.cachedResults.length is 0 or this.cachedResults is undefined or this.cachedResults is null.
Hope this solves your problem.
Rather than subscribing in the code you can use the async pipe in your template
items$ = this.psService.tDate;
showGlobalError$ = this.items$.pipe(map(results => !results || !results.length));
constructor(private psService: ProjectShipmentService, private pdComp: ProjectDetailsComponent) { }
and in your template
<div *ngIf="showGlobalError$ | async">
<h6>The reporting project doesn't have any Shippable Items</h6>
</div>
<ng-template *ngFor="let item of items$ | async">
Do stuff with {{item | json}}
</ng-template>
This manages your subscription for you and fixes the memory leak you have in your code with the subscription you don't unsubscribe from.
Take a look at alibrary I wrote for this sort of thing, make caching data a lot easier. https://medium.com/#adrianbrand/angular-state-management-with-rxcache-468a865fc3fb

AngularJS - Get printed value from scope inside an attribute?

I'm currently working on an AngularJS project and I got stuck in this specific requirement.
We have a service that has all the data, DataFactoryService. Then, I have a controller called DataFactoryController that is making the magic and then plot it in the view.
<div ng-repeat = "list in collection">
{{list.name}}
...
</div>
Now, we have a requirement that pass multiple data into one element. I thought an "ng-repeat" would do, but we need to have it inside an element attribute.
The scenarios are:
At one of the pages, we have multiple lists with multiple data.
Each data has a unique code or ID that should be passed when we do an execution or button click.
There are instances that we're passing multiple data.
Something like this (if we have 3 items in a list or lists, so we're passing the 3 item codes of the list):
<a href = "#" class = "btn btn-primary" data-factory = "code1;code2;code3;">
Submit
</a>
<a href = "#" class = "btn btn-default" data-factory = "code1;code2;code3;">
Cancel
</a>
In the example above, code1,code2,code3 came from the list data. I tried several approach like "ng-repeat", "angular.each", array, "ng-model" but I got no success.
From all I've tried, I knew that "ng-model" is the most possible way to resolve my problem but I didn't know where to start. the code below didn't work though.
<span ng-model = "dataFactorySet.code">{{list.code}}</span>
{{dataFactorySet.code}}
The data is coming from the service, then being called in the controller, and being plot on the HTML page.
// Controller
$scope.list = dataFactoryService.getAllServices();
The data on the list are being loaded upon initialization and hoping to have the data tags initialized as well together with the list data.
The unique code(s) is/are part of the $scope.list.
// Sample JSON structure
[
{ // list level
name: 'My Docs',
debug: false,
contents: [ // list contents level
{
code: 'AHDV3128',
text: 'Directory of documents',
...
},
{
code: 'AHDV3155',
text: 'Directory of pictures',
...
},
],
....
},
{ // list level
name: 'My Features',
debug: false,
contents: [ // list contents level
{
code: 'AHGE5161',
text: 'Directory of documents',
...
},
{
code: 'AHGE1727',
text: 'Directory of pictures',
...
},
],
....
}
]
How can I do this?
PLUNKER -> http://plnkr.co/edit/Hb6bNi7hHbcFa9RtoaMU?p=preview
The solution for this particular problem could be writing 2 functions which will return the baseId and code with respect to the list in loop.
I would suggest to do it like below
Submit
Cancel
//inside your controller write the methods -
$scope.getDataFactory = function(list){
var factory = list.map( (a) => a.code );
factory = factory.join(";");
return factory;
}
$scope.getDataBase= function(list){
var base= list.map( (a) => a.baseId);
base= base.join(";");
return base;
}
Let me know if you see any issue in doing this. This will definitely solve your problem.
You don't really have to pass multiple data from UI if you are using Angular.
Two-way data binding is like blessing which is provided by Angular.
check your updated plunker here [http://plnkr.co/edit/mTzAIiMmiVzQfSkHGgoU?p=preview]1
What I have done here :
I assumed that there must be some unique id (I added Id in the list) in the list.
Pass that Id on click (ng-click) of Submit button.
You already have list in your controller and got the Id which item has been clicked, so you can easily fetch all the data of that Id from the list.
Hope this will help you... cheers.
So basing from Ashvin777's post. I came up with this solution in the Controller.
$scope.getFactoryData = function(list) {
var listData = list.contents;
listData = listData.map(function(i,j) {
return i.code;
});
return listData.join(';');
}

Angular JS - ng-repeat repeating old values

I am new to Angular JS. I have created a code in angular using app and controller. What I am tyring to do is to add name dynamically to a array when a button is clicked.
By default my array has two value passed. When i give an input and click the add button,it adds the string for the first time.
But when i give another input and click add again, the old string is replaced by the new string and the new string is added again.
Here is the piece of code on JSFiddle: http://jsfiddle.net/5DMjt/3680/
var demo= angular.module("demo",[]);
var simplecontroller = function($scope){
$scope.members = [{id:1,name:'prateek'},{id:2,name:'Ruchi'}];
$scope.addmember = function(newmember){
newmember.id = $scope.members.length+1;
$scope.members.push(newmeber);
demo.controller(simplecontroller);
}
}
and here is the HTML Code:
<div ng-app="demo">
<div ng-controller="simplecontroller">
<ul>
<li ng-repeat="member in members">{{member.id}}-{{member.name}}</li>
</ul>
Name<input type="Text" ng-model="inputmember.name">
</br><h2>
{{inputmember}}
</h2>
<input type="button" value="Add" ng-click="addmember(inputmember)">
</div>
</div>
Please Help !
What i analyzed is that push function is passing the address that is why binding still exists.What u can do is pass the value instead like i did below-:
$scope.addmember = function(newmember){
newmember.id = $scope.members.length+1;
$scope.members.push({id:newmember.id,name:newmember.name});
demo.controller(simplecontroller);
}
Hope this solves your problem.Happy learning :)
You have two options.
Either you can reinitialize it every time what I would not recommend.
And the other one is to, pass the parameters with values.
$scope.members.push({id:newmember.id,name:newmember.name});
:)
See this updated fiddle: http://jsfiddle.net/5DMjt/3689/
Name<input type="Text" ng-model="newname">
This gives you a scope variable newname.
<input type="button" value="Add" ng-click="addmember()">
And addmember function uses this newname to create a new object and add it to the list:
$scope.addmember = function(){
var newmember = {};
newmember.id = $scope.members.length+1;
newmember.name = $scope.newname;
$scope.members.push(newmember);
}
You have a syntax error. See console error for more info.
Your variable inputmember is not defined anywhere.
Also you need to push to array new reference of the object, so the old one in array does not change each time you type value.
Here is a working version.
http://jsfiddle.net/a9zvgm8k/
$scope.addmember = function(newMember){
newMember.id = $scope.members.length+1;
$scope.members.push(angular.extend({}, newMember));
demo.controller(simplecontroller);
}
$scope.members = $scope.members.concat({id: newmember.id, name: newmember.name});
Solved : http://jsfiddle.net/5DMjt/3693/
Before pushing to $scope.members you need to create a new object and populate it with id and name from the input.

Update unrelated field when clicking Angular checkbox

I have a list of checkboxes for people, and I need to trigger an event that will display information about each person selected in another area of the view. I am getting the event to run in my controller and updating the array of staff information. However, the view is not updated with this information. I think this is probably some kind of scope issue, but cannot find anything that works. I have tried adding a $watch, my code seems to think that is already running. I have also tried adding a directive, but nothing in there seems to make this work any better. I am very, very new to Angular and do not know where to look for help on this.
My view includes the following:
<div data-ng-controller="staffController as staffCtrl" id="providerList" class="scrollDiv">
<fieldset>
<p data-ng-repeat="person in staffCtrl.persons">
<input type="checkbox" name="selectedPersons" value="{{ physician.StaffNumber }}" data-ng-model="person.isSelected"
data-ng-checked="isSelected(person.StaffNumber)" data-ng-change="staffCtrl.toggleSelection(person.StaffNumber)" />
{{ person.LastName }}, {{ person.FirstName }}<br />
</p>
</fieldset>
</div>
<div data-ng-controller="staffController as staffCtrl">
# of items: <span data-ng-bind="staffCtrl.infoList.length"></span>
<ul>
<li data-ng-repeat="info in staffCtrl.infoList">
<span data-ng-bind="info.staffInfoItem1"></span>
</li>
</ul>
</div>
My controller includes the following:
function getStaffInfo(staffId, date) {
staffService.getStaffInfoById(staffId)
.then(success)
.catch(failed);
function success(data) {
if (!self.infoList.length > 0) {
self.infoList = [];
}
var staffItems = { staffId: staffNumber, info: data };
self.infoList.push(staffItems);
}
function failed(err) {
self.errorMessage = err;
}
}
self.toggleSelection = function toggleSelection(staffId) {
var idx = self.selectedStaff.indexOf(staffId);
// is currently selected
if (idx >= 0) {
self.selectedStaff.splice(idx, 1);
removeInfoForStaff(staffId);
} else {
self.selectedStaff.push(staffId);
getStaffInfo(staffId);
}
};
Thanks in advance!!
In the code you posted, there are two main problems. One in the template, and one in the controller logic.
Your template is the following :
<div data-ng-controller="staffController as staffCtrl" id="providerList" class="scrollDiv">
<!-- ngRepeat where you select the persons -->
</div>
<div data-ng-controller="staffController as staffCtrl">
<!-- ngRepeat where you show persons info -->
</div>
Here, you declared twice the controller, therefore, you have two instances of it. When you select the persons, you are storing the info in the data structures of the first instance. But the part of the view that displays the infos is working with other instances of the data structures, that are undefined or empty. The controller should be declared on a parent element of the two divs.
The second mistake is the following :
if (!self.infoList.length > 0) {
self.infoList = [];
}
You probably meant :
if (!self.infoList) {
self.infoList = [];
}
which could be rewrited as :
self.infoList = self.infoList || [];

Conditionally bind data in AngularJS

I have an array of tasks. They have titles and and labels.
function Task(taskTitle, taskType) {
this.title = taskTitle;
this.type = taskType;
}
$scope.tasks = [];
I end up declaring a bunch of tasks with different types and adding them to the array
In my html, I show a column of cards, filtered by type of task:
<div ng-model="tasks">
<div class="card" ng-repeat="abc in tasks track by $index" ng-show="abc.type==0">
<p> {{ abc.title }} </p>
</div>
</div>
I want to bind the first card displayed in this filtered view to some other div. I'll be processing an inbox, so I'll whittle this list of cards down to zero. Each time I 'process' a card and remove it from the list, I need the data to refresh.
<div ng-model="firstCardInFilteredArray">
<h4>Title of first card:</h4>
<p> This should be the title of the first card! </p>
</div>
My intuition was to do something like this (in javascript):
// pseudo-code!
$scope.inboxTasks = [];
for (i=0; i<tasks.length(); i++) {
if (tasks[i].type == 0) {
inboxTasks.append(tasks[i]);
}
}
and somehow run that function again any time the page changes. But that seems ridiculous, and not within the spirit of Angular.
Is there a simple way in pure javascript or with Angular that I can accomplish this conditional binding?
You can filter your ng-repeat: https://docs.angularjs.org/api/ng/filter/filter
<div ng-model="tasks">
<div class="card" ng-repeat="abc in filteredData = (tasks | filter: {type==0}) track by $index">
<p> {{ abc.title }} </p>
</div>
</div>
Additionally, by saving the filtered data in a separate list you can display the next task like this:
<div>
<h4>Title of first card:</h4>
<p> filteredData[0].title </p>
</div>
Your data will automatically update as you "process" tasks.
The other answers helped point me in the right direction, but here's how I got it to work:
HTML
<input ng-model="inboxEditTitle" />
JS
$scope.filteredArray = [];
$scope.$watch('tasks',function(){
$scope.filteredArray = filterFilter($scope.tasks, {type:0});
$scope.inboxEditTitle = $scope.filteredArray[0].title;
},true); // the 'true' keyword is the kicker
Setting the third argument of $watch to true means that any changes to any data in my tasks array triggers the watch function. This is what's known as an equality watch, which is apparently more computationally intensive, but is what I need.
This SO question and answer has helpful commentary on a similar problem, and a great fiddle as well.
More on different $watch functionality in Angular
To update inboxTasks, you could use $watchCollection:
$scope.inboxTasks = [];
$scope.$watchCollection('tasks', function(newTasks, oldTasks)
{
for (i=0; i<newTasks.length(); i++)
{
if(newTasks[i].type == 0)
{
$scope.inboxTasks.append(tasks[i]);
}
}
});

Categories