Why are my angular curly braces not working? - angularjs

My curly braces are showing up as curly braces, I don't get what's wrong, I did everything...when I use the controller to manipulate the input box, it works. But when I sumbit text into the input box on my browser, it doesn't do anything..
This is where I create my module:
'use strict';
var foodApp=angular.module('foodApp', []);
This is my html:
<script src="/lib/angular/angular.js"></script>
<!DOCTYPE html>
<html lang="en-us" >
<head>
<meta charset="utf-8">
<title>Food App</title>
</head>
<body>
<div ng-controller="foodController" ng-app="foodApp">
<input type="text" ng-model="foods"/>
<input type="submit" value="Healthy Lunch?" />
<br />
<br />
<h4>{{outcome}}</h4>
{{foods}}
</div>
<script src="/js/food.js"></script>
<script src="/js/controllers/foodController.js"></script>
</body>
</html>
This is my controller page:
foodApp.controller('foodController', function($scope)
{
var foods = $scope.foods;
$scope.outcome=foods;
var foodsArray=foods.split(',');
if(foodsArray.length<=4)
$scope.outcome="Bon Appetit!";
else if(foodsArray.length<=7)
$scope.outcome="Pig!";
else
$scope.outcome="One at a time, your scale is going to shout!!";
});

The problem is in fact in your controller. The code you have in your controller is only executed once, when the controller is constructed. As such the variable foods is undefined (since $scope.foods is also undefined). A couple of lines later, you try to run foods.split(..) but since it's undefined, it throws an exception and the application fails. This is shown as an error in the developer console of your browser.
To fix it you need to completely refactor your controller code.
foodApp.controller('foodController', function($scope)
{
$scope.handleFoodChange = function() {
$scope.outcome = $scope.foods;
if($scope.foods){
var foodsArray = $scope.foods.split(',');
if(foodsArray.length<=4)
$scope.outcome = "Bon Appetit!";
else if(foodsArray.length<=7)
$scope.outcome = "Pig!";
else
$scope.outcome = "One at a time, your scale is going to shout!!";
}
}
});
and in your view you should change your input to this:
<input type="text" ng-model="foods" ng-change="handleFoodChange()" />
That should make your application work as expected. Now, whenever you make a change in the input field, the function handleFoodChange is called, and it handles the logic that sets a value for the $scope.outcome variable.
Here's a Plunker showing it working

Related

this vs $scope in AngularJS, 'this' showing peculiar behavior with ng-if

I have following controller and view in AngularJS and I'm trying to learnt the difference between this and $scope.
//index.js
angular.module('angularApp', [])
.controller('indexCtrl', ($scope)=>{
// Initialize variables
$scope.name1 = '';
this.name2 = '';
$scope.greeting1 = `Hello ${$scope.name1}`;
this.greeting2 = `Hi ${this.name2}`;
})
//index.html
<!doctype html>
<html ng-app="angularApp">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
<script src="index.js"></script>
</head>
<body>
<div ng-controller="indexCtrl as app">
<input
type="text"
ng-model="name1"
placeholder="Using $scope variable name"
/>
<br />
<input
type="text"
ng-model="app.name2"
placeholder="Using this variable name"
/>
<br /><br />
<h2 ng-if="name1 != ''"> Hello {{name1}} </h2>
<br />
<h2 ng-if="app.name2 != ''"> Hi {{app.name2}} </h2>
</div>
</body>
</html>
Ideally, when I first run the localhost, it should not show the 'Hello' or the 'Hi' text because of ng-if. While 'Hello' is not displayed, 'Hi' gets displayed. Why is this happening?
$scope
The scope is the binding part between the HTML (view) and the JavaScript (controller).
The scope is an object with the available properties and methods. It is used to get all the controls on the controller.js files.
The scope is available for both the view and the controller.
this
When the controller constructor function is called, this is the controller.
Within functions defined on $scope, this is set to the $scope in effect where/when the function was called".
<!doctype html>
<html ng-app="angularApp">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
<script src="index.js"></script>
</head>
<body>
<div ng-controller="indexCtrl as app">
<input
type="text"
ng-model="name1"
placeholder="Using $scope variable name"
/>
<br />
<input
type="text"
ng-model="app.name2"
placeholder="Using this variable name"
/>
<br /><br />
<h2 ng-if="name1 != ''"> Hello {{name1}} </h2>
<br />
<h2 ng-if="app.name2 != ''"> Hi {{app.name2}} </h2>
</div>
</body>
</html>
<script>
angular.module('angularApp', [])
.controller('indexCtrl', ($scope)=>{
// Initialize variables
$scope.name1 = '';
this.name2 = '';
$scope.greeting1 = `Hello ${$scope.name1}`;
this.greeting2 = `Hi ${this.name2}`;
})
</script>
In the controller, you are setting this.name2=''; In this case, this is not on $scope. So app.name2 != '', it equals undefined. It's generally considered better not to use $scope directly, but rather to use the ControllerAs syntax (see this explanation).
$scope is just a JavaScript object like any other, but it is the implicit scope of anything referred to in the template. Therefore if you have something like ng-if="name2 == ''", name2 refers to a field on $scope.
When you use ControllerAs, it creates an object on $scope by that name ($scope.app in your case). $scope.app corresponds to the controller's this. It's exactly the same as if you put $scope.app = this; in the controller's JavaScript. So then, in the controller, you could set this.name2='Harry' and in the HTML, have:
<span> Hi {{app.name2}} </span>
And you would see Hi Harry.
However, you should not use an arrow function to define your controller, since arrow functions do not have their own this scope, but inherit it from their parent. When you define functions on the controller, use this.myFunc = () => {...} and access it in the HTML with app.myFunc, but when defining the controller itself, use the normal function syntax.
To make things simpler, rather than using app in the HTML and this in the controller, it is a good idea to use the same name, by assigning this to a variable. Commonly people use vm (for View Model). So you would have ControllerAs='vm' and then in the JavaScript, set let vm = this; at the top of your controller code.
Then you can refer to vm.name2 (for example) in both your HTML and your JavaScript.

Why is safari not rendering my AngularJS bindings properly?

I've encountered an angular issue that only seems to occur in Safari:
TL;DR - Here is an obvious example of what I describe below (obviously this will only be demonstrated if you run the plunk in safari)
https://plnkr.co/edit/t6Ts2DlhV84C7CLFzdui?p=preview
<html>
<head>
<script src="https://code.angularjs.org/1.6.6/angular.js"></script>
<script>
var app = angular.module('safariBug', []);
app.controller('main', function($scope) {
$scope.mytext = "Here is a bunch of text, some of which will continue to be displayed.";
$scope.update = function() {
$scope.mytext = "New line of text.";
}
});
</script>
</head>
<body ng-app='safariBug'>
<div ng-controller='main'>
<div style='height:300px;width:300px;font-size:48px'>{{mytext}}</div>
<input type='button' ng-click='update()' value='Update Text' />
</div>
</body>
</html>
When displaying a string in a view using a data-bound variable, replace the string with a new value it gets displayed immediately, but if the old value is longer it doesn't get erased. For instance if the string is "An original sentence", and its replaced with "New text", it will end up displaying something such as "New textinal sentence". As soon as the the style of the html element is modified, it seems to force Safari to re-render the element correctly with the old text removed.
<div style='height:300px;width:300px;font-size:48px' ng-bind="mytext"</div>
Try this way.

Access form inside controller

Here is my full code:
<html ng-app="myApp">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js"></script>
</head>
<body >
<div ng-controller="myController">
<form name="myForm">
<input ng-model="option" name="test">
{{myForm.$dirty}}
<button>Save</button>
</form>
</div>
<script>
angular.module('myApp',[]).controller('myController',function($scope){
$scope.option=2;
console.log($scope.myForm);
});
</script>
</body>
</html>
While {{myForm.$dirty}} works, console.log($scope.myForm) returns undefined!!! At the same time if I console.log($scope) I can see myForm as one of its properties!!!! As not to go mad, could someone explain this paradox?
I don't like this solution, but it works. Put a $timeout around the code that you would like to access the form. The $timeout kind of forces the code to wait until the form is fully rendered. (Don't forget to inject $timeout.)
angular.module('myApp',[]).controller('myController',function($scope, $timeout){
$scope.option=2;
$timeout(function() {
console.log($scope.myForm);
}); //Note that you don't need it to actually wait for any amount of time
The reason why you see the form if you console.log($scope) but not when you console.log($scope.myForm), is because the console will evaluate $scope when you expand it. By then, the form has rendered and attached to the scope.
Have you tried to put a watcher on the form ? I'm guessing that the form is simply not yet defined when the controller code is defined.
$scope.$watch('myForm', function(form) {
if(form) {
//check if form is defined
}
});

Angularjs controller nesting

I'm new to angular, I've tried some testing pattern and it's ok with the $scope variable but I can't make it work for a simple controller nesting. (and avoid using the $scope variable, instead I want to use "this")
Here is my sample HTML and javascript :
<!doctype html>
<html ng-app="appTest">
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
</head>
<body>
<div ng-controller="FirstController as first">
<div>
First is {{first.text}}
</div>
<div ng-controller="SecondController as second">
Second is {{second.text}}
</div>
</div>
<script>
var app = angular.module("appTest",[]);
function printFirst() {
this.text = "first"
}
function printSecond() {
this.text = "second";
}
app.controller("FirstController",[printFirst]);
app.controller("SecondController",[printSecond]);
</script>
</body>
</html>
In the output html the angular variables inside curly brackets are not replaced and I don't know what's going on. I've tried to install Angular Batarang for debugging but the scope console is empty.
Obviously it's a silly mistake but I don't see where I'm wrong
Ok, the answer has nothing to do with my code, I was just using a too old version of Angularjs (1.0.8).
I moved to the last version 1.3.4 and it works fine.
Access the variable using $scope.text please instead of this.text.

angular error in declaring multiple modules

I m new to Angular JS (apologies if my my terminology is incorrect or not enough explained).
I m trying to do a demo creating multiple modules which are just returning messages. My domo has just 2 files, I m copying complete code below.
JS:
var app = angular.module("app", ['controllers1', 'controllers2']);
angular.module('controllers1', []).controller('MainController', function($scope) {
$scope.message1 = "controllers1 message";
$scope.func1 = function () {
return "controllers1 func";
}
}
);
angular.module('controllers2', []).controller('MainController2', function ($scope) {
$scope.message2 = "controllers2 message";
$scope.func2 = function () {
return "controllers2 func";
}
}
);
HTML:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" ng-app="app">
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js"></script>
<script src="JS/Index.js"></script>
</head>
<body>
{{2+2}}
<div ng-controller="MainController1">
{{message1}}
{{func1()}}
<br /><br/>
<div ng-controller="MainController2">
{{
{{message2}}
{{func2()}}
}}
</div>
</div>
</body>
</html>
Issue:
If I create a just one module it works fine but if I create 2 modules it give weird error. Can you please guide me who to fix this error and create multiple modules and consume them.
Error: [$parse:syntax] http://errors.angularjs.org/undefined/$parse/syntax?p0=message2&p1=is%20unexpected%2C%20expecting%20%5B%3A%5D&p2=16&p3=%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%7Bmessage2&p4=message2
L/<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:6:446
Ya.prototype.throwError#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:152:392
Ya.prototype.consume#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:153:338
Ya.prototype.object#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:161:34
Ya.prototype.primary#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:152:26
Ya.prototype.unary#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:158:114
Ya.prototype.multiplicative#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:158:1
Ya.prototype.additive#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:157:365
Ya.prototype.relational#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:157:1
Ya.prototype.equality#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:157:1
Ya.prototype.logicalAND#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:156:1
Ya.prototype.logicalOR#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:156:346
Ya.prototype.ternary#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:156:1
Ya.prototype.assignment#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:155:1
Ya.prototype.expression#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:155:369
Ya.prototype.filterChain#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:155:1
Ya.prototype.statements#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:154:292
Ya.prototype.parse#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:151:19
td/this.$get</<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:89:450
f#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:72:89
t#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:56:1
oa#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:45:14
E#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:43:136
E#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:43:252
E#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:43:252
E#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:43:252
v#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:41:303
Wb/c/</<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:17:455
wd/this.$get</g.prototype.$eval#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:100:187
wd/this.$get</g.prototype.$apply#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:100:452
Wb/c/<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:17:413
d#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:30:321
Wb/c#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:17:321
Wb#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:18:23
Oc#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:17:96
#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:198:494
a#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:128:229
Uc/c/<#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:26:466
q#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:7:259
Uc/c#https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js:26:439
https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.min.js
Line 83
You seem to be declaring a MainController controller, but you reference MainController1 in the ng-controller directive.
Try this line instead:
angular.module('controllers1', []).controller('MainController1', function($scope) {
Also, I don't get what you are trying to do with these lines of code:
<div ng-controller="MainController2">
{{
{{message2}}
{{func2()}}
}}
</div>
Try removing those extra brackets as shown below:
<div ng-controller="MainController2">
{{message2}}
{{func2()}}
</div>
If you open the provided link (this one) it shows the following message:
Syntax Error: Token 'message2' is unexpected, expecting [:] at column
16 of the expression [
{{message2] starting at [message2].
So yes, the error is thrown because you are using an invalid expression in your HTML template.
please check this working CODE - PLUNKER LINK
problem you have is the curly brackets
{{ //remove this
{{message2}}
{{func2()}}
}} //remove this as well
also as danilo pointed out
angular.module('controllers1', [])
.controller('MainController1', function($scope) {

Resources