Angular2 ngModel binding in the third property level gets undefined - javascript

A weird thing is happening on my form or maybe i am not doing it right, let me explain to you by presenting my code.
i have defined a form object inside my component
form = {};
There is a button on each row with data that when you click it opens a modal widow and also passes the item as argument.
<a class="btn btn-warning" (click)="open(item)"><i class="glyphicon glyphicon-pencil"></i></a>
This is the method that fires and opens a modal window but also assign the item object to form object above:
open = (item: any) => {
this.inventoryEditModal.open(); //Opens a modal window
this.form = item; // the assignment
}
The item object is available on the view by printing it out like this:
{{ form | json }} // i can see all item properties
The modal window contains a form where user will edit the item, so basically the input form fields should get filled with item properties values but for some reason the third level is undefined and i don't understand why, let me show you an screenshot of the second level
<input type="text" class="form-control" [(ngModel)]="form.alarmSystem" name="wireless">
The third level gets undefined:
<input type="text" class="form-control" [(ngModel)]="form.alarmSystem.wireless" name="wireless">
This issue is happening only for the third level "object.object.property". I am only showing one input field but the form contains more than 8 fields they all have same issue.
Not sure what i am missing here, but logically it should work. Do you have see this issue happening here and there or experienced your self?
Thank you in advance.

I am not sure if it helps your case, but I was in a very similar situation.
What helped me out was using the "safe-navigation-operator".
I assume that what you need to do is just add the ? after form:
<input type="text" class="form-control" [(ngModel)]="form?.alarmSystem.wireless" name="wireless">
The docs can be found here: https://angular.io/docs/ts/latest/guide/template-syntax.html#!#safe-navigation-operator

There can be 3 possible solutions with Angular 5
Don't assign ngForm to the template variable of the form (in form HTML element)
Don't do this -
<form #newItem="ngForm" (ngSubmit)="saveItem(newItem.value);">
Instead, do this -
<form (ngSubmit)="saveItem();">
<input type="text" class="form-control" name="wireless [(ngModel)]="form.alarmSystem.wireless">
<submit type="submit">Save</submit>
</form>
By this, you will be able to assign a 3 level nested property to
[(ngModel)] without any elvis or safe navigation operator (?).
If you are assigning ngForm to the form template variable then [(ngModel)] will give undefined for a 3 level nested property even if it already has some value.
So, use the name attribute instead -
<form #newItem="ngForm" (ngSubmit)="saveItem(newItem.value);">
<input type="text" name="alarmSystem.wireless" ngModel class="form-control">
</form>
Now, in this case, the nested property alarmSystem.wireless assigned
to the name attribute will be bound 2-way using ngModel directive.
And you can easily access it in the Event emitter function.
And the last solution by using elvis operator (?) is -
Here, again we will not assign ngForm in the form template variable, although there will not be any error but it won't store the value entered in input correctly.
So, split 2-way data binding with [ngModel] and (ngModelChange) like this
<form (ngSubmit)="saveItem();">
<input type="text" name="wireless"
[ngModel]="form?.alarmSystem?.wireless"
(ngModelChange)="form.alarmSystem.wireless=$event" class="form-control">
</form>
Also you can refer to this answer - Correct use of Elvis operator in Angular2 for Dart component's view
But, I don't recommend this solution as it adds up a lot of code.

Related

How to access unknown form in controller?

I have more than three dynamically generated forms. I need to iterate all the errors of the forms in controller. I am assigning form names by using models.
<form name="{{myForm}}" novalidate>
<input type="text" ng-model="username" name="username" required/>
<span ng-show="(submit && myForm.username.$error.required)">
<span>Required</span>
</span>
angular.module("myApp",[]).controller("myCtrl",function($scope) {
$scope.myForm= "validateForm";
console.log("form" + $scope.myForm)
});
What I want is when I console $scope.myForm it should print the form object but what happens is it just prints the "validateForm" string.
You ultimately want $scope.validateForm since "validateForm" is the name you give to the form once name="{{myForm}}" is compiled:
Can get it from $scope[$scope.myForm]
Note that this won't be available in controller until after the view is compiled first time and the validation object is created during the compile process
All you are currently doing is logging a primitive that you assigned on the previous line

Scope lost in ng-include and ng-submit does not submit form while ng-click does but without values of form

I am trying to use ng-include and ng-submit for the first time. I have been trying to follow this SO question Why form undefined inside ng-include when checking $pristine or $setDirty()?. Here is how I have structured my index.html:
<div id="info" ">
<div ng-include src="'standard.html'" ng-controller="FormController as formcontrol">
</div>
</div>
In my standard.html
<uib-accordion close-others="oneAtATime"> <uib-accordion-group
heading="{{person.personID}}" ng-repeat="person in people.info">
<form name="formHolder.personForm>
<div class ="form-group">
<input type="text" name="name"
class="form-control"
ng-model="person.name"
ng-readonly="person.name">
</div>
----------
</form>
<button type="button" ng-submit="updateStatus(person.personID)"
class="btn btn-success btn-lg btn-block">Update</button>
Similarly, I have 20 more fields, of which only 4 are editable fields. Once user click update button, I want to get all the form data into an ajax call which is being made within the FormController.
In my FormController:
(function() {
angular.module('peopleInfo2').controller('FormController', ['$http','$scope', function($http, $scope) {
$scope.formHolder = {};
$scope.updateStatus =function (personID) {
console.log($scope.formHolder);
};
}]);
})();
Questions:
a) form does not get invoked when I use ng-submit, but it does when I use ng-click. I have read the differences between them and everywhere they say that I should use ng-submit. What am I doing wrong?
b) Currently, if I use ng-click then the data in $scope.formHolder is a personForm object, which has my data, all in object form within updateStatus function. Why am I not able to access them like deviceForm.personID? Why does it give me values like $modelValue and $viewValue instead of just the value bounded to ng-model in form?
c) If I use ng-click, then whenever form is submitted. it just picks up value from the last entry in the person.info array. Meaning that no matter what, only last value read by ng-repeat is accessible when trying to read values of ng-model. Why?
I will appreciate any help. I am close to get this thing, but I want to make sure that I understand things correctly as it will be used throughout the project. I was trying to use a custom directive earlier, but was suggested that that approach is not correct to render web forms and should use ng-include. Thank You.
There are some problems in your code but as the first one I think you should use ng-submit directive on your form tag. like this:
<form name="{{formHolder.personForm}}" ng-submit="updateStatus(person.personID)">...</form>
with an <input type="submit" class="btn btn-success btn-lg btn-block"/> for the submit button inside your form.
But why don't you use the ng-repeat inside your form and pass the whole array to your submit function?

Angular: how to reset form elements that map to different data

My angular app has > 1 forms on a page. Each form can be saved or reset. The fields on each form don't necessarily map to its own data object.
For example I have two pieces of data that must be gotten and saved separately. Let's call the json chunks, a and b.
HTML:
<form>
<input type="text" ng-model="a.foo"/>
<input type="text" ng-model="b.bar"/>
</form
<form>
<input type="text" ng-model="b.bar[0].baz"/>
<input type="text" ng-model="a.boo"/>
</form
If the first form were mapped to just a and the second to b it would be a simple matter of resetting the data. But I don't want to reset all the a or b data for all forms on the page. I just want to reset the specific data fields for the inputs represented on a particular form.
My current logic mostly works. On cancel I get the elements in the form, get their ng-model attributes and dynamically reset properties on a and b depending on the ng-model string value. This seems "dirty" and plus it doesn't work for some ng-model attributes which use the $index special variable because the attr value isn't parsed by angular when doing .attr(). What's the best solution for this? Different models for each form that map back to the original data?
Make a deep copy of the object you are editing when opening the form and edit it ( angular.extend)
when save just use your save logic
on cancel you will need to do nothing
e g
.controller('myctrl', function($scope, dataService) {
$scope.data = angular.extend( {}, dataService.get())
$scope.save = function ( ) {
dataService.set($scope.data)
}
})
I haven't done this before, but you can try having something like below:
<form>
<input type="text" ng-model="form1.element1" ng-change="a.foo=form1.element1"/>
<input type="text" ng-model="form1.element2" ng-change="b.bar=form1.element2"/>
</form>
<form>
<input type="text" ng-model="form2.element1" ng-change="b.bar[0].baz=form2.element1"/>
<input type="text" ng-model="form2.element2" ng-change="a.boo=form2.element2"/>
</form>
to have an easy reference to your form-specific elements. And then for resetting, you can simply reset the form1 or form2 objects with initial values using angular.copy().
One thing you may need to watch with this approach is, once you enter some values and reset although on the form1 or form2 will be reset, there may still be values in a and b objects, you might want to handle that (disable submit for e.g.)

Set form specific property as valid in angularjs

I have form and i want to set one of its property to valid based on some condition.
Lets say,
<form class="form-horizontal" name="Registration">
<form name="studentRegisteration">
<input type="number" id="input" name="input" model="input">
</form>
</form>
I am trying as following but i see in immediate window (Visual studio), it gives undefined outcome.
$scope.Registration.studentRegisteration.input.$setValidity('integer', false);
'integer' is a property i am setting it false in my directive.
I want to do this so eventually form becomes valid.
I am not sure i am doing in right away using my above statement.
Any help would be appreciated.
thanks
When you want to access a nested form you need to first use form then ng-form.
I modified your code a bit in this plunker to show you.

Angular - Adding an input's value with a number from $scope

I have the following code:
<div data-ng-controller="MainController">
<input class="amount" type="text" name="" value="" />
<input class="result" type="text" name="" value=""/>
</div>
I want to take a numerical value from $scope and add it to a number entered by a user in the input with class "amount" and display the result in the input with class "result". So, basically, the variable is defined in the MainController function as the following:
$scope.cost = 100;
I'm a bit confused as to what the best way is to do this, I see there are ng-value and ng-model directives at my disposal but I am having a hard time understanding which is the right one for this application (and how to properly use them).
Seems like your application is asking for an inputs and they are going to submit there values OR gonna store it somewhere in DB. So ng-model (two way binding) will suits you application, which will update the value on model & view both.
Markup
<div data-ng-controller="MainController">
<input class="amount" type="text" ng-model="cost"/>
</div>
Above field will pre-populated as 100 and as you update it will also change $scope.cost value and the value if it is displayed on view anywhere.
Don't think about the ng-value that is only one way sort of binding. You can assign the value to input using ng-value="cost" that will only update the value attribute of input but when you update input from html you will never get those changes reflected inside cost scope variable as ng-value is meant for single way binding. Thinks like you should use use ng-value only when you want to display a value.
you should use ng-model
ng-value : Its a directive useful for evaluating expression and the value is bound to $scope used for evaluating expressions
ng-model : helps in two-way data binding ,view-->controller and vice versa moreover its a directive binds the value of HTML controls

Categories