Why does two-way binding not work in some situations? - angularjs

Consider this HTML
...
<label>Weight:
<input type="text" ng-model="weight">
</label><br>
<label>Height:
<input type="text" ng-model="height">
</label><br>
<label>
BMI: {{bmi}}
</label>
...
and this JavaScript
...
$scope.bmi = +$scope.weight / +$scope.height * +$scope.height;
...
If I give values to the weight and height input fields in the browser, why doesn't the BMI field get updated? Obviously when the controller loads for the first time, the $scope.weight and $scope.height values are empty. But once they get values from the view, why doesn't $scope.bmi use these new values? I have found numerous solutions for this problem (by using $watch or calling a function that updates the bmi value), but could somebody explain WHY the code above does not work?

It is because $scope.bmi is calculated for one time only when controller loads. you will have to make bmi property to be computable or dependable to calculate everytime you change the value of height and weight
See the demo code here to see how can we make dependent properties in angularjs

It's because your bmi here is an affectation. This is set the 1st time you call the controller and never change. Because your var is just a primitive value,i t's not a binding, just a value. A binding could work with a function store on factory for example.
With a function you can update the value.
<label>Weight:
<input type="text" ng-change="updateBMI()" ng-model="weight">
</label><br>
<label>Height:
<input type="text" ng-change="updateBMI()" ng-model="height">
</label><br>
<label>
BMI: {{bmi}}
</label>
And then in your controller you will have the update function :
$scope.updateBMI = function(){
$scope.bmi = +$scope.weight / +$scope.height * +$scope.height;
}

Related

Empty ng-model overwrites ng-value

when I use ng-model together ng-value. ng-value returns empty even there is a value given.
for example, there are two controllers called FirstCtrl and SecondCtrl.
This is FirstCtrl, and If I type a value for this input, it will write in my SeconCtrl input since I call ng-value="firstname" in my SecondController:
I can pass the value from firstctrl to secondctrl(I mean first input field to second input field). But the second input field has an ng-model called d_firstname, which doesn't allow to save ng-value but ng-value is displaying the correct value but saves empty because of ng-model(d_firstname). However, i need d_firstname if user wants to enter new value. Moreover, If I type over the input field in the secondCtrl, I can save the record because of d_firstname but if I keep not modifying anything in that input field, returns empty. hope you get the problem. Please someone help on this.. I wanted to pass data from one form to other if checkbox clicked for billing details and shopping details are same
FirstController input:
<input type="text" name="firstname" ng-model="firstname" required>
SecondCtrl input:
<input name="firstname" ng-value="firstname" ng-model="d_firstname">
There is no point in using ng-value and ng-model together.
You could use ng-change event to update the second one
<input name="firstname" ng-model="firstname" ng-change="updateName()" required>
<input name="d_firstname" ng-model="d_firstname">
Controller:
$scope.updateName = function(){
$scope.d_firstname = $scope.firstname
}
Note that you should always use an object in ng-model. You will run into problems with child scopes if you don't

Angular JS get value of date input with ng-model

I try to get the value of my input date html 5 component by binding it with ng-model like this:
<input type="date" id="dateFin" class="form-control" name="dateFin" ng-model="filtres.dateFin"
placeholder="dd/MM/yyyy" min="01/01/2014"/>
And with the model :
$scope.filtres.dateFin = null;
I think the binding is correct because when I change the initial value to
$scope.filtres.dateFin = new Date();
The initial value is set to current date.
But my problem occurs when i try to get the value on my form processing. When debugging I saw that the value of $scope.filtres.dateFin become undefined when the value is changed. Should I override an onchange method or getting the value by another way?
https://jsfiddle.net/u2vkzemh/
html
<div ng-app ng-controller="testCtrl">
<input type="date" id="dateFin" name="dateFin" ng-model="filtres.dateFin"/>
{{filtres.dateFin}}
<button type="button" ng-click="show()">Show it</button>
{{testDate}}
</div>
controller
function testCtrl($scope) {
$scope.show=function(){
$scope.testDate = $scope.filtres.dateFin;
}
}
It seems to work well.
Ok, so, a little thanks your example I managed to find the issue. In fact I had a min-value and a format like placeholder="dd/MM/yyyy" min="01/01/2014" and this was preventing my code which was similar to yours to work.
I think the problem was the format of the min parameter with the good format everything is ok :
min="2014-01-01"
My bad for removing for my code example on the question, I was juste trying to make it more readable.

Angular : Put in ng-model a value set in scope

In the ng-model, i want to set a default value defined in my scope but the value is not recognized.
Here's my controller :
$scope.defaultRole = "Admin";
My view :
<input type="text"
class="form-control" ng-model="user.role='{{defaultRole}}'">
but i have {{defaultRole}} instead of Admin in my input text. Maybe it's a problem of formating but i dont know how to make it work.
Note : i can put ng-model="user.role='Admin'" directly, but i want it from the scope.
Thank you for your help !
You don't understand how ngModel works. ngModel expects an assignable angular expression. The expression is bound two way. That means that
to populate the input field, angular evaluates the expression
when the value entered in the input field changes, the variable that the ngModel expression refers to is set to the entered value
So, all you need is
<input type="text" class="form-control" ng-model="defaultRole">
That will read the defaultRole variable and populate the field with its value, and vice versa.
If you want, instead, to populate user.role with the entered value, and the field to have the defaultRole value by default, then it should be
<input type="text" class="form-control" ng-model="user.role">
and the controller should do
$scope.user.role = $scope.defaultRole;
or, if user doesn't exist yet
$scope.user = {
role: $scope.defaultRole
};
to initialize user.role to its default value.
You can do that by using ng-init. ng-model isn't suppose to deal with affectation. This will be done directly by angular.
<input type="text" class="form-control" ng-model="user.role" ng-init="user.role = defaultRole">
Working Fiddle

how to get ng-model value of text box in controller

<input type='text' ng-model='courseIDER' ng-change="india()" class="form-control" placeholder="Enter CourseId">`{{courseIDER}}`<br>
suppose there is a text box where one can input value and i will be getting what one enters by {{courseIDER}}. But my problem is i want this value in controller.
As an angularjs newbie i'm hoping anyone helps.
Thanks in advance
Define courseIDER as a $scope obj in your controller
function controller($scope, ... other injections) {
$scope.courseIDER;
}
now, when the input changes, so will $scope.courseIDER.
you can now use the courseIDER in any function / object/ array you want

Interpolating nested values from a scope variable in a view

So I have the following view:
<p type="text" disabled='true' class="form-control" >
{{selected.timerange}}
</p>
The value of $scope.selected.timerange is:
{"available":false,"schedule_start_at":"2015-03-13T00:30:00","schedule_end_at":"2015-03-13T01:00:00"}
This works fine, but when I use the following view:
<p type="text" disabled='true' class="form-control">
{{selected.timerange.schedule_start_at}}
</p>
the interpolation does not happen.
I'm unable to figure out why. Any help please?
Your example works if you correctly set up angular. See fiddle
Make sure that :
The controller that is responsible for the second view is the same instance that the one responsible for the first view. If you instantiated the controller with the ngController directive, the instantiation should be on a common parent for both views.
By the way, please note that boostrap form-control class is usually for input elements, not for paragraphs.
Consider replacing :
<p type="text" disabled='true' class="form-control" >
{{selected.timerange}}
</p>
with :
<input type="text" disabled='true' class="form-control" value="{{selected.timerange}}"/>
Late to the party here but in case anyone else runs into this issue:
Try initializing your timerange variable in the constructor.
this.selected.timerange = {} if that doesn't work go one step deeper
this.selected.timerange.schedule_start_at = "" (keeping the init from above)
Not sure the philosophy behind this, but I guess it has something to do with observables and/or promises if thats how you're getting your variables ( that was the issue in my case at least )

Resources