Angularjs: why there are 3 watchers for 1 binding? - javascript

Please take a look at the screenshot given below
As you can see in the screenshot above there are #3 watchers for a single binding.
Can anyone please elaborate why is it so?
P.S: I am using AngularJS Batarang for checking the performance.
var app = angular.module('app', []);
app.controller('appCtrl', function ($scope, $timeout) {
$scope.name = 'vikas bansal';
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.5/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-app="app" ng-controller="appCtrl">
{{name}}
</div>
</body>
</html>

I think Angular Batarang has a wrong counter of watchers. I checked with few different sources, and all except AngularJS Batarang show me single watcher on your code. Check out this question with function:
(function () {
var root = angular.element(document.getElementsByTagName('body'));
var watchers = [];
var f = function (element) {
angular.forEach(['$scope', '$isolateScope'], function (scopeProperty) {
if (element.data() && element.data().hasOwnProperty(scopeProperty)) {
angular.forEach(element.data()[scopeProperty].$$watchers, function (watcher) {
watchers.push(watcher);
});
}
});
angular.forEach(element.children(), function (childElement) {
f(angular.element(childElement));
});
};
f(root);
// Remove duplicate watchers
var watchersWithoutDuplicates = [];
angular.forEach(watchers, function(item) {
if(watchersWithoutDuplicates.indexOf(item) < 0) {
watchersWithoutDuplicates.push(item);
}
});
console.log(watchersWithoutDuplicates.length);
})();
And you can check Watchers extension for chrome. Both show 1 watcher.

Related

Scope function calling on DOM change(two-way data binding) angularjs

<!DOCTYPE html>
<html data-ng-app="app">
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
</head>
<body data-ng-controller="SimpleController">
<script>
var app = angular.module('app', []);
app.controller('SimpleController', SimpleController);
function SimpleController($scope) {
$scope.isNumberA = function(val) {
console.log('called');
if (val == 2) return true;
}
}
</script>
<input type="checkbox" ng-model="switcher" />
<h1 ng-if="isNumberA(10)">isNumber</h1>
</body>
</html>
In the above code first time, isNumberA calling because of ng-if="isNumberA(10)" but I don't know why it is calling another time. Check console, it prints two times on DOM render in brower. After that when I click on check box again it calling the function. Why this method calling on check box click? I didn't called it. Is this the two-way binding? And also if I remove the <h1 ng-if="isNumberA(10)"></h1>, it is not calling. What is happening here?
You have used a function call rather then a variable for condition (ng-if).
Angular watch every scope variable used in view, but when you use a function call, it can't decided which variable or event will effect this function return value, so Angular run such function on every digest cycle.
You should call this function in ng-init and store the return value of this function in a variable, and use that variable in ng-if.
$scope.isNumberA = function(val) {
console.log('called');
if (val == 2){
$scope.showIfBlock = true;
} else {
$scope.showIfBlock = false;
}
}
<span ng-init="isNumberA(10)"></sapn>
<h1 ng-if="showIfBlock">isNumber</h1>
ng-if will evaluate its expression when digest cycle runs, basically you shouldn't make an function call from ng-if expression.
DEMO
<!DOCTYPE html>
<html data-ng-app="app">
<head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
</head>
<body data-ng-controller="SimpleController">
<script>
var app = angular.module('app', []);
app.controller('SimpleController', SimpleController);
function SimpleController($scope) {
$scope.isNumberA = function(val) {
console.log('called');
if (val == 2) $scope.block = true;
$scope.block = false;
}
}
</script>
<input type="checkbox" ng-model="switcher" />
<span ng-init="isNumberA(10)"></sapn>
<h1 ng-if="block">isNumber</h1>
</body>
</html>
Read More here
ng-if being called more times than it should

How to send value in JavaScript variable to a Angular js variable

I am having a problem sending a value of JavaScript variable to Angular js variable. I want to send a value in dataArray variable in JavaScript to Angular js variable $scope.test
html code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script src="angular.js"></script>
<script type='text/javascript'>
$(document).ready(function () {
// $("#fileUpload").load('test.csv');
$.get("test.csv", function(data) {
alert(data);
var rows = data.split("\r\n");
if(rows.length>0){
alert("inside if");
var firstRowCells = GetCSVCells(rows[0], ",");
var dataArray = new Array();
for(var i=1;i<rows.length;i++)
{
var cells = GetCSVCells(rows[i], ",");
var obj = {};
for(var j=0;j<cells.length;j++)
{
obj[firstRowCells[j]] = cells[j];
}
dataArray.push(obj);
}
$("#dvCSV").html('');
alert(dataArray);
$("#dvCSV").append(JSON.stringify(dataArray));
var myjson=JSON.stringify(dataArray);
//alert(myjson);
}
});
function GetCSVCells(row, separator){
return row.split(separator);
}
});
</script>
</head>
<body>
<div id="container">
Test
</div>
<div ng-app="sortApp" ng-controller="mainController">
<div id="dvCSV" ng-model="dataf" ng-bind="bdc">dfsgdfd</div>
</div>
<script src="app.js"></script>
</body>
</html>
app.js:
angular.module('sortApp', [])
.controller('mainController', function($scope) {
window.alert("Angular");
window.alert("asdfad"+$scope.bdc);
$scope.test=$scope.dataf;
window.alert($scope.myjson);
window.alert("test"+$scope.test.value);
You can do this all jquery stuff in angular using http service of angular js.
For simple http service you can refer this link -
http://www.w3schools.com/angular/angular_http.asp
I agree with previous answer. Also its wrong to use $(document).ready along with using angular framework in you application.
Try something like this:
angular.module('sortApp', [])
.service('loadTestCsv' ['$http', function($http) {
return $http.get('test.csv').then(data => {
// do all data processing you need
return data;
});
}]);
.controller('mainController', ['$scope', 'loadTestCsv', function($scope, loadTestCsv) {
loadTestCsv().then(data => {
$scope.data = data;
});
}]);

ReferenceError: random is not defined at Scope.$scope.generateRandom angular js

For some reason it gives me the error:
ReferenceError: random is not defined at Scope.$scope.generateRandom
I dont know what im doing wrong, you can go check out the website im using to do this HERE.
index.html:
<!DOCTYPE html>
<html lang= "en">
<head>
<meta charset="UTF-8" />
<title>Basic Login Form</title>
<script data-require="angular.js#1.4.x" src="https://code.angularjs.org/1.4.8/angular.js" data-semver="1.4.8"></script>
<script src = "https://rawgit.com/nirus/Angular-Route-Injector/master/dist/routeInjector.js"></script>
<script src = "https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular-route.js"></script>
<script type="text/javascript" src="script23.js"></script>
</head>
<body ng-app = "app" ng-controller = "app">
<button ng-click = "generateRandom()">Generate Random Number</button>
<br> {{randomNumber}}
</body>
</html>
script23.js:
var app = angular.module('app', []);
app.service('random', function(){
var randomNum = Math.floor(Math.random()*10)
this.generate = function(){
return randomNum;
}
});
app.controller('app' , function($scope){
$scope.generateRandom = function(){
alert("Something")
$scope.randomNumber = random.generate();
}
})
To use service in controller, you need to inject it.
app.controller('app', function ($scope, random) {
I'd recommend you to use following syntax:
app.controller('app', ['$scope', 'random', function ($scope, random) {
See Why we Inject our dependencies two times in angularjs?
Change your controller like this, since you are using the service 'random'
myApp.controller('app', ['$scope','random', function( $scope,random)
{
$scope.generateRandom = function(){
alert("Something")
$scope.randomNumber = random.generate();
}
}])
Here is the working Application

Why printing multiple times on calling a function - AngularJS

I am calling a function from the controller scope, but in the console the values are printed three times. Why is this happening?
SOURCE
<!DOCTYPE html>
<html ng-app="myModule" >
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
</head>
<body ng-init="priceList='promo03,promo04'">
<div ng-controller="PricingController" >
{{splitArray()}}
</div>
<script>
var myModule = angular.module('myModule',[]);
myModule.controller('PricingController',['$scope', function($scope){
$scope.priceString = $scope.priceList;
$scope.array = [];
$scope.splitArray= function(){
console.log($scope.priceString);
$scope.array = $scope.priceString.split(",");
console.log($scope.array[0]);
console.log($scope.array[1]);
};
}]);
</script>
</body>
</html>
CONSOLE OUTPUT
promo03,promo04
promo03
promo04
promo03,promo04
promo03
promo04
promo03,promo04
promo03
promo04
Expected Output
promo03,promo04
promo03
promo04
This is called for every digest loop of Angular.
If you keep your program running, you'll have even more logs.
To prevent it, call your function INTO your controller, not into a binded value into your html.
For instance :
$scope.splitArray= function(){
console.log($scope.priceString);
$scope.array = $scope.priceString.split(",");
console.log($scope.array[0]);
console.log($scope.array[1]);
};
$scope.splitArray();

infdig Infinite $digest Loop

I'm learning AngularJs but I cant make it works.
I read about the digest cycle but it is not clear for me.
It's obvious that this code fails because enter in a infinite loop, but I dont know how to fix it.
Could someone help me?
<!DOCTYPE html>
<html lang="eng" ng-app="test">
<head>
<title>Learning Angular</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-route.js"></script>
<script type="text/javascript">
var app = angular.module('test', ['ngRoute']);
app.factory('visitCounterService', function () {
var counterService = function() {
var _count = 1;
var counter = function() { return _count++; };
return { counter: counter }
}();
return counterService;
});
app.service('homeModel', ['visitCounterService', function(visitCounterService){
this.getTitle = function() {
var n = visitCounterService.counter();
return "Welcome to this awesome demo. You are the visitor n° " + n;
};
}]);
app.controller('homeController', ['$scope', 'homeModel', function($scope, homeModel) {
$scope.home = homeModel;
}]);
</script>
</head>
<body ng-controller="homeController">
<h3>{{home.getTitle()}}</h3>
</body>
</html>
Thanks in advice!!!
Angular registers an implicit $watch on the home.getTitle() expression. This expression will get called at least twice because angular wants to check if the model has stabilized.
Your code returns a different string everytime home.getTitle() is called so angular continues digesting until it reaches the max digest cycles limit.
Try:
$scope.homeTitle = homeModel.getTitle();
and
<h3>{{homeTitle}}</h3>

Categories