How to bind 2 models to one input field in Angular? - angularjs

Is there anyway that I can bind two model values to one input field?
Suppose I have input field which I want to be the value of two variables in the scope something like:
<input type="text" model="sn_number; id" >

You cannot, but there are some workarounds.
1. Use ngChange to update the other model
<input type="text"
ng-model="sn_number"
ng-change="id=sn_number"/>
2. You could watch a model, and when in changes, update another
$scope.$watch('sn_number', function(v){
$scope.id = v;
});
You would need to watch also for changes in id if you want to keep them in sync.
Example here

You can bind fields immediately, not only in ng-change, and actually it isn't data binding, its only angular expression
<label>Name</label>
<input type="text" ng-model="name" value="{{name}}"/>
<label>Key</label>
<input type="text" ng-model="key" value="{{key=name}}" />

It would make no sense to bind an input to two variables in the model. Binding works both ways, so if the model is updated, the field is updated and vice-versa. If you were to bind to two variables, what would be the single source of truth?
However you can use ng-change to call a method on the controller which can set two variables when the field changes.

with ng-init
<div ng-controller="ctrl" ng-init="model = { year: '2013', month:'09'}">
or
<div ng-repeat="c in contact" ng-init="likes = { food: 'steak', drink:'coke'}">

Related

AngularJs: Copy the data using ng-value but model does not update

I'm having an issue on updating or assigning the value or data into the model using ng-value.
I would like to copy any values in the DisplayName model to CopyDisplayName and using below directives i was able to do that, But the problem is the model CopyDisplayName doesn't have any value when I submit my changes. It can only have if I inputted it manually.
<input type="Text" ng-model="DisplayName" ng-disabled="true" />
<input type="Text" ng-model="CopyDisplayName" ng-value="DisplayName" />
Forgot to include that the DisplayName is disabled.. the data will came from service call.
ngValue
Binds the given expression to the value of or input[radio], so that when the element is selected, the ngModel of that element is set to the bound value.
You can take a look in this documentation.
So basically, the one you're doing right now will not work.
You can do this in your angular controller:
$scope.copyValue = function () {
$scope.copyDisplayName = $scope.displayName;
}
In html:
<input type="text" ng-model="displayName" ng-change="copyValue()" />
Just assign one variable to another:
// in the controller
$scope.CopyDisplayName = $scope.DisplayName;
If you need to keep them in sync (and for some reason, you don't want to just use the same variable), then you can keep them updated via ng-change:
<input type="Text" ng-model="DisplayName" ng-change="CopyDisplayName = DisplayName" />
Directives like ng-value (or ng-checked) only toggle the attributes in the DOM - they do not alter the View Model.
You can add $watch on DisplayName as:
$scope.$watch('DisplayName',function(newValue, oldValue){
console.log(newValue +":"+oldValue)
$scope.CopyDisplayName = newValue;
});
To have copy updated you need copy value by reference. For that you need to wrap displayName to object:
$scope.model = {DisplayName: 'val'}; and make a copy of it: $scope.modelCopy = $scope.model;
<input type="Text" ng-model="model.DisplayName" ng-disabled="true" />
<input type="Text" ng-model="modelCopy.DisplayName" ng-value="DisplayName" />
JSFiddle
what you can do in controller is watch the model and copy that value whenever it is changed($watch will do that for you) you dont need ngChange on the HTML.
$scope.$watch('displayName', function() {
$scope.copyDisplayName = $scope.displayName;
});

Detecting value change in ng-model without using $watch and form for application having large number of models

My application has a lot of models in the page. I want to detect whether user has changed value of any model on click of save. Using $watch on every model puts too much load, so don't want to use this method. Is there any good approach for this?
Small snippet is like below:
<div>
<div class="ttere2">
<input type="radio" name="nc2-radio3" ng-model="nc2PenaltyAfter" value="specificDays" />
<input class="ggfe1" ng-model="nc2AfterDays" ng-disabled="nc2PenaltyAfter!='specificDays'" type="number" min="1" max="100" step="1" value="1" />days</div>
<div class="admin_wp-line">
<input type="radio" name="nc2-radio3" ng-model="nc2PenaltyAfter" value="immediately"/> Immediately </div>
<div class="acfv1">model 1</div>
</div>
<div style="margin-top: 20px;"><button ng-click="saveData();">Done</button></div>
............too many inputs go here
</div>
Use .$dirty! Angular will set this on every element that is bound using ng-model, automatically, when it has been changed. It will also set it on the entire form. You can access it in code like this:
if ($scope.myForm.$dirty) {
// Your code here
}
Angular will provide six useful variables on the form, and every ngModel-bound element in your form: $dirty and $pristine, $valid and $invalid, and $touched and $untouched. You can mix and match these to drive a lot of useful behaviors, and they're available both in your controller (using the expression shown above) and your template (directly).

Get "raw" value from invalid input field

I have an input field in a form with some validations. It works like a charm.
It basically looks like this:
<input
class="form-control"
type="number"
ng-model="zipcode"
ng-minlength="5"
ng-maxlength="5"
id="zipcode"
name="zipcode"
required
>
A working plunkr is here: http://plnkr.co/edit/H0h59kG75T5MGE9cAhSo?p=preview
But now I also want to react to every input change - whether valid or not. So for example if the input field contains "123" it is not valid and the value is not transferred to my model - thats fine. But I still want to get the value to do some intermediate requests to a webservice.
Any Ideas?
First call the form element in your controller, then use the $viewValue attribute :
View :
<form name="form">
<input
...
ng-model="zipcode"
ng-change="getRawValue(form)"
name="zipcode"
required
>
</form>
Controller:
$scope.getRawValue = function(form) {
var rawValue = form.zipcode.$viewValue;
}
Angular 1.3 introduced a real answer for this: allowInvalid in ngModelOptions.
Example:
<input
type="text"
name="userName"
ng-model="user.name"
ng-model-options="{allowInvalid: true}"
>
Here is what i came up with for your scenario.
Basically you can write a directive which requires ngModel (ngModelController). The ngModelController has a array of parsers which it call to parse the view value in a pipeline manner. If validation fail these parsers do not update the model. If you inject a custom parser at the start of this parsers array, you can get the each view change value and do anything you want with it.
See my plunkr here http://plnkr.co/edit/ruB42xHWj7dBxe885OGy?p=preview (See console)
The basic code would be
ngModelCtrl.$parsers.splice(0,0,(function (viewValue) {
console.log("The view value is:"+viewValue)
return viewValue;
}));
Also see ngModelController documenation

Model not updated when view changes

I have a form for creating new records in a partial which I load in my main view like this
<div ng-controller="NewProductController">
<ng-include src=" 'views/partials/product-form.html' "></ng-include>
</div>
In the form, I have some input fields
..
<input ng-model="cip" type="text" id="cip" class="form-control" placeholder="Enter the CIP" autofocus="autofocus"/>
<input ng-model="name" type="text" id="name" class="form-control" placeholder="Enter the name" />
And in my controller, I'm sending a POST request with the values of the input fields:
...
.controller('NewProductController', function(Product, $scope) {
$scope.create = function () {
Product.create( {'cip': $scope.cip,
'name': $scope.name,
'dosage': $scope.dosage,
...
});
};
The problem is that when the values of the input fields change, it is not reflected in the controller ($scope.cip and $scope.name are undefined unless I initialized them with some value) but when $scope.cip and $scope.name are changed in the controller, the changes are correctly reflected in the view.
I thought that kind of updates are automatic or am I missing something ?
The reason why this is happening because ng-include creates a child scope. Since you are managing the model fields in the child scope i.e inside the template html, the fields are not available on the parent scope, where your controller is defined.
To fix this issue first and foremost thing that you need to do would be to create a obj such as product and define it on the controller NewProductController scope.
$scope.product={};
The template then should bind to sub properties of this product object.
<input ng-model="product.cip" type="text" id="cip" class="form-control" placeholder="Enter the CIP" autofocus="autofocus"/>
Now your changes would be available in the parent product object.
You can improve it a bit by passing the product object using ng-init like this
<ng-include src=" 'views/partials/product-form.html' " ng-init='model=product'></ng-include>
Now your template input fields change to
<input ng-model="cip" type="text" id="model.cip" class="form-control" placeholder="Enter the CIP" autofocus="autofocus"/>
Advantage
You template is not dependent on the structure of parent model class. Dependency is explicit. The template becomes more reusable as it clearly defines the model it works with, like in your case the template works with Product model.
For the sake of completeness of the answer i must link to this must read article, Understanding Scopes

AngularJS - Model not updating on selection of radio button generated by ng-repeat

I am generating a bunch of radio buttons using ng-repeat, and then trying to update a model when one of them is selected. This doesn't appear to be working.
The same markup works just fine when the radio inputs are hardcoded as opposed to being generated by ng-repeat.
This works:
<input type="radio" ng-model="lunch" value="chicken" name="lunch">
<input type="radio" ng-model="lunch" value="beef" name="lunch">
<input type="radio" ng-model="lunch" value="fish" name="lunch">
{{lunch}}
This doesn't:
<input type="radio" ng-model="lunch" ng-repeat="m in meat" value="m" name="lunch">
{{lunch}}
See jsfiddle showing both here: http://jsfiddle.net/mark_up/A2qCS/1/
Any help would be appreciated.
Thanks
<div ng-controller="DynamicCtrl">
<input type="radio" ng-model="$parent.lunch" ng-repeat="m in meat"
ng-value="m" name="lunch">
{{lunch}}
</div>
Should do the trick.
As I understand it, ng-repeat creates its own $scope. so you need to refer to the $parent $scope; Yes, AngularJS is tricky. Also you need to change the value to ng-value too.
the above issue was discussed here
That happens because ng-repeat creates a new scope. Basically, each <input> is creating a selectedOption value on its own inner scope. To work around that, create a new container object for that value. For example, you could declare in your controller:
$scope.data = {selectedOption: x};
And then in your template, use ng-model="data.selectedOption"
in this way, ng-model gets updated .. :)
this is tricky
Just need to replace value with ng-value

Resources