AngularJS - ng-click is calling multiple times - angularjs

I'm new to AngularJS and have been learning it from W3Schools. My issue is that ng-click is not working properly. It's calling repeatedly. If I click on the element with ng-click once it calls the function once. If I click it again it calls the function twice. If I continue clicking the button the function is called as many times as I've clicked the element before.
<!DOCTYPE html>
<html>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<h1 id="h12" ng-click="changeName()" style="cursor:pointer;">{{firstname}}</h1>
</div>
<script>
var count = 0;
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.firstname = "John";
$scope.changeName = function() {
var h12 = document.getElementById("h12").innerHTML;
alert(count);
if (count == 0) {
$scope.firstname = "Nelly";
changeNGClick(h12);
count++;
} else {
count++;
var x = "";
var div1 = document.getElementById("h12");
var align = div1.getAttribute("data-v");
alert(align);
$scope.firstname = align;
changeNGClick(h12);
}
}
return false;
});
function compile(element) {
var el = angular.element(element);
$scope = el.scope();
$injector = el.injector();
$injector.invoke(function($compile) {
$compile(el)($scope)
})
}
function changeNGClick(v) {
var el = document.getElementById("h12");
el.setAttribute("data-v", v);
compile(el);
}
</script>
<p>Click on the header to run the "changeName" function.</p>
<p>This example demonstrates how to use the controller to change model data.</p>
</body>
</html>
This is how the code will work. When I click the header which has the text John then it will change to display Nelly. If you click it again it should change back to John. The value will be saved on the <h1> tags data-v. I would also appreciate another way of doing this if you have any suggestions.

Related

How to use angular.bind(self, fn, args)

I am new to angular js. I was gone through the angular api references,
I had seen function called angular.bind(self, fn, args).
I could not understand the usage of this function. Can anyone explain this function with one example?
It used in Function Currying. An example with JavaScript:
var concat = function(input1) {
return function(input2) {
console.log(input1 + ", " + input2);
};
};
var externalFunction = concat("Hello");
externalFunction("World!"); // gives: "Hello, World!"
This allows you to use only some parameters and not all, for example concant("Hello") instead of concant("Hello","World!"). You can imagine using a defined variable as one of the parameters, whereas you fill in the second one from a user input. The same concept can be used with AnuglarJS:
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.2/angular.min.js"></script>
</head>
<body ng-app="app">
<div ng-controller="bindController">
<input type="number" ng-model="num" ng-change="AddValue()" />
Adding 5: {{Add}}
</div>
</body>
</html>
<script>
var app = angular.module("app", []);
app.controller('bindController',['$scope',function($scope){
$scope.num = 30;
$scope.AddValue = function () {
var addData = angular.bind(this, function (a, b) {return a + b;});
$scope.Add = addData(5, $scope.num);
}
$scope.AddValue();
}]);
</script>
Controller
app.controller('Identity`enter code here`Controller', ['$scope',
function($scope) {
$scope.Name = "";
$scope.Result = "";
var greet = function (greeting, punctuation) {
$scope.Result = greeting + ' ' + $scope.Name +''+ punctuation;
};
$scope.callBind = function () {
var bound = angular.bind(this, greet, 'Welcome');
bound('!!!!!');
};
}]);
html
<fieldset style="background-color:#DDE4E9;">
<legend>AngulerJS $scope.bind() Example</legend>
<div ng-controller="IdentityController">
<p>{{Result}}</p>
<input ng-model="Name">
<button ng-click="callBind()">Call Bind</button>
</div>
</fieldset>
I Think Its Working

How to hide some element on screen resize in angularjs

I am new in angularjs. I searched a lot to hide some html element on body resize but did't work. here is my controller code.
var app = angular.module('studentPage',[]);
app.controller ('studentController',function($scope, $window) {
var appWindow = angular.element($window);
appWindow.bind('resize', function () {
if($window.innerWidth < 600){
alert("hello");
$scope.ohh = true;
}
});
});
and here where i use ng-show
<div id="sidebar-wrapper" ng-show="ohh">
If you want to achieve this using AngularJS, you need to relaunch the digest cycle using $scope.$apply().
appWindow.bind('resize', function () {
if($window.innerWidth < 600){
$scope.ohh = true;
$scope.$apply();
}
});
Anyway, I think a cleaner way to do that is using CSS media queries:
#media only screen and (max-width: 599px) {
#sidebar-wrapper {
display: none;
}
}
You have to manually trigger the digest cycle using $apply() function , since what you are doing is out of angular context.Try the below code.
var app = angular.module('studentPage',[]);
app.controller ('studentController',function($scope, $window) {
var appWindow = angular.element($window);
appWindow.bind('resize', function () {
if($window.innerWidth < 600){
alert("hello");
$scope.ohh = true;
$scope.$apply()
} });});
You have to apply the scope changes by calling $scope.$apply().:-
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope, $window) {
var appWindow = angular.element($window);
$scope.ctrl = {};
$scope.ctrl.ohh = false;
appWindow.bind('resize', function() {
console.log($window.innerWidth);
if ($window.innerWidth < 600) {
$scope.ctrl.ohh = true;
$scope.$apply()
}
});
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<h1>THis is main content</h1><br>
<div id="sidebar-wrapper" ng-show="ctrl.ohh">This is shown after window width is less than 600
</div>
</div>

angular $watch is not work with d3.js

look, click the button, $scope.optionis change, but $watch is not work, can`t console.log the option value , why?
I am sorry , it is my mistake , but it still is a problem in I use width d3.js
I use d3.js append a rect into page, and I want to when I click the rect can chagne the option value, but $watch is not work, why?
angular.module('myapp',[]).controller('myCtrl', function($scope){
$scope.option = '123';
$scope.d3TreeDraw = {
source : {
name: 'myTree'
},
updata: function(){
var _self = this;
var tree = d3.layout.tree().nodeSize([90, 60]);
var nodes = tree.nodes(_self.source).reverse();
nodes.forEach(function(d) { d.y = d.depth * 90; });
var svg = d3.select("body").append("svg")
.attr("width", 200)
.attr("height", 200)
var node = svg.selectAll("g.node")
.data(nodes)
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.style('cursor','pointer')
.on('click', function(d){
console.log('click'); // can console.log
$scope.option = '456';
console.log($scope.option) //is change
})
nodeEnter.append("rect")
.attr('width',150)
.attr('height', 30)
.style('fill', '#000')
}
}
$scope.d3TreeDraw.updata();
$scope.$watch('option', function(){
console.log('change:' + $scope.option); // when option is change,can not console.log
})
})
1) First You have taken myTree.onClick() and your function has onclick
So, the onClick() spelling mismatched.
Change button to <button ng-click="myTree.onclick()">456</button>
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<button ng-click="myTree.onclick()">{{data}}</button>
<br>
</div>
<script>
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.firstName = "John";
$scope.lastName = "Doe";
$scope.data = '100';
$scope.myTree = {
onclick: function() {
$scope.data = '456';
}
}
$scope.$watch('data', function(){
console.log($scope.data);
alert($scope.data);
})
});
</script>
</body>
</html>
Here is a working DEMO.
EDIT:
By checking your edit, I saw that your scope assignment is outside of angular.
So, you need to $apply() the $scope
Change,
$scope.option = '456';
to,
$scope.$apply(function() {
$scope.option = '456'
});
The above method, runs the digest cycle manually, and apply the changes for the scope.
Performance:
If you write $scope.$apply() it will run complete digest cycle, which will affect the performance, so we sent a function into the $apply method and only ran the digest cycle of specific `scope.
Hence, you can $watch the scope whenever you want.
you have a upper case letter in the function name
change this
<button ng-click="myTree.onClick()">456</button>
to this
<button ng-click="myTree.onclick()">456</button>
Demo
angular.module("app",[])
.controller("ctrl",function($scope){
$scope.data = '123';
$scope.$watch('data', function(){
console.log($scope.data);
})
$scope.myTree = {
onclick: function() {
$scope.data = '456';
}
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<button ng-click="myTree.onclick()">456</button>
</div>

ng-animate not firing event (ng-enter)

I have the following angularjs application which loads content from Instagram, however, on page load I would like to fade the loaded content in with a smooth transition.
For some reason ng-animate doesn't seem to be firing the ng-enter event. so I can add a CSS animation. Is there something wrong?
HTML
<section ng-controller="ShowImages as images" class="page {{ loadedClass }}" >
<div ng-view>
......
</div>
JS
(function(){
//Place your own Instagram client_id below. Go to https://instagram.com/developer/clients/manage/ and register your app to get a client ID
var client_id = '83aaab0bddea42adb694b689ad169fb1';
//To get your user ID go to http://jelled.com/instagram/lookup-user-id and enter your Instagram user name to get your user ID
var user_id = '179735937';
var app = angular.module('instafeed', ['ngAnimate']);
app.filter('getFirstCommentFrom',function(){
return function(arr, user){
for(var i=0;i<arr.length;i++)
{
if(arr[i].from.username==user)
return arr[i].text;
}
return '';
}
})
app.factory("InstagramAPI", ['$http', function($http) {
return {
fetchPhotos: function(callback){
var endpoint = "https://api.instagram.com/v1/users/self/media/liked/";
endpoint += "?access_token=179735937.83aaab0.e44fe9abccb5415290bfc0765edd45ad";
endpoint += "&callback=JSON_CALLBACK";
$http.jsonp(endpoint).success(function(response){
callback(response.data);
});
}
}
}]);
app.controller('ShowImages', function($scope, InstagramAPI){
$scope.layout = 'grid';
$scope.data = {};
$scope.pics = [];
$scope.$on('$viewContentLoaded', function(){
$scope.loadedClass = 'page-feed';
});
InstagramAPI.fetchPhotos(function(data){
$scope.pics = data;
console.log(data)
});
});
})();
I also link to these in the HTML:
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular/angular-route.js"></script>
<script src="bower_components/angular/angular-animate.js"></script>
What am I doing wrong?
See here:
http://machinas.com/wip/machinas/instagramfeed/
Do u ve included the css file right??
I think u don't need this:
$scope.$on('$viewContentLoaded', function(){
$scope.loadedClass = 'page-feed';
});
The ng-enter is active when u set the value of the var that u use inside the ng-repeat
look at this http://codepen.io/shprink/pen/Ariyc

How does service variable change update to controllers

I have a small problem and I don't understand this thing:
When I add an item to TestiFactorys arr - array it does update to both controllers
On the other hand why does not TestiFactorys arr_len update to both controllers. And in TestiController why do I have to "manually" update TestControllers list1_length to make it update to view but I don't have to update TestiContollers list1 to make it update to view
I am assuming that my poor Javascript or Javascript variable scope understanding is causing this but i just don't see it.
I am using AngularJS version 1.2.16
<!DOCTYPE html>
<html ng-app="TestiApp">
<head>
<title></title>
</head>
<body>
<div ng-controller="TestController">
List items from controller: {{list1}}<br>
List item count:{{list1_length}}
<input type="text" ng-model="param"><br>
<button ng-click="list1_add(param)">asd</button>
</div>
<br><br>
<div ng-controller="TestController2">
List items from controller2{{list2}} <br>
List items count in from controller2: {{list2_length}}
</div>
<script src="scripts/angular.min.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>
And this is my app.js:
var TestiApp = angular.module('TestiApp', [])
TestiApp.factory('TestiFactory',function() {
var arr = ['abx','cbs'];
var arr_len = arr.length;
return {
list : function() {
return arr;
},
add_to_arr : function(n) {
arr.push(n);
},
arr_len : function() {
arr_len = arr.length;
return arr_len;
}
}
}
);
TestiApp.controller('TestController', function($scope, TestiFactory) {
$scope.list1 = TestiFactory.list();
$scope.list1_length = TestiFactory.arr_len();
$scope.list1_add = function (d) {
TestiFactory.add_to_arr(d);
$scope.param = '';
$scope.list1_length = TestiFactory.arr_len();
}
});
TestiApp.controller('TestController2', function($scope, TestiFactory) {
$scope.list2 = TestiFactory.list();
$scope.list2_length = TestiFactory.arr_len();
});
EDIT WITH SOLUTION
Here is working solution. Based to comments I decided to do more studying on Javascripts basics which
is of course the thing I should have done before trying to use this complex framework which uses Javascript. So now I have some basic understanding how to use references in Javascript and what primitive data types are. And based on that here is working version:
<!DOCTYPE html>
<html ng-app="TestiApp">
<head>
<title></title>
</head>
<body>
<div ng-controller="TestController">
List items from controller: {{list1()}}<br>
List item count:{{list1_len()}}
<input type="text" ng-model="param"><br>
<button ng-click="list1_add(param)">asd</button>
</div>
<br><br>
<div ng-controller="TestController2">
List items from controller2{{list2()}} <br>
List items count in from controller2: {{list2_length()}}
</div>
<script src="scripts/angular.min.js"></script>
<script src="scripts/app.js"></script>
</body>
</html>
And app.js:
var TestiApp = angular.module('TestiApp', [])
TestiApp.factory('TestiFactory',function() {
var arr = ['abx','cbs'];
return {
list : function() {
return arr;
},
add_to_arr : function(n) {
arr.push(n);
},
arr_len : function() {
return arr.length;
}
}
}
);
TestiApp.controller('TestController', function($scope, TestiFactory) {
$scope.list1 = TestiFactory.list;
$scope.list1_add = TestiFactory.add_to_arr;
$scope.list1_len = TestiFactory.arr_len;
});
TestiApp.controller('TestController2', function($scope, TestiFactory) {
$scope.list2 = TestiFactory.list;
$scope.list2_length = TestiFactory.arr_len;
});
I've ran into this many times. Factories and services in angular are not like scopes...they work using references. The reason the array updates in your controllers is because the original reference was updated. The length is not updating because the number type is primitive.
This should work:
TestiApp.controller('TestController', function($scope, TestiFactory) {
$scope.list1 = TestiFactory.list();
$scope.$watch('list1', function(list1) {
$scope.list1_length = list1.length;
});
$scope.list1_add = function (d) {
TestiFactory.add_to_arr(d);
$scope.param = '';
};
});
TestiApp.controller('TestController2', function($scope, TestiFactory) {
$scope.list2 = TestiFactory.list();
$scope.$watch('list2', function(list2) {
$scope.list2_length = list2.length;
});
});

Resources