Difference between ng-model and angular expression - {{}} - javascript

{{}} is working fine but ng-model is not, at the same place.
I am using the following html-
<body ng-app="crud">
Gray input fields will not be visible.
<div ng-controller="ctrl">
<input type="text" value="sdf" ng-model="asdf"/>
<h1 ng-model="asdf"></h1> <!-- this doesn't work-->
<h1>{{asdf}}</h1> <!-- this work-->
</div>
</div>
</body>
asdf is defined in this js app like this
var app = angular.module("crud", []);
app.controller("ctrl", ['$scope', function($scope) {
$scope.asdf="ankur";
}]);
Can someone explain why is it so ?

The ng-model directive is to be used on the input fields such as input, select for two way data binding and to get an input from a user.
Where as the one way data binding expression {{}} or ng-bind directive is used to output the data in the view.
var app = angular.module("crud", []);
app.controller("ctrl", ['$scope', function($scope) {
$scope.asdf="ankur";
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="crud">
Gray input fields will not be visible.
<div ng-controller="ctrl">
<input type="text" value="sdf" ng-model="asdf"/>
<h1 ng-bind="asdf"></h1>
<h1>{{asdf}}</h1>
</div>
</div>

Use ng-bind for display purposes, instead of ng-model.
<h1 ng-bind="asdf"></h1>
You only want to use ng-model when binding to an element that will be editing the variable, such as a text field.

From documentation:
The ngModel directive binds an input, select, textarea (or custom form control) to a property on the scope using NgModelController, which is created and exposed by this directive.
You are trying to use it on a <h1>. Use ng-bind instead.

According the doc
the ngModel directive binds an input,select, textarea (or custom form control) to a property on the scope using NgModelController, which is created and exposed by this directive.
so you will not use it for display an H1
For the brackets they will be dirty checked and refreshed in every $digest, even if it's not necessary. So it's slower. Plus thez may appear while your angularjs is bootstrapping

ng-model : This directive binds the values of AngularJS application data to HTML input controls.
{{}} This use For Printing purpose only. you can put expression also like {{2*2}} it prints 4
Refer This for study basic syntax https://angularjs.org/

Related

Accessing ngModel elements that use a class

I have many elements in my HTML code that have their ngModel assignment defined as ng-model = "object.[something]".
For example:
<div class="form-group row" ng-model="object.askUser">
I do this to be clear of my purpose for these elements. My question is how do I access these element in my Javascript? Do I call $scope.object.askUser, $object.askUser, or something else? I had a hard time finding things on the web about this, most likely because I wasn't quite sure of the words to use in the search bar to describe what I am trying to do.
Inside your controller use $scope.object.askUser:
var app = angular.module('TestApp', []);
app.controller("testCtrl", function ($scope) {
$scope.someObject = {};
$scope.someObject.askUser = "Hello, world!";
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="TestApp">
<div ng-controller="testCtrl">
<input ng-model="someObject.askUser" />
</div>
</div>
Side note:
You use in your example <div> with ngModel.
ngModel Docs:
The ngModel directive binds an input,select, textarea (or custom form
control) to a property on the scope
If you want to one-way bind a model to a div use Angular Expression:
<div class="form-group row">
{{ object.askUser }}
</div>

Disabling submit button based on fields added with ng-bind-html

JSFiddle here: http://jsfiddle.net/c6tzj6Lf/4/
I am dynamically creating forms and buttons and want to disable the buttons if the required form inputs are not completed.
HTML:
<div ng-app="choicesApp">
<ng-form name="choicesForm" ng-controller="ChoicesCtrl">
<div ng-bind-html="trustCustom()"></div>
<button ng-repeat="button in buttons" ng-disabled="choicesForm.$invalid">
{{button.text}}
</button>
</ng-form>
</div>
JavaScript:
angular.module('choicesApp', ['ngSanitize'])
.controller('ChoicesCtrl', ['$scope', '$sce', function($scope, $sce) {
$scope.custom = "Required Input: <input required type='text'>";
$scope.trustCustom = function() {
return $sce.trustAsHtml($scope.custom);
};
$scope.buttons = [
{text:'Submit 1'},
{text:'Submit 2'}];
}]);
choicesForm.$invalid is false and does not change when entering text into the input field.
Solution:
I ended up using the angular-bind-html-compile directive from here: https://github.com/incuna/angular-bind-html-compile
Here is the relevant bit of working code:
<ng-form name="choicesForm">
<div ng-if="choices" bind-html-compile="choices"></div>
<button ng-click="submitForm()" ng-disabled="choicesForm.$invalid">
Submit
</button>
</ng-form>
And choices might be a snippit of HTML like this:
<div><strong>What is your sex?</strong></div>
<div>
<input type="radio" name="gender" ng-model="gender" value="female" required>
<label for="female"> Female</label><br>
<input type="radio" name="gender" ng-model="gender" value="male" required>
<label for="male"> Male</label>
</div>
The main problem is that ngBindHtml doesn't compile the html - it inserts the html as it is. You can even inspect the dynamic input and see that it doesn't have the ngModel's CSS classes (ng-pristine, ng-untouched, etc) which is a major red flag.
In your case, the form simply doesn't know that you've added another input or anything has changed for that matter. Its state ($pristine, $valid, etc) isn't determined by its HTML but by the registered NgModelControllers. These controllers are added automatically when an ngModel is linked.
For example this <input required type='text'> won't affect the form's validity, even if it's required, since it doesn't have ngModel assigned to it.
But this <div ng-model="myDiv" required></div> will affect it since it's required and has ngModel assigned to it.
The ngDisabled directive on your buttons works as expected since it depends on the form's $invalid property.
See this fiddle which showcases how ngModel registers its controller. Note that the html containing the dynamic input gets compiled after 750ms just to show how NgModelControllers can be added after FormController has been instantiated.
There are a few solutions in your case:
use a custom directive to bind and compile html - like this one
use ngInclude which does compile the html
use $compile to compile the newly added HTML but this is a bit tricky as you won't know exactly when to perform this action
This is an answer yet imcomplete because i cannot do the code at the moment.
I think your html will be included, not compiled. So the inputs are not bind to angular and are not part of the angular form object.
The only way i see is to use a directive that will compile the passed html and add it to your form. This may be quite tricky though, if you want to go on this way i suggest to edit your question to ask for the said directive.
However i'm not really familiar with $compile so i don't know if it'll work to just add $compile around $sce.trustAsHtml()
You can write a method as ng-disabled does not work with booleans, it works with 'checked' string instead:
So on your controller place a method :
$scope.buttonDisabled = function(invalid){
return invalid ? "checked" : "";
};
And on your view use it on angular expression :
<button ng-repeat="button in buttons" ng-disabled="buttonDisabled(choicesForm.$invalid)">
Here is a working fiddle
Working DEMO
This is the solution you are looking for. You need a custom directive. In my example I have used a directive named compile-template and incorporated it in div element.
<div ng-bind-html="trustCustom()" compile-template></div>
Directive Code:
.directive('compileTemplate', function($compile, $parse){
return {
link: function(scope, element, attr){
var parsed = $parse(attr.ngBindHtml);
function getStringValue() { return (parsed(scope) || '').toString(); }
//Recompile if the template changes
scope.$watch(getStringValue, function() {
$compile(element, null, -9999)(scope); //The -9999 makes it skip directives so that we do not recompile ourselves
});
}
}
});
I found the directive in this fiddle.
I believe what is really happening though due to jsfiddle I'm unable to dissect the actual scopes being created here.
<div ng-app="choicesApp">
<ng-form name="choicesForm" ng-controller="ChoicesCtrl">
<div ng-bind-html="trustCustom()"></div>
<button ng-repeat="button in buttons" ng-disabled="choicesForm.$invalid">
{{button.text}}
</button>
</ng-form>
</div>
The first div is your top level scope, your form is the first child scope. Adding the div using a function creates the dynamically added input field as a child of the first child, a grandchild of the top level scope. Therefore your form is not aware of the elements you're adding dynamically causing only the static field to be required for valid form entry.
A better solution would be to use ng-inclue for additional form fields or if your form isn't to large then simply put them on the page or template you're using.

How to include a filter in a custom directive

I'm new to Angular JS and am having trouble with custom directives. I've tried to copy a tutorial and I can't get it working using my own code.
Here's the relevant part of my HTML:
<div ng-controller="calcController" class="container">
<div class="form-group">
<label for="balInput">Balance:</label>
<input id="balInput" type="text" class="form-control" ng-model="balance" ng-change="updateAnnualInt(balance)" placeholder="Please enter your balance here...">
</div>
<p>{{'At a '+(interestRate)+'% interest rate you would save...'}}</p>
<p style="text-indent: 30px;" ng-repeat="interest in interests">{{'per '+interest.time+': '}}{{(interest.factor*annualInterest*0.01) | currency:'£'}}</p>
To start with, I'm just trying to turn the last paragraph into a custom directive. Here's my attempt:
app.directive('interest-amount',function(){
var directive={};
directive.restrict='E';
directive.template="<p style='text-indent: 30px;'>'per '+{{interest.time}}+': '{{(interest.factor*annualInterest*0.01) | currency:'£'}}</p>";
directive.compile=function(element,attributes){
var linkFunction=function($scope, element,attributes){
element.html("<p style='text-indent: 30px;'>per "+$scope.interest.time+": "+($scope.interest.factor*$scope.annualInterest*0.01)+"</p>");
}
return linkFunction;
}
return directive;
})
This isn't giving the HTML template I expect when I insert it as follows:
<interest-amount ng-repeat="interest in interests"></interest-amount>
My first question is why is this not working?
I am also confused as to how to include the currency filter in the linkFunction. What is the syntax for encoding this in Javascript rather than Angular-powered HTML?
Thanks
app.directive('interestAmount',function($filter){ // camel case, as #isha aggarwal noted
$filter('filterName')('argument');
});
Answer to your first question, the directive should be declared in camel case. So, declare the directive like this :
app.directive('interestAmount',function(){
And call it the way you are doing currently.
<interest-amount ng-repeat="interest in interests"></interest-amount>
This should take you inside the directive code.
For your second question, you should use a directive controller. Just create a controller for this directive, inject $filter in that controller and call function of that controller from link function of your directive.
Refer this : AngularJs - Use custom filter inside directive controller

Data binding not working in AngularJS with input tag

Below is my angularjs code,
When I try to enter any text in the textbox, it doesn't appear in the binding.
<!DOCTYPE html>
<html lang="en">
<head>
<script src="js/angular.js"></script>
<script type="text/javascript">
var app = angular.module('myApp', []);
app.controller('cont', ['$scope', function($scope) {
}]);
</script>
</head>
<body ng-app="myApp">
<input type="text" ng-bind="user"></input>
<p>{{user}}</p>
</body>
</html>
You would need to use ng-model directive for 2-way binding. ng-bind is just one-way which updates the bound element with data (model value) when a digest cycle happens. Without ng-model when you update the textbox there wont be any digest cycle. Angular has directive definition for types like input and other form controls which requires optional ng-model directive. And these element directives registers events like change/input etc only if it gets the optional ng-model controller on the target element. And when you have them it uses ng-model controller to set the view-value, model-value and triggers the digest cycle when that event occurs. Of course with the new angular versions there is an ng-model-options which you can set at the element level or at a global level to specify when do you want the model value update (and form validation) to happen.
So do:-
<input type="text" ng-model="user" name="user"></input>
<p>{{user}}</p>
Though not an issue in your case, you are missing the usage of ng-controller="cont". Without it all properties will be attached to the rootScope in your case. So may be:
<body ng-app="myApp">
<div ng-controller="cont">
<input type="text" ng-model="user" name="user"></input>
<p>{{user}}</p>
</div>
</body>

Binding Controller Property containing HTML in AngularJS

First of all: I am absolutely new to AngularJS but worked on MVC-projects in other languages.
I try to bind a Property containing HTML.
This is the code:
HTML:
<div ng-controller="MyController">
<p>{{About}}</p>
</div>
JS:
.controller('MyController', ['$scope', function($scope) {
$scope.About="This is me<br/>and not you!"
}
Now the HTML is encoded which I do not want (the <br/> should result in line breaks)
I already tried <p ng-bind-html="About"></p> but that resulted in no output at all
You need to allow html in your text which Angular does not by default.
Plunker: http://plnkr.co/edit/K4KRCQi4Rpe99MJel5J2?p=preview
Angular Docs for $sce
Strict Contextual Escaping (SCE) is a mode in which AngularJS requires
bindings in certain contexts to result in a value that is marked as
safe to use for that context. One example of such a context is binding
arbitrary html controlled by the user via ng-bind-html. We refer to
these contexts as privileged or SCE contexts.
<div ng-controller="htmlChar" ng-bind-html="about"></div>
<script>
angular.module("app",[])
.controller("htmlChar",function($scope, $sce){
$scope.about= $sce.trustAsHtml("This is me<br/>and not you!");
});
angular.bootstrap(document,["app"]);
</script>
You shoudln't need to insert html through model binding in AngularJS since the philosophy of the framework is to keep the HTML (page's structure and style) intact and only bind the data to be shown inside that HTML.
If you really need to bind HTML tags into your data you need to use the $sanitize service.
You have to use angular compile functionality here, go through the link to get more information angular compile

Categories

Resources