Pass variable from controller to another controller via rootScope - angularjs

im working on a project, and I'm having difficulties passing a variable from a MainController to NavbarController, via rootScope.
Angular doesnt print the {{windowName}} variable that i pass from MainController to NavbarController via $rootScope.
So this is the code that im using:
View:
<body>
<nav ng-controller="NavbarController">
<ul>
<li>{{windowName}}</li>
</ul>
</nav>
<!-- this is where i use ng-view instead of MainController -->
<div ng-controller="MainController">
{{name}}
</div>
</body>
Controller:
var myApp = angular.module('myApp',[]);
function MainController($scope, $rootScope){
$rootScope.windowName = 'Window name 95';
$scope.name = 'Test name';
}
function NavbarController($scope, $rootScope){
$scope.windowName = $rootScope.windowName;
}
Filddle: http://jsfiddle.net/6v0fx6d2/1/
Explanation:
I'm using ngRoute, so i simplified the code, in the comment is where i use ng-view, to render the templates, so the navbar is the Basic Template that I'm using.

if you change your html structure it will work.
<div ng-controller="MainController">
{{name}}
</div>
<nav ng-controller="NavbarController">
<ul>
<li>{{windowName}}</li>
</ul>
</nav>
In angularjs the controllers are executed in the order they appear in the code.So in your case the windowName is not set. So it isn't available in NavbarController

Okay i found the problem.
To print a rootScope variable you need to add {{$route.windowName}} .
Also if you use ExpressJS with HoganTemplate, make sure you change
Hogan mustache brackets with this:
app.locals.delimiters = '{{{ }}}';

Related

How to change scope when controller is changed using Angular routes without using $rootScope

https://plnkr.co/edit/U9tL95qS5AgsPu6nNwVD/
I am able to change ng-view with templateUrl. But it is not updating {{msg}} when I am updating it using $scope.msg in every new controller.
Is there a way to update it without using $rootscope. Since I have heard that $rootScope practise is bad.
I guess I Am not registering the controller ??
I am new to Angular.
I dont know how to use services
in index.html
app.controller("redCtrl", ['$scope', '$route', function($scope, $route) {
$scope.msg = "I love red"; //NOT WORKING **************
}]);
check out this plnkr https://plnkr.co/edit/rvIZouNydPpwFgsIiVaf
#Rohitas Behera The reason is simple you are using
<div ng-app="myApp" ng-controller="mainController">
<p>Main</p>
Red
Green
Blue
<div ng-view>
</div>
{{msg}} <!-- why using here !>
</div>
so this time the msg is in scope of maincontroller . There are not other controller in scope
To do so remove {{msg}} from index.html and place it in there respective page.
Like this.
blue.html
<div style="background-color:#2196f3;">
<h1>Blue {{msg}}</h1>
</div>
same for all html page.
To alter the value {{msg}} in different context/controller, you will need to write {{msg}} in individual .html files where you have set the scope of respective controller.
As of now the variable is accessible only to your mainController as it is seen in index.html only, hence the value never changes.
You need to remove it from index.html and put it in every html.
here is the fixed plunkr
you have to add {{msg}} in every template.like this
<div style="background-color:#f44336;">
<h1>Red</h1>
{{msg}}
</div>
and remove {{msg}} form index.html page because maincontroller is working for index page and the modified page like this
<div ng-app="myApp" ng-controller="mainController">
<p>Main</p>
Red
Green
Blue
<div ng-view>

Why run method of this module isn't run? [duplicate]

I'm trying to add two angular apps / modules to one page.
In the fiddles below you can see that always only the first module, referenced in the html code, will work correctly, whereas the second is not recognized by angular.
In this fiddle we can only execute the doSearch2 method, whereas in this fiddle only the doSearch method works correctly.
I'm looking for the way how to correctly place two angular modules into one page.
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead. AngularJS applications cannot be nested within each other.
-- http://docs.angularjs.org/api/ng.directive:ngApp
See also
https://groups.google.com/d/msg/angular/lhbrIG5aBX4/4hYnzq2eGZwJ
http://docs.angularjs.org/api/angular.bootstrap
I created an alternative directive that doesn't have ngApp's limitations. It's called ngModule. This is what you code would look like when you use it:
<!DOCTYPE html>
<html>
<head>
<script src="angular.js"></script>
<script src="angular.ng-modules.js"></script>
<script>
var moduleA = angular.module("MyModuleA", []);
moduleA.controller("MyControllerA", function($scope) {
$scope.name = "Bob A";
});
var moduleB = angular.module("MyModuleB", []);
moduleB.controller("MyControllerB", function($scope) {
$scope.name = "Steve B";
});
</script>
</head>
<body>
<div ng-modules="MyModuleA, MyModuleB">
<h1>Module A, B</h1>
<div ng-controller="MyControllerA">
{{name}}
</div>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
<div ng-module="MyModuleB">
<h1>Just Module B</h1>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
</body>
</html>
You can get the source code at:
http://www.simplygoodcode.com/2014/04/angularjs-getting-around-ngapp-limitations-with-ngmodule/
It's essentially the same code used internally by AngularJS without the limitations.
Why do you want to use multiple [ng-app] ? Since Angular is resumed by using modules, you can use an app that use multiple dependencies.
Javascript:
// setter syntax -> initializing other module for demonstration
angular.module('otherModule', []);
angular.module('app', ['otherModule'])
.controller('AppController', function () {
// ...do something
});
// getter syntax
angular.module('otherModule')
.controller('OtherController', function () {
// ...do something
});
HTML:
<div ng-app="app">
<div ng-controller="AppController">...</div>
<div ng-controller="OtherController">...</div>
</div>
EDIT
Keep in mind that if you want to use controller inside controller you have to use the controllerAs syntax, like so:
<div ng-app="app">
<div ng-controller="AppController as app">
<div ng-controller="OtherController as other">...</div>
</div>
</div>
You can bootstrap multiple angular applications, but:
1) You need to manually bootstrap them
2) You should not use "document" as the root, but the node where the angular interface is contained to:
var todoRootNode = jQuery('[ng-controller=TodoController]');
angular.bootstrap(todoRootNode, ['TodoApp']);
This would be safe.
Manual bootstrapping both the modules will work. Look at this
<!-- IN HTML -->
<div id="dvFirst">
<div ng-controller="FirstController">
<p>1: {{ desc }}</p>
</div>
</div>
<div id="dvSecond">
<div ng-controller="SecondController ">
<p>2: {{ desc }}</p>
</div>
</div>
// IN SCRIPT
var dvFirst = document.getElementById('dvFirst');
var dvSecond = document.getElementById('dvSecond');
angular.element(document).ready(function() {
angular.bootstrap(dvFirst, ['firstApp']);
angular.bootstrap(dvSecond, ['secondApp']);
});
Here is the link to the Plunker
http://plnkr.co/edit/1SdZ4QpPfuHtdBjTKJIu?p=preview
NOTE: In html, there is no ng-app. id has been used instead.
I made a POC for an Angular application using multiple modules and router-outlets to nest sub apps in a single page app.
You can get the source code at: https://github.com/AhmedBahet/ng-sub-apps
Hope this will help

AngularJS - How to add an app in a particular state to a HTML element

So lets say my app is called myApp, and the controller I wanna use is MyCtrl. So I can include this app in a div tag like this:
<div ng-app="myApp" ng-controller="MyCtrl">
</div>
Lets say there are a few states, and usually I would use the router to map the states to the URL like this: http://example.com/state1 or http://example.com/state2.
If I wanna include this app in state2 into the div tag, is there a way to do this? I'm kinda new to angular, basically I wanna be able to build a page that includes pieces of different modules into different parts of the page.
You will want to user ui-router for that. Specifically, you will use the ui-view directive to specify where a state's template goes into it's parent template, or the page.
you can use ng-include: Fetches, compiles and includes an external HTML fragment.
From Angular docs: AngularJS API
<div ng-controller="ExampleController">
<select ng-model="template" ng-options="t.name for t in templates">
<option value="">(blank)</option>
</select>
url of the template: <code>{{template.url}}</code>
<hr/>
<div class="slide-animate-container">
<div class="slide-animate" ng-include="template.url"></div>
</div>
</div>
<div ng-app="myApp" ng-controller="MyCtrl">
<div ui-view>
//here goes your states
</div>
</div>
// inject $stateProvider in your module and config function like:
var routerApp = angular.module('routerApp', ['ui.router']);
routerApp.config(function($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/home');
$stateProvider.state("home.state1",{
url:"home/state1"
templateUrl:templatename.html,
controller:MyCtrl,
}).state("home.state2",{
url:"home/state2"
templateUrl:templatename.html,
controller:MyCtrl,
});
})

AngularJS Trying to use ng-click with ng-switch but ng-switch is not switching my divs

AngNoob here. I have some global navigation that uses the routeProvider to swap out external html pages inside the view. Within the view i set up a list type sub navigation (created with ng-repeat) that switches out divs in the external html file. I can get it to load up the page if I set it manually in the appCtrl:
//Here I set the initial value
$scope.page = 'Comfort Homes of Athens';
But when I click on the span that has the ng-click. I get nothing. I started to think it was a scope issue but when i put just an ng-click='alert()' it does nothing either.
I have read around other posts but most seem to be putting a ng-click inside of an ng-switch rather than the reverse. and aren't using routing in their examples either. Still new to angular so maybe its something I haven't come across yet.
App HTML:
<body ng-app="app">
<header ng-include="header.url" ng-controller="nav"></header>
<article ng-view></article>
<footer ng-include="footer.url" ng-controller="nav"></footer>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.2.16/angular-route.js"></script>
<script type="text/javascript" src="js/data.js"></script>
<script type="text/javascript" src="js/model.js"></script>
</body>
External HTML File:
<div id="web" class="wrapper">
<aside class="boxModel">
<div id="controller" class="container">
<div class="topBox bluebg subNavBar"><h1 class="white">Projects</h1></div>
<div ng-controller="nav" id="controls" class="botBox whitebg">
<span ng-repeat='item in webProjects' ng-click="page='{{item.name}}'">{{item.name}}</span>
</div>
</div>
</aside><section ng-switch on="page" class="boxModel">
<div ng-switch-when="Comfort Homes of Athens" id="sandbox" class="container round box whitebg">
<h1>Here is link 1</h1>
</div>
<div ng-switch-when="Sealpak Incorporated" id="sandbox" class="container round box whitebg">
<h1>here is Link 2</h1>
</div>
</section>
</div>
JS:
var app = angular.module("app", ["ngRoute"]);
function nav($scope) {
$scope.templates = templates;
$scope.header = $scope.templates[0];
$scope.footer = $scope.templates[1];
$scope.mainNav = mainNav;
$scope.footNav = footNav;
}
app.config(function($routeProvider) {
$routeProvider.when('/',{
templateUrl: "templates/home.html",
controller: "AppCtrl"
}).when('/templates/web.html',{
templateUrl: "templates/web.html",
controller: "AppCtrl"
}).when('/templates/seo.html',{
templateUrl: "templates/seo.html",
controller: "AppCtrl"
}).otherwise({
template: "This doesn't exist!"
});
});
app.controller("AppCtrl", function($scope) {
$scope.webProjects = webProjects;
$scope.seoProjects = seoProjects;
//Here I set the initial value
$scope.page = 'Comfort Homes of Athens';
});
Unfortunately for you, ng-repeat creates child scopes which are siblings with each other and children of your parent controller (ng-controller="nav") while your <section> where ng-switch is on is not child scope of your ng-controller="nav", but AppCtrl.
You could try ng-click="$parent.$parent.page=item.name" just to understand scopes in angular.
<div id="web" class="wrapper">
<aside class="boxModel">
<div id="controller" class="container">
<div class="topBox bluebg subNavBar"><h1 class="white">Projects</h1></div>
<div ng-controller="nav" id="controls" class="botBox whitebg">
<span ng-repeat='item in webProjects' ng-click="$parent.$parent.page=item.name">{{item.name}}</span>
</div>
</div>
</aside><section ng-switch on="page" class="boxModel">
<div ng-switch-when="Comfort Homes of Athens" id="sandbox" class="container round box whitebg">
<h1>Here is link 1</h1>
</div>
<div ng-switch-when="Sealpak Incorporated" id="sandbox" class="container round box whitebg">
<h1>here is Link 2</h1>
</div>
</section>
I don't recommend using this solution as it's quite ugly. The solution of #link64 is better, but I think the inheritance of model is so implicit and creates a tightly-coupled code. Here I propose another solution which I hope is better by emitting an event:
<span ng-repeat='item in webProjects' ng-click="$emit('pageChange',item.name)">{{item.name}}</span>
I'm not sure if angular is able to resolve $emit('pageChange',item.name) expression in the template. If you run into any problems, you could write inside your controller:
<span ng-repeat='item in webProjects' ng-click="setPageChange(item.name)">{{item.name}}</span>
In your nav controller:
$scope.setPageChange = function (pageName) {
$scope.$emit("pageChange",pageName);
}
In your AppCtrl, listen to the event and update the page.
app.controller("AppCtrl", function($scope) {
$scope.webProjects = webProjects;
$scope.seoProjects = seoProjects;
//Here I set the initial value
$scope.page = 'Comfort Homes of Athens';
$scope.$on("pageChange", function (event, newPage){
$scope.page = newPage;
}
});
In addition to #KhanhTo's answer, I wanted to point you toward another tool to use instead of ngRoute; UI-Router. This is not the answer to your original question, but it is a better solution that avoids your issue entirely.
UI-Router enhances the page routing of ngRoute and is more centered around states. You transition to states that have templates and optional controllers. It emits its own events such as $stateChangeStart or $stateChangeSuccess. You can invoke these state transitions with the function command $state.go(stateName) or by a directive ui-sref="my.state({name: item.name})
UI-Router is a very powerful tool and I cannot go into all the details here but the documentation and community is great.
A simple rewrite of your code could look like the following.
Template for web.html
<div class="wrapper">
<aside class="boxModel">
<div id="controller" class="container">
<div class="topBox bluebg subNavBar"><h1 class="white">Projects</h1></div>
<div ng-controller="nav" id="controls" class="botBox whitebg">
<span ng-repeat='item in webProjects' ui-sref="app.web.page({name: {{item.name}})">
{{item.name}}
</span>
</div>
</div>
</aside>
<section class="boxModel">
<div ui-view class="container round box whitebg">
<!-- Page content will go here -->
</div>
</section>
</div>
JavaScript
app.config(function($stateProvider) {
$stateProvider
.state('app', {
abstract: true,
template: '<div ui-view></div>', //Basic template
controller: "AppCtrl",
}).state('app.home', {
templateUrl: "templates/home.html",
url: '/home'
}).state('app.web',{
templateUrl: "templates/web.html",
url: '/web'
}).state('app.web.page',{
templateUrl: "templates/page.web.html",
url: '/web/page/:name' //Note here the ':' means name will be a parameter in the url
}).state('app.seo',{
templateUrl: "templates/seo.html",
url: '/seo'
});
});
app.controller('AppCtrl', function($scope){
$scope.webProjects = webProjects;
$scope.seoProjects = seoProjects;
$scope.$on("$stateChangeStart", function (event, toState, toParams, fromState, fromParams){
if(newState.name == 'app.web.page'){
var pageName = newStateParams.name; //Variable name matches
$scope.linkText = fetchPageContent(pageName);
}
});
});
Template for page.web.html
<h1>{{linkText}}</h1>
With these changes you will be able to reuse the same instance of your controller. In addition to allowing your paging content to be more scalable.
Notes on $scopes
Every $scope has a parent except for the $rootScope. When you ask for an object in the view, it will look at its $scope to find the reference. If it does not have the reference, it will traverse up to its parent scope and look again. This occurs until you get to the $rootScope.
If you assign something to the $scope in the view, it will assign it to the current $scope as opposed to searching up the $scope chain for an existing property. That is why ng-click="model.page = ..." works; it looks up the $scope chaing for model and then assigns to the page property whereas ng-click="page = ..." assigns directly to the current $scope.
Notes on Controller re-use
To my knowledge, ngRoute does not support nested views. When you go to a new route, it will destroy the current view and controller as specified in the $routeProvider and then instantiate a new controller for the new view. UI-Router supports nested states (i.e. child states with child $scopes). This allows us to create a parent controller that can be re-used amongst all the child states.
I think this may be related to some misunderstanding of how scope works.
ng-repeat creates its own scope. When attempting to set page, angular creates it on the scope of the ng-repeat.
In your AppCtrl, create an object on the scope as follows:
$scope.model = {};
$scope.model.page = 'Comfort Homes of Athens';//Default value
On your ng-click, refer to model.page instead of just page. Angular will then traverse up the scope to find model.page instead of just create a property on the local scope of the ng-repeat.
<span ng-repeat='item in webProjects' ng-click="model.page='{{item.name}}'">{{item.name}}</span>
Also, your AppCtrl is going to be recreated every time you change pages. You should probably use a service to persist the state between page changes

Multiple angularjs applications for one page [duplicate]

I'm trying to add two angular apps / modules to one page.
In the fiddles below you can see that always only the first module, referenced in the html code, will work correctly, whereas the second is not recognized by angular.
In this fiddle we can only execute the doSearch2 method, whereas in this fiddle only the doSearch method works correctly.
I'm looking for the way how to correctly place two angular modules into one page.
Only one AngularJS application can be auto-bootstrapped per HTML document. The first ngApp found in the document will be used to define the root element to auto-bootstrap as an application. To run multiple applications in an HTML document you must manually bootstrap them using angular.bootstrap instead. AngularJS applications cannot be nested within each other.
-- http://docs.angularjs.org/api/ng.directive:ngApp
See also
https://groups.google.com/d/msg/angular/lhbrIG5aBX4/4hYnzq2eGZwJ
http://docs.angularjs.org/api/angular.bootstrap
I created an alternative directive that doesn't have ngApp's limitations. It's called ngModule. This is what you code would look like when you use it:
<!DOCTYPE html>
<html>
<head>
<script src="angular.js"></script>
<script src="angular.ng-modules.js"></script>
<script>
var moduleA = angular.module("MyModuleA", []);
moduleA.controller("MyControllerA", function($scope) {
$scope.name = "Bob A";
});
var moduleB = angular.module("MyModuleB", []);
moduleB.controller("MyControllerB", function($scope) {
$scope.name = "Steve B";
});
</script>
</head>
<body>
<div ng-modules="MyModuleA, MyModuleB">
<h1>Module A, B</h1>
<div ng-controller="MyControllerA">
{{name}}
</div>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
<div ng-module="MyModuleB">
<h1>Just Module B</h1>
<div ng-controller="MyControllerB">
{{name}}
</div>
</div>
</body>
</html>
You can get the source code at:
http://www.simplygoodcode.com/2014/04/angularjs-getting-around-ngapp-limitations-with-ngmodule/
It's essentially the same code used internally by AngularJS without the limitations.
Why do you want to use multiple [ng-app] ? Since Angular is resumed by using modules, you can use an app that use multiple dependencies.
Javascript:
// setter syntax -> initializing other module for demonstration
angular.module('otherModule', []);
angular.module('app', ['otherModule'])
.controller('AppController', function () {
// ...do something
});
// getter syntax
angular.module('otherModule')
.controller('OtherController', function () {
// ...do something
});
HTML:
<div ng-app="app">
<div ng-controller="AppController">...</div>
<div ng-controller="OtherController">...</div>
</div>
EDIT
Keep in mind that if you want to use controller inside controller you have to use the controllerAs syntax, like so:
<div ng-app="app">
<div ng-controller="AppController as app">
<div ng-controller="OtherController as other">...</div>
</div>
</div>
You can bootstrap multiple angular applications, but:
1) You need to manually bootstrap them
2) You should not use "document" as the root, but the node where the angular interface is contained to:
var todoRootNode = jQuery('[ng-controller=TodoController]');
angular.bootstrap(todoRootNode, ['TodoApp']);
This would be safe.
Manual bootstrapping both the modules will work. Look at this
<!-- IN HTML -->
<div id="dvFirst">
<div ng-controller="FirstController">
<p>1: {{ desc }}</p>
</div>
</div>
<div id="dvSecond">
<div ng-controller="SecondController ">
<p>2: {{ desc }}</p>
</div>
</div>
// IN SCRIPT
var dvFirst = document.getElementById('dvFirst');
var dvSecond = document.getElementById('dvSecond');
angular.element(document).ready(function() {
angular.bootstrap(dvFirst, ['firstApp']);
angular.bootstrap(dvSecond, ['secondApp']);
});
Here is the link to the Plunker
http://plnkr.co/edit/1SdZ4QpPfuHtdBjTKJIu?p=preview
NOTE: In html, there is no ng-app. id has been used instead.
I made a POC for an Angular application using multiple modules and router-outlets to nest sub apps in a single page app.
You can get the source code at: https://github.com/AhmedBahet/ng-sub-apps
Hope this will help

Resources