Why is ng-bind and {{}} giving different outputs for a json? - javascript

Here is the code that I am using, don't understand why is there a difference in the output of ng-bind and {{}}.
angular.module('Test', []);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="Test">
<input type="text" ng-model="foo.bar" />
<input type="text" ng-model="foo.baz" />
<p ng-bind="foo"></p>
<p>{{ foo }}</p>
</div>
This is the output that I am getting
//for ng-bind
[object Object]
//for {{}}
{"foo":"ankur","bar":"23"}

The reason is that the {{}} is evaluating the expression before to bind it to the view, while ng-bind is not doing that, so you are having a string rapresentation of your array object.

Related

Input validations on table ng-repeat

I am making app using angularJs app and I have one table in which I am using ng-repeat with texbox in td now I want to validate texbox so I used ng-form
and ng-class but I am getting invalid expression error
my code is
<input name ="abc-pqr-{{item.id}}"
ng-model="something"
ng-class="{'has-error':formName.abc-pqr-{{item.id}}.$dirty}">
but not worked then I have tried this
<input name ="abc-pqr-{{item.id}}"
ng-model="something"
ng-class="{'has-error':formName[abc-pqr-{{item.id}}].$dirty}">
that also not worked
so can someone suggest me right way to archive this
thanks in advance
The syntax is wrong, you should use ng-class="{...}" not ng-class=:{...}
You must quote the input name, i.e ng-class="{'has-error':formName['abc-pqr-{{item.id}}'].$dirty}" you are actually referring to a (none existing) variable called abc-pqr-xx
When you refer to $dirty the input must have a ng-model
The correct markup could look like this :
<input name="abc-pqr-{{item.id}}"
ng-model="item.value"
ng-class="{'has-error':formName['abc-pqr-{{item.id}}'].$dirty}">
it just misses the quotes: ng-class="{'has-error':formName['abc-pqr-{{item.id}}'].$dirty}"
angular.module('myApp', [])
.controller('myCtrl', function() {
this.items = [{id:1}, {id:2}, {id:3}];
});
.has-error {
border-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.7/angular.min.js"></script>
<div ng-app="myApp">
<div ng-controller="myCtrl as vm">
<form name="formName">
<input ng-repeat="item in vm.items"
name="abc-pqr-{{item.id}}"
ng-model="tem.value"
ng-class="{ 'has-error': formName['abc-pqr-{{item.id}}'].$dirty}"/>
</form>
</div>

AngularJS : ng-model binding in ng-repeat

I'm looping through a series of data and want to dynamically bind a model.
My problem is that when looping through elements, it seems as if Angular creates a new scope for each iteration, so the models are not the same in the three iterations.
I've made a simplified example of my code that does not work;
http://jsfiddle.net/Fizk/uurL65e5/
<div ng-app="">
<p ng-repeat="key in [1,2,3]">
<input type="text" ng-model="contact.name" />
{{contact}}
</p>
</div>
As opposed to the non-dynamic way that works:
http://jsfiddle.net/Fizk/d0smns1v/
<div ng-app="">
<p>
<input type="text" ng-model="contact.name" />
{{contact}}
</p>
<p>
<input type="text" ng-model="contact.name" />
{{contact}}
</p>
<p>
<input type="text" ng-model="contact.name" />
{{contact}}
</p>
</div>
The real code is a bit more complicated, and I cannot just hardcode the number of fields, since it's dynamically fetched from an api.
I've looked through tons of questions regarding dynamic model binding and looked through the documentation, but with no luck.
Can anyone shed some light on how I can make all three fields use the same model, so they'll update nicely?
Angular 1.3 added a controllerAs option which should solve all your issues when dealing with child scopes and scope inheritance.
This is considered best practice today. I've created a plunker for you.
<div ng-app="myApp" ng-controller="myCtrl as vm">
<p ng-repeat="key in [1,2,3]">
<input type="text" ng-model="vm.contact.name" />
{{contact}}
</p>
</div>
<script>
angular.module("myApp", []).controller("myCtrl", function() {
var vm = this;
// use vm.value instead of $scope.value
});
</script>
I highly recommend reading this article: Understanding Scopes.
And to understand the new controllerAs syntax you should check out: Exploring Angular 1.3: Binding to Directive Controllers.
If you assign contact to be an object in the parent scope before creating the child scope (I'm using ng-init to do this but it would make more sense in a controller), it will work as the child scopes will inherit the reference to the same object.
http://jsfiddle.net/uurL65e5/1/
<div ng-app="" ng-init="contact = {}">
<p ng-repeat="key in [1,2,3]">
<input type="text" ng-model="contact.name" />
{{contact}}
</p>
</div>
you need to define your model before, usually you define your model in your controller but for instance this works :
<div ng-app="">
<input type="text" ng-model="contact.name" />
<p ng-repeat="key in [1,2,3]">
<input type="text" ng-model="contact.name" />
{{contact}}
</p>
</div>
Just use $parent
<div ng-app="">
<p ng-repeat="key in [1,2,3]">
<input type="text" ng-model="$parent.contact.name" />
{{contact}}
</p>
</div>
Fiddle - http://jsfiddle.net/ujmd0pc9/

AngularJs Error: [ngModel:nonassign]

I have started to learn AngularJS and this is what amazes me, at the beginning even a four lines of code does not work properly and I have no clue
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<div data-ng-app="">
<input type="text" ng-model="name='Rocky'">
Your name is {{name}}
</div>
On typing something in the textbox, my expression does not change.
It shows the below error in the console.
TypeError: r is not a function
You can't initialize to Rocky inside ng-model. Try this:
<div data-ng-app="">
<input type="text" ng-model="name" ng-init="name='Rocky'">
Your name is {{name}}
</div>
Docs
This error occurs when expression the ngModel directive is bound to is a non-assignable expression.
You need to initialize using ngInit directive. You cannot initialize using ngModel
The ngInit directive allows you to evaluate an expression in the current scope.
<input type="text" ng-init="name='Abhinav'" ng-model="name" />
DEMO
Using ng-value instead of ng-model worked for me.

ng-if and scope variable control interaction [duplicate]

In the code below the 2nd checkbox does not work when the 1st checkbox is clicked.
http://plnkr.co/edit/JF0IftvWx7Ew3N43Csji?p=preview
HTML:
<html ng-app="App">
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular-animate.min.js"></script>
<link rel="stylesheet" type="text/css" href="animations.css" />
<script type="text/javascript" src="script.js"></script>
</head>
<body>
Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /><br/>
Show when checked:
<span ng-if="checked==true" class="animate-if">
<input type="checkbox" ng-model="checked1" ng-init="checked1=true" />
</span>
<br>
<span ng-if="checked1==true" class="animate-if">
test <input type="checkbox" ng-model="checked2" ng-init="checked2=true" />
</span>
</body>
</html>
As noted ng-if creates it's own scope.
You're setting checked1 inside what I'm calling "Inner Scope 1". Then using it in "Outer Scope". "Outer Scope" can't see into "Inner Scope 1" so javascript creates a new variable checked1 on "Outer Scope". Now you have two entirely different variables both calledchecked1- one on "Outer Scope" and one on "Inner Scope1". This is not what you want.
To fix this you need to set checked1 on the same scope as you'll use it- "Outer Scope". "Outer Scope" is the parent of "Inner Scope1" so we can use $parent.checked1 like so:
<input type="checkbox" ng-model="$parent.checked1" ng-init="checked1=true" />
Now there's only one copy of checked1- the one on "Outer Scope". And it works, check it out on this updated plunker: http://plnkr.co/edit/XaPWYvYLrFRZdN2OYn6x?p=preview
ngIf creates a different scope. Use $parent:
<span ng-if="checked==true" class="animate-if">
<input type="checkbox" ng-model="$parent.checked1"
ng-init="$parent.checked1=true" />
</span>
<br>
<span ng-if="checked1==true" class="animate-if">
test <input type="checkbox" ng-model="$parent.checked2"
ng-init="$parent.checked2=true" />
</span>
Plunk
You can use ngShow instead of ngIf. ngShow helps because it doesn't create child scope. See result here.
The issue comes from the fact that you are using primitive type (boolean) for your data model. Generally it is admit that you should not use primitive types for two way data binding. If you want to know why I encourage you to read this article important part being :
This means that, if a property changes within a local scope, the original/parent version of the property isn’t updated with those changes.
In your case what is happening is :
- You are using primitive type boolean
- ngIf creates/destroy its scope while inheriting from its parent scope
- Every change made within the ngIf local scope is never propagated to the parent.
- Hence no update on the nested if.
To fix the issue please use a JS object to hold your check boxes values as follows :
<body>
Click me:
<input type="checkbox" ng-model="checkboxes.first" ng-init="checkboxes = {first : true, second:true, third:true}" />
<br/>Show when checked:
<span ng-if="checkboxes.first==true" class="animate-if">
<input type="checkbox" ng-model="checkboxes.second" />
</span>
<br>
<span ng-if="checkboxes.second==true" class="animate-if">
test <input type="checkbox" ng-model="checkboxes.third"/>
</span>
</body>
Note that the check boxes are now bound to boolean values inside a js object.
Modifyied working Plunker over here
I think the issue has to do with the fact that you are not nesting the ng-if. The two span tags are siblings.
So, my theory is that when the compile phase occurs, the ng-if that the Third depends on cannot be executed. So, it cannot build up the entire Third part of the template.
This plunker is working (with nested elements).
<div>First <input type="checkbox" ng-model="first" ng-init="first = true"/></div>
<div ng-if="first">
Second <input type="checkbox" ng-model="second" ng-init="second = true"/>
<div ng-if="second">
Third <input type="checkbox" ng-model="third" ng-init="third = true"/>
</div>
</div>
If I change my plunker to this, it is not working (with siblings):
<div>First <input type="checkbox" ng-model="first" ng-init="first = true"/></div>
<div ng-if="first">
Second <input type="checkbox" ng-model="second" ng-init="second = true"/>
</div>
<div ng-if="second">
Third <input type="checkbox" ng-model="third" ng-init="third = true"/>
</div>

The submit button not working AngularJS

So basically wwhat I'm trying to do is take input of two numbers n1 and n2 and then print their sum all using angular. I have used bootstrap for styling. But i noticed nothing was happening so to check i added alert() function in the function to be called but still it's not getting accessed somehow. I dont know jQuery.
PS: when I use text1+text2 it's concatinating the string instead of printing the sum
This is my html:
<!DOCTYPE html>
<html ng-app="store">
<head >
<title>Trying Angular</title>
<link rel="stylesheet" type="text/css" href="bootstrap/dist/css/bootstrap-theme.css">
<link rel="stylesheet" type="text/css" href="bootstrap/dist/css/bootstrap.min.css">
</head>
<body>
<form class="form-inline" style="border: 2px solid blue; max-width:500px;" ng-controller="formCtrl as formCtrl" ng-submit="formCtrl.submit()">
<div class="form-group">
<label>Enter n1</label>
<input type="text" class="form-control" placeholder="enter the first number" ng-model="text1">
<p>{{ text1}}</p>
</div>
<div class="form-group">
<label>Enter n2</label>
<input type="text" class="form-control" placeholder="enter the second number" ng-model="text2">
<p >{{text2}}</p>
</div>
<div class="form-group" style="display:block; margin:10px auto; margin-left:370px;">
<input type="submit" class="form-control" >
</div>
<p> Your SUM of two numbers is ={{text1+text2}}</p>
</form>
<script src="angular.min.js"></script>
<script src="exp1.js"></script>
<script src="jquery.min.js"></script>
<script src="bootstrap/dist/js/bootstrap.min.js"></script>
</body>
</html>
This is my angular code:
(function(){
var app=angular.module('store',[]);
var n1=0;
var n2=0;
app.controller('formCtrl',function(){
this.submit=function(){alert("successful");}; // <----- alert()
});
})();
As explained in the documentation for the ngController directive, there are two ways to access the members of a controller:
Use the as <scopeProperty> syntax, and access it using the <scopeProperty> name:
<form class="form-inline" style="border: 2px solid blue; max-width:500px;" ng-
controller="formCtrl as fc" ng-submit="fc.submit()">
Here, fc is being declared as the name for the controller instance, and its properties are accessed with fc.
Example
Inject $scope into the controller and add properties to that:
app.controller('formCtrl', ['$scope', function($scope){
$scope.submit = function(){alert("successful");};
}]);
<form class="form-inline" style="border: 2px solid blue; max-width:500px;" ng-
controller="formCtrl" ng-submit="submit()">
Here, the controller's properties are added to the $scope and this allows us to access them directly in the HTML without using the dot notation.
Example
The page linked to above compares and contrasts the two approaches. You were not exactly using either, and that's why you were having trouble.
It would be better to add your submit code inside a function:
app.controller('formCtrl',[$scope, function('$scope'){
$scope.submit = function() {
alert('submit');
};
}]);
then in your ng-submit directive use submit() as per documentation you can also use ng-change and ng-click directives to update the models then do whatever with the models.
Further to the comments about accessing the data from the inputs:
When you add the ng-model attribute to an input you are saying I would like data from this input to be stored in ng-models name. Adding this to an input: ng-model="inputvalue.input1" would enable you to store data kind of like the following:
inputvalue = {
input1 : "Input value would go here"
}
note the names are the same for a reason.
You can then set up those objects to be stored/accessed inside the controller using $scope look at the docs on AngularJS website - take your time and get to know what's going on.

Categories