Consider two div areas as follows, in html file
<div class="divArea1" ng-controller="myController">
<input ng-click="updateName()" type="button" value="button"/>
</div>
<div class="divArea1" ng-controller="myController">
<p>{{name}}</p>
</div>
Following is the angular js example
productApp.controller("myController", [ '$scope', function($scope) {
$scope.name= "XYZ";
$scope.updateName= function() {
$scope.name = "ABC";
};
} ]);
problem is when I am trying to update the name, upon click on update button it is not visible in the second in the div area. Is there any mistake i am doing.
What you have is two different controllers (with two separate scopes) with the same name.
You need to put the controller in the parent controller to keep the name in the same scope as the button:
<div id="container" ng-controller="myController">
<div class="divArea1">
<input ng-click="updateName()" type="button" value="button"/>
</div>
<div class="divArea1">
<p>{{name}}</p>
</div>
</div>
Controllers are not singletons. Each time you have a new controller, you're having a new instance of this controller, with a new isolated scope.
If your need is to share data between controllers, you should use a factory (which is a singleton).
angular.module('app').factory('mySharedData', function(){
var service = {
object : objectToShare
};
var objectToShare = {};
return service;
});
And from your controller :
angular.module('app').controller('myController',
['$scope','mySharedData',
function($scope, mySharedData){
$scope.someObject = mySharedData.object;
$scope.updateName= function() {
$scope.someObject.name = "ABC";
};
}
]);
And from your view :
<div class="divArea1" ng-controller="myController">
<input ng-click="updateName()" type="button" value="button"/>
</div>
<div class="divArea1" ng-controller="myController">
<p>{{someObject.name}}</p>
</div>
Note : I've encapsulated the name property into an object because objects are passed by reference, and strings by value. This allows you to make it easier to share your values and to have it automatically updated into the service and other controllers, without having to access your property through accessors.
here is demo http://jsfiddle.net/wg7pb1yu/3/
inject $rootScope so that it will do from global scope
productApp.controller("myController", [ '$scope','$rootScope', function($scope, $rootScope) {
$rootScope.name= "XYZ";
$scope.updateName= function() {
$rootScope.name = "ABC";
};} ]);
Hope this will help you
Related
I'm new to angular and little bit confused with it. So basically I created a simple button and i want to run function foo() whitch assigns variable var one = 1; to $scope and outputs it in <p>{{one}}<p> every time its clicked like in live typing but this seems not working. Please provide me a solution to this.
<html ng-app="app">
<!-- Body tag augmented with ngController directive -->
<body ng-controller="myController">
<input type="text" ng-model="name">
<p>{{name}}</p>
<p>{{one}}</p>
<button ng-click="foo()">1</button>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script src="controller.js"></script>
</body>
</html>
controller:
var app = angular.module('app',[]);
app.controller('myController', ['$scope',function($scope){
var one = 1;
$scope.name = name;
function foo(){
return $scope.one = one;
}
}]);
function foo() dont exist in $scope your controller "myController"
if you declaration:
$scope.foo = function(){}
in your controller, then this work for you
when you are calling controller function from the html, controller function should be scope. Other wise ng-click directive doesn't recognize the function.
same concept goes to binding variable to html. only scope variables can directly bind to html using curly brackets. so inside foo function var one should assign to scope.one in order to display it in the html.
angular.module("app",[])
.controller("ctrl",function($scope){
var one = 1;
$scope.name = name;
$scope.foo = function(){
$scope.one = one;
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
<input type="text" ng-model="name">
<p>{{name}}</p>
<p>{{one}}</p>
<button ng-click="foo()">1</button>
</div>
I wish I can handle this, but in the bad way...namely I need to use $cookieStore to check either the function called or not.
Every time to use push array then I need to use $cookieStore. But it seems not practical.
Here was my DOM:
<div ng-controller="MyCtrl">
<div>
<div ng-include="'temp2.html'">
Hello, {{name}}!
</div>
</div>
</div>
<script type="text/ng-template" id="temp2.html">
<div ng-controller="MyCtrl">Another View</div>
</script>
And my angularjs controller:
var myApp = angular.module('myApp',[]);
//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});
function MyCtrl($scope) {
$scope.name = 'Superhero';
alert(1);
}
alert(1) function will be called 2 times every times the page was called.
How to avoid this problem without using watcher?
My fiddle for your convenience. Thanks!
The controller would called be twice for both the views, i would suggest you to move controller specific code to init function and use ng-init in one of your views.
var Controller = function($scope) {
$scope.init = function () {
};
};
Your View
<div ng-controller="Controller" ng-init="init()"/>
Yo don't need to specify the Controller name again in the include.... if its the same as the parent one(same as controller of main page).
just go with this
<div ng-controller="MyCtrl">
<div>
<div ng-include="'temp2.html'">
Hello, {{name}}!
</div>
</div>
</div>
<script type="text/ng-template" id="temp2.html">
<div>Another View {{name}}</div>
</script>
Js Fiddel
name will be accessible in the view you included.
Hope it will help you..
I have a requirement wherein a single page contains lot of data. All these data are though different but needs to be displayed in one page only (with vertical scroll).
I have made various collapsible divs on my page and they are controlled usig ng-if for avoiding too much of DOM.
Initially for prototype, I had JS logics for all these divs in one controller. However, now I am following a different approach wherein I want one controller for the page and various child controller for the collapsible divs.
I kept one object each for a div in page controller and made several other controller on my main module (app.js). I expect each of them to be child of pageCtrl and as such I should be accessing data for each div in 'pageCtrl`.
However, this is not working. No errors though on consoles, but no divs are visible.
My structure is as:
<body ng-app ="mainModule">
<div ng-controller ="pageCtrl">
<div ng-controller = "collapse1Ctrl" ng-include="collapse1.tpl" ng-if="collapse1reqd">
<div ng-controller = "collapse2Ctrl" ng-include="collapse2.tpl" ng-if="collapse2reqd">
<div ng-controller = "collapse3Ctrl" ng-include="collapse3.tpl" ng-if="collapse3reqd">
<div ng-controller = "collapse4Ctrl" ng-include="collapse4.tpl" ng-if="collapse4reqd">
<div ng-controller = "collapse5Ctrl" ng-include="collapse5.tpl" ng-if="collapse5reqd">
</div>
JS is like:
angular.module("mainModule", []);
angular.module("mainModule").controller("pageCtrl", pageCtrlFn);
angular.module("mainModule").controller("collaspse1Ctrl", collaspse1CtrlFn);
angular.module("mainModule").controller("collaspse2Ctrl", collaspse2CtrlFn);
angular.module("mainModule").controller("collaspse3Ctrl", collaspse3CtrlFn);
angular.module("mainModule").controller("collaspse4Ctrl", collaspse4CtrlFn);
angular.module("mainModule").controller("collaspse5Ctrl", collaspse5CtrlFn);
Rest assured, all templates and conditions are at correct places.
Since my code as such is too large, I am avoiding to post it currently. May be I will post a similar fiddle soon.
But currently I wonder if is there any problem with having such a structure at all ??
Based on the OP's question and the problem's faced here's an example demo on how nested controllers work and how the scope behaves.
HTML looks like
<body ng-app="scopeInheritance">
<div class="spicy">
<div ng-controller="MainController">
<p>Good {{timeOfDay}}, {{name}}!</p>
<p>{{display.showName}} - {{age}} --> New Age - {{display.age}}</p>
<input type="text" ng-model="name">
<button ng-click="resetTime()">CHANGE</button>
<div ng-controller="ChildController">
<p>Good {{timeOfDay}}, {{name}}!</p>
<button ng-click="setTime()">SET</button>
<input type="text" ng-model="display.showName"> Age - {{age}}
<input type="text" ng-model="age">
<button ng-click="setAge()">Change Age</button>
<div ng-controller="GrandChildController">
<p>Good {{timeOfDay}}, {{name}}!</p>
</div>
</div>
</div>
</div>
JS looks like below
(function(angular) {
'use strict';
var myApp = angular.module('scopeInheritance', []);
myApp.controller('MainController', ['$scope', function($scope) {
$scope.timeOfDay = 'morning';
$scope.files ='';
$scope.name = 'Nikki';
$scope.display={};
$scope.display.showName ='Vikram';
$scope.age ='20';
// $scope.display.age ='20';
$scope.resetTime = function(){
$scope.timeOfDay = 'chaged day';
};
}]);
myApp.controller('ChildController', ['$scope', function($scope) {
$scope.name = 'Mattie';
$scope.$parent.timeOfDay ='';
$scope.setTime = function(){
$scope.timeOfDay = 'new day';
};
$scope.setAge = function(){
$scope.display.age ='25';
};
}]);
myApp.controller('GrandChildController', ['$scope', function($scope) {
$scope.timeOfDay = 'evening';
$scope.name = 'Gingerbread Baby';
}]);
})(window.angular);
This example is an extension of Angular Js org nested controllers doc's based example.
Better to wrap all your templates and controllers into components and hide them from outside controller
<component1 ng-if="req1"></component1>
<component2 ng-if="req2"></component2>
<component3 ng-if="req3"></component3>
and use ControllerAs of course.
I'm trying to display a div if an object is non-empty. Using this answer, Im trying to use angular.equals to check emptyness, but its not behaving as expected
var test = angular.module('test',[]);
test.controller('testCtrl', ['$scope', function($scope){
$scope.foo={};
$scope.bar="bam"
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
<div ng-controller="testCtrl">
<div ng-show="!angular.equals(foo,{})">{{bar}}</div>
</div>
</div>
The expectation here is that the value of bar will only show if foo is not equal to an empty object. However, foo is clearly set to {} and yet bar still shows.
If you want to access the angular object from templates or expressions, you have to make it available on the scope of where you want to use it. In this case you can put it on the testCtrl's scope.
var test = angular.module('test',[]);
test.controller('testCtrl', ['$scope', function($scope){
$scope.angular = angular;
$scope.foo={};
$scope.bar="bam"
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
<div ng-controller="testCtrl">
<div ng-show="!angular.equals(foo,{})">{{bar}}</div>
</div>
</div>
I generally put utility objects on $rootScope, so they're available from everywhere.
A cleaner way would be to only add the angular equals method to the $scope:
var test = angular.module('test',[]);
test.controller('testCtrl', ['$scope', function($scope){
$scope.angularEquals = angular.equals;
}
Then you can use the equals method in the template, like:
<div ng-show="!angularEquals(foo,{})">{{bar}}</div>
Your view is looking for a function on the scope, and $scope.angular.equals does not exist. You need to write one like this:
var test = angular.module('test', []);
test.controller('testCtrl', ['$scope',
function($scope) {
$scope.foo = {};
$scope.bar = "bam";
$scope.isEmpty = function(obj) {
return angular.equals(obj,{});
};
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="test">
<div ng-controller="testCtrl">
<div ng-hide="isEmpty(foo)">{{bar}}</div>
</div>
</div>
Angular functions can't be used inline, AFAIK.
You could do the equal check with a function inside the controller instead and return the result.
I'm new to Angular.
I am having problems dealing with variables back and forth between my controller and html.
In my controller not only I want to read $scope, but I also want to use it in a function I have in my services.
This is my factory:
angular.module('myApp.services', [])
.factory('hotels', function($http){
return{
search: function(city, callback){
$http({
method: 'GET',
url: 'http://myhotels.com/hotels/?city='+city+
cache: true
}).success(callback);
}
};
})
controller:
angular.module('myApp.controllers', [])
.controller('SearchHotelsController', ['$scope', 'hotels', function($scope, hotels){
$scope.hotelCity = "";
hotels.search($scope.hotelCity, function(hotelResults){
$scope.hotelResults = hotelResults;
});
}])
and in the html I don't have a button to call the function. It is supposed to be called when I get the scope variable (hotelResults):
<input class="form-control" type="text" ng-model="hotelCity">
<a ng-href="#/searchResults"><button>Search</button></a>
and when it routes to that page, which uses the same controller, I get:
{{hotelResults.name}}
================================================================
I also tried declaring $scope.hotels = {hotelCity: "sf"}; in th controller , then put this in html: <input type="text" ng-model="hotels.hotelCity"> and in my controller to call $scope.hotels.hotelCity in the function, but still they are not connected! no matter what the user puts in the input, I get 'sf' for my hotelCity.
Please someone shed a light on this for me, thanks!
I am also new-bie to angular, and looking at your question, i am not fully aware what you are actually looking for but what i have understood and came up with this. Might help.
<html ng-app="myApp">
<head><title>Test</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.21/angular.min.js"></script>
</head>
<body>
<div class="test-wrap" ng-controller="myHotels">
<input type="text" name="h" ng-model="hotelcity" />
<button ng- click="search()">Search</button>
<p>List of Hotel's</p>
<ul>
<li ng-repeat="h in hotel | filter:hotelcity">{{h.name}}</li>
</ul>
</div>
</body>
</html>
<script type="text/javascript">
var myApp = angular.module('myApp',[]);
myApp.controller('myHotels', ['$scope', function($scope) {
$scope.hotel = [{"name":"Test1 hotel"},{"name":"Test2 hotel"},{"name":"Test3 hotel"}];
$scope.search = function(){
console.log($scope.hotelcity);
}
}]);
</script>
I finally decided to pass my data through my url and then get it with $routeParams in my controller.
I didn't figure out the problem with my code, and I kind of expected Angular to be this smooth with passing variables back and forth, but I guess this particular situation is a javascript issue with different scopes and function arguments.
I also learned about the Closure concept of javascript which didn't help me either!
Solution: I put a button at the bottom of the page inside an tag;
<a ng-href="#/searchResults/{{hotelCity}}"><button>Search</button></a>
then in routeProvide in my app.js file:
$routeProvider.when('/searchResults/:city', {templateUrl: 'partials/second.html', controller: 'secondController'});
then in controller:
hotels.search($routeParams.city, function(hotelResults){
$scope.hotelResults = hotelResults;
});
[make sure to declare $routeParams in your controller next to $scope]