Angular JS two way binding not updating when using button - angularjs

I'm a bit of a newb at angular and having a persnickety issue. I am trying to update a variable bound to a div in my controller with a function, that is called when a button is clicked. (The function is bound to the button by ng-click.) When I click the button, the displayed value does not change, even though the variable is changed. However if I assign the same updating function to the element itself it does change when I click that element. Can anyone explain?
Here's my code:
Javascript
angular.module('Compendium',['ngRoute'])
.config(function($routeProvider){
$routeProvider.when('/css',{
templateUrl:'css.html',
controller: 'cssCtrl'
})
}).controller('cssCtrl',function($scope,counterhelper){
//counterhelper($scope.data)
//counter.increment();
$scope.increment = function(){
alert('hey');
$scope.display = 'Nothing'
}
$scope.display = 1;
// var transform = function(){
//
}).factory('counterhelper',function(){
var addOne = function(val){
val ++;
}
return addOne;
})
and Html
<html ng-app = "Compendium">
<head>
<script src = "node_modules/angular/angular.js"> </script>
<script src = "node_modules/angular-route/angular-route.js"> </script>
<script src = "app.js"></script>
<script type="text/ng-template" id="css.html">
<h1 ng-controller = 'cssCtrl' ng-click='increment()'>
{{display}}
</h1>
<button ng-click = 'increment()' >Increment</button>
</script>
</head>
<body>
<div ng-view>
</div>
</body>
</html>
Thanks!

Problem here is your controller is outside the button hence it does not recognize the controller attached, wrap it inside a div
<div ng-controller = 'cssCtrl'>
<h1 ng-click='increment()'>
{{display}}
</h1>
<button ng-click = 'increment()' >Increment</button>
</div>

Related

ng-if="hideDiv" , where hideDiv = false does not hides div

I have to hide a div on click .
<div ng-if="hideDiv">
<div>text text text text</div>
<a ng-click="hideMe(false)">Click Me To Hide</a>
</div>
Controller
this.hideMe = function(action){
$scope.hideDiv = action;
}
tested results are
console.log($scope.hideDiv) // Is false
{{hideDiv}} <!--Is false-->
But still ng-if doesn't hide div ?
Please, test the snippet below. I'm pretty sure your problem is due to some angularJS configuration failure
(function(){
angular.module("app", []).controller("testController", function($scope)
{
$scope.showDiv = true;
$scope.hideMe = function(IsVisible)
{
$scope.showDiv = IsVisible;
}
});
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app" ng-controller="testController">
<div ng-if="showDiv">
<a ng-click="hideMe(false)">Click Me To Hide</a>
</div>
</div>

angularjs dom manipulation based on button click

basically i want to change the attribute value based on the button i clicked,
these are the two buttons
<button ng-click="fn(a)"></button>
<button ng-click="fn(b)"></button>
and then i have a prebuilt directive who takes value as input,
<div directive-name="" id="abc"></div>
if i click on first button,i want the value of directive based on button clicked.
What i did earlier;
$scope.go = function(data){
if(data==a){
var b = document.querySelector( 'div' );
b.setAttribute("directive-name","value");
}
else{}
}
here the problem is that it is selecting the first div of document and setting attribute value for that.
I also tried to pass it with id like
var b = angular.element(document.querySelector('#abc'));
I also saw some custom directives to do so, but they are not working
AngularJS DOM Manipulation through Directives
If possible provide me a demo in plunkr or fiddle
and also if i want to change css property of div based on button clicked
Thanks in advance
You can do it like this.
Assign the directive-name value to a $scope.variable and then use variable as the value in HTML.
HTML - 1:
<button ng-click="go(a)"></button>
<button ng-click="go(b)"></button>
HTML - 2:
<div directive-name="{{directive}}" id="abc"></div>
JS:
$scope.go = function(data){
if(data==a){
$scope.directive = "directive-1";
}else if(data==b){
$scope.directive = "directive-2";
}
}
To assign class name to div you can define other $scope.classVar and then use that in HTML like below:
<div directive-name="{{directive}}" id="abc" ng-class="classVar"></div>
I hope this will solve your problem.
This should work, (you had some errors in your code):-
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.fn = function(data,id) {
if (data == 'a') {
var b = document.querySelector('#'+id);
b.setAttribute("directive-name", "value");
} else {
}
}
});
<!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">
<div directive-name="" id="abc"></div>
<button ng-click="fn('a','abc')">A</button>
</div>
"Basically I want to change the attribute value based on the button I clicked."
You can do this by changing the attribute value the angular way, referencing a property of $scope or the controller instance in your template. When clicking a button, set the variable to the value you require to be passed to your directive.
Note: When you pass a value into your ngClick directive, you need to pass it as a string unless a and b are declared as properties of $scope.
Here's a basic example:
// app.js
(function() {
'use strict';
angular.module('app', []);
})();
// main.controller.js
(function() {
'use strict';
angular.module('app').controller('MainController', MainController);
MainController.$inject = ['$scope'];
function MainController($scope) {
$scope.fn = fn;
function fn(data) {
// set the value so it's accessable in the view
// therefore we can pass it into our directive
$scope.myVar = data;
}
}
})();
// directive-name.directive.js
(function() {
'use strict';
angular.module('app').directive('directiveName', directiveNameDirective);
function directiveNameDirective() {
return {
restrict: 'A',
scope: {
directiveName: '='
},
template: '<span>directiveName: {{ directiveName }}</span>'
};
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="MainController as MainCtrl">
<!-- here we pass a and b as strings otherwise they get evaluated as variables -->
<button ng-click="fn('a')">Set a</button>
<button ng-click="fn('b')">Set b</button>
<hr>
<!-- here we pass myVar which is declared as a property of $scope when the fn function is called -->
<div directive-name="myVar" id="abc"></div>
<hr> myVar: {{ myVar }}
</div>
</div>

form has both a `name` attribute and a `ng-controller` directive?

I understand that a form directive is an instance of FormController and is published onto the current scope under the value of the name attribute. (https://docs.angularjs.org/guide/forms).
What happens then when a form directive also contains a ng-controller directive as shown in this example?
I tried to see what would happen if the name of the ng-controller attribute is not "FormController":
<html>
<head>
<script src='angular.js'></script>
</head>
<script type='text/javascript'>
Object.prototype.getName = function() {
var funcNameRegex = /function (.{1,})\(/;
var results = (funcNameRegex).exec((this).constructor.toString());
return (results && results.length > 1) ? results[1] : "";
};
</script>
<body>
<div ng-app='theApp'>
<form name='myForm' >
</form>
{{myForm.getName()}}
<form name='myForm2' ng-controller='MyFormController'>
{{myForm2.getName()}}
</form>
</div>
<script type='text/javascript'>
angular.module('theApp', []).controller('MyFormController', ['$scope', function($scope) {}]);
</script>
</body>
</html>
The above code prints in the console:
FormController
FormController
The name of the controller is not important!
The sense of ngForm is that a <form> automatically becomes an instance of the ngForm directive, to which you can attach any controller!
So in the end your myForm2 will have:
ngForm methods and props (es. myForm2.$valid ecc.)
MyFormController methods and props (in your case... nothing :-p )

ng-show and ng-hide not binding to given variable in angularjs

I am using ng-show and ng-hide to show the banner for my page. When I am logged in I wanna show different banner than for logged out. So I have two div with ng-show and ng-hide whose value I am changing in the controller to true and false.
Html code:
First banner:
<div id="firstPageHeader" class="navbar navbar-inverse" role="navigation" ng-show={{display}}>
Second banner:
<div id="restPageHeader" class="navbar-header" ng-hide={{display}}>
Controller:
var LoginController = function($scope){
$scope.display = true;
$scope.loginUser = function(credentials){
console.log(credentials.username);
$scope.display = false;
}
$scope.logout = function(){
console.log('logout');
$scope.display = true;
}
So here according to login and logout the display value will change to true and false but its not happening the value remains only true.
So I want to know why the value is not getting changed even I used $scope.$apply()
ngShow and ngHide directives expect expressions. So it should be without curly braces {{ (which are used for expression interpolation):
ng-show="display"
Can you explain how you are using loginUser() and logout() , coz in my case it is working fine..
My index.html is :
<!doctype html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="switchcases"> <div ng-controller="LoginController">
<div ng-click="logout()">Hi</div>
<div ng-click="loginUser()">Bye</div>
<hr>
<div ng-show="display">Hi</div>
<div ng-hide="display">Bye</div>
</div>
</body>
</html>
and app.js is :
angular.module('switchcases',[])
.controller('LoginController',function($scope){
$scope.display = true;
$scope.loginUser = function(credentials){
//console.log(credentials.username);
$scope.display = false;
};
$scope.logout = function(){
//console.log('logout');
$scope.display = true;
};
});
Cases :: When I click Hi(the one above <hr> tag) , only the 'Hi' below <hr> tag is displayed and when i click Bye(the one above <hr> tag),only the 'Bye' below <hr> tag is displayed , as expected .
The default value displayed will be 'Hi' below the <hr> tag.
Just check once that if you are using loginUser() inside the scope of the controller.
You just need to replace braces in ng-hide and ng-show double quotes
<div id="restPageHeader" class="navbar-header" ng-hide="display">
I am login
<img src="https://marketplace.canva.com/MABY09l0-Tw/1/0/thumbnail_large/canva-outlined-lettering-border-tumblr-banner-MABY09l0-Tw.jpg" alt="">
</div>
<div id="restPageHeader" class="navbar-header" ng-show="display">
I am logout
<img src="https://img.clipartfest.com/08e6b6a7495aca9bbc478fcf662cd29b_welcome-hanging-banner-welcome-banner-clipart_935-311.jpeg" alt="">
</div>
this is controller
$scope.display = true;
$scope.loginUser = function () {
console.log('loginUser');
$scope.display = false;
}
$scope.logout = function () {
console.log('logout');
$scope.display = true;
}

Manipulate array of parent controller from child controller inside ng-repeat loop

I want to manipulate items in an array stored in a parent controller. When I manipulate the items, I want to do this from within an ng-repeat loop inside a child controller.
As far as I can tell, the array in the parent controller is being updated - in fact s===cs. I have read that $scope.$apply() might be the answer but I'm not sure how to call that using the "controller as" syntax below - or if that is even wise.
<html ng-app='app'>
<body ng-controller='parent_controller as pc'>
{{ pc.parent_name }}
<br>
Enter parent_name <input ng-model='pc.parent_name'/>
<br>
<button ng-click='pc.change_parent_name()'>change parent_name</button>
<div ng-controller='child_controller as cc'>
<div ng-repeat='item in pc.myarray' style='border:1px solid #ccc; margin:20px;'>
Item = {{ item }}
<br>
<button ng-click='cc.change_item_name($index)'>change item name</button>
</div>
</div>
<script src="js/jquery.min.js"></script>
<script src="js/angular.min.js"></script>
<script type='text/javascript'>
var app = angular.module('app',[]);
function parent_controller(){
var self = this;
window.s = self; // For debugging
self.myarray = ['a','b','c'];
self.change_parent_name = function () {
self.parent_name = 'changed!!';
}
}
app.controller('parent_controller',[parent_controller]);
function child_controller() {
var self = this;
window.cs = self; // For debugging
parent_controller.apply(self, arguments);
self.change_item_name = function(index){
console.log(index);
self.myarray[index] = 'changed';
}
}
app.controller('child_controller',[child_controller]);
</script>
</body>
</html>
Since the array has primitive string type, pass in the parent array and index into the child controller function and it should work fine.
self.change_item_name = function(items, index){
console.log(index);
items[index] = 'changed';
}
And the html changes to:
<button ng-click='cc.change_item_name(pc.myarray,$index)'>change item name</button>
You would be better off putting the child controller on the ng-repeat, and then using that to update the parent controller. $scope.$apply is not necessary. If you want to update the parent controller from the controller code, you are better off using a service to communicate between the two.
Moving the data source from the parent controller to a service and injecting that service into both controllers allows them to access the same data. [AngularJS API reference]
This example does that and adds a third controller to highlight the extent to which the data is shared across controllers.
ctrl_3 below also shows how $scope can be accessed using controller as syntax. $scope is only used for the console.log part - it isn't used for this service approach.
<html ng-app='app'>
<body ng-controller='a_controller as ctrl_1'>
{{ ctrl_1.parent_name }}
<br>
Enter parent_name <input ng-model='ctrl_1.parent_name'/>
<br>
<button ng-click='ctrl_1.change_parent_name()'>change parent_name</button>
<div><strong>ctrl_2</strong></div>
<div ng-controller='a_controller as ctrl_2'>
<div ng-repeat='item in ctrl_2.myarray' style='border:1px solid #ccc; margin:20px;'>
Item = {{ item }}
<br>
<button ng-click='ctrl_2.change_item_name(ctrl_2.myarray, $index)'>change item name</button>
</div>
</div>
<!-- an extra repeat of the myarray, this time using ctrl_1 for the repeat of myarray but ctrl_3 as the controller, just to show it all ties back to the same data source -->
<hr>
<div><strong>ctrl_3</strong></div>
<div ng-controller='a_controller as ctrl_3'>
<div ng-repeat='item in ctrl_1.myarray' style='border:1px solid #ccc; margin:20px;'>
Item = {{ item }}
<br>
<button ng-click='ctrl_3.change_item_name(ctrl_3.myarray, $index)'>change item name</button>
</div>
</div>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js'></script>
<script type='text/javascript'>
angular.module('app',[])
.factory('DataService', [function() {
data = [ {'a':1}, {'b':2}, {'c':3} ];
return {
myarray : data
}
}])
.controller('a_controller', ['DataService', '$scope', function(DataService, $scope) {
var self = this;
window.s = self; // For debugging
console.log($scope);
self.myarray = DataService.myarray;
self.change_parent_name = function () {
self.parent_name = 'changed!!';
}
self.change_item_name = function(array,index){
array[index] = {'changed': 999};
}
}]);
</script>
</body>
</html>

Resources