Can't access $parent from ng-included controller - angularjs

I'm pretty new to Angular and I'm trying to build an app.
I use ng-include to insert my view, depending on the currentURL variable of my main controller.
When I try to access the main controller via $parent from the ng-included file, all I get is undefined.
My goal is to change the currentURL variable to update the view.
Here is my code:
index.html
<body ng-controller="mainCtrl as main">
currentURL : {{main.currentURL}}
<div ng-include="main.currentURL"></div>
<script src="/vendors/angular.min.js"></script>
<script src="/modules/login.js"></script>
<script src="app.js"></script>
</body>
app.js
angular
.module('mcaApp', ['login'])
.controller('mainCtrl', mainCtrl);
function mainCtrl() {
var vm = this,
baseURL = 'views/';
vm.currentURL = baseURL + 'login.html';
}
views/login.html
<div ng-controller="loginCtrl as login">
<h1>LOGIN</h1>
</div>
modules/login.js
angular
.module('login', [])
.controller('loginCtrl', loginCtrl);
function loginCtrl() {
var vm = this;
console.log(vm.$parent); // undefined
}

As you want to access mainCtrl which was inside loginCtrl controller then you need use $parent to access parent controller scope.
But the thing is you are loading loginCtrl controller view using ng-include so your controller is loaded in the child scope of the mainCtrl, because ng-include create a child scope from current scope.
For that reason you need use $parent.$parent to access mainCtrl scope from loginCtrl
Code
function loginCtrl($scope) {
var vm = this;
console.log($scope.$parent.$parent); // this would contain mainCtrl
}
Better approach would be to use controllerAs syntax or follow dot rule while defining objects so that prototypal inheritance gets followed.

Related

angularjs components getting a form inside template

so I have a component with a template containing a form.
mycomponent.html:
<div>
<form name="myForm">
<!-- more html code -->
</form>
</div>
How can I access myForm inside the component controller?
Currently I'm injecting $scope to get it from that.
Or is that the only way to get the form?
Edit: Added some code to better illustrate in javascript
angular.module('example')
.component('myComponent', {
templateUrl: 'mycomponent.html',
controller: function($scope) {
$scope.myForm // This works
this.myForm // undefined, can I access it through the component scope instead of $scope somehow?
}
});
The name attribute of a form is what angular uses to decide what to bind to. So, if you're using the controllerAs syntax, you have to use that in the form name:
<body ng-controller="MainCtrl as vm">
<form name='vm.myForm'>
</form>
</body>
This will allow you to refer to it in your controller without using $scope, but only after the controller has been successfully created:
app.controller('MainCtrl', function($scope, $timeout) {
var vm = this;
console.log(vm.myForm); // undefined
$timeout(function() {
console.log(vm.myForm); // FormController object
}, 100);
});
Here is a working plunk.
Use the name syntax but also a components postLink lifecycle hook, that function is called once a template and controller have been connected see https://docs.angularjs.org/guide/component

How to initialise value in controller with Angular js ?

How to initialise value inside controller function with AngularJS tried multiple time but not getting proper answer??
You can inject $scope in your controller function. Then you can define any variable inside $scope.
Example
.controller('TestController', ['$scope', function($scope) {
$scope.message = 'Hello';
}])
As you can see in the above example I have injected $scope to TestController and defined message variable inside it.
Note that all the variables defined in a controller scope are accessable by the view belonging to that controller. So you can access the value of $scope.message in your DOM as
<div ng-controller="TestController">
{{message}}
</div>
On the screen you will see the text Hello

Angular function parameter order

I made a little fiddle here. In the example below, there are 3 controllers:
1st is a regular controller.
2nd I changed ordering of controller constructor parameters
3rd Assigned value to local $scope instead of $rootScope.
2nd controller shows that even I when changed ordering and number of parameters, value still gets assigned to root scope. From this I conclude angular somehow knows names of parameters for a function, regardless of their order? (kinda like named parameters?) This sounds weird to me. How can parameter names mean something outside of function's own 'curly brackets'?
3rd controller shows, all local scopes are a copy of $rootScope, and {{variable}} convention points to variable inside local scope, instead of the global root scope.
Am I right in these two conclusions?
index.html :
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.5/angular.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="myApp" ng-controller="myController">
<div ng-controller="myController">
<h3>Echo: {{one}}</h3>
</div>
<div ng-controller="myController2">
<h3>Echo: {{two}}</h3>
<h3>Echo: {{three}}</h3>
</div>
<div ng-controller="myController3">
<h3>Echo: {{three}}</h3>
</div>
</body>
</html>
script.js
var app = angular.module('myApp',[]);
app.run(function($rootScope) {
$rootScope.today = new Date();
});
app.controller("myController", function($rootScope, $scope){
$rootScope.one = 'root scope one';
});
app.controller("myController2", function($scope, $scope, $rootScope){
$rootScope.two = 'root scope two';
});
app.controller("myController3", function($scope, $scope, $rootScope){
$scope.three = '~scope three';
});
outputs:
Echo: root scope one
Echo: root scope two
Echo:
Echo: ~scope three
Angular's dependency injection can infer the service to be injected based on the name. So yes, if you name the parameters according to the name of the services, then Angular will infer the correct service and the parameter ordering is irrelevant. This is not minification-safe, if you will be minifying your code you need to use one of the other approaches for injection. See section on Implicit Annotation in Angular's guide to Dependency Injection.
There is a single $rootScope which is injected into each of your controllers, so they are not copies of each other but are the same object. Local scopes inherit from $rootScope via prototypical inheritance. Therefore, if you attempt to access a property on a local scope, Angular will first check on the local scope for the property but if it does not exist, it will search the parent scope (then the parent scope of the parent scope etc.) See Angular's guide to Scope especially the section on Scope Hierarchies.

ng-include and ngRoute: how to make them work together? (i.e. route to a view wihin a ng-include)

[EDITED] My app has the following structure:
index.html
<body ng-app = "myApp" ng-controller ="mainController">
<ng-view></ng-view>
</body>
mainView.html (loaded into ng-view through routeProvider in app.js)
<div ng-include src="subview1">
<div ng-include src="subview2">
subview1 and subview2 are set within mainController (mainView's controller) as scope variables:
$scope.subview1= "templates/subview1.html";
$scope.subview2= "templates/subview2.html";
controller1 and controller2 are subview1 and subview2's controllers.
subview1.html (loaded in first div of mainView)
<div ng-controller="controller1">
<button ng-click="loadNewView()"></button>
</div>
controller1.js
.controller('controller1', function($scope){
$scope.loadNewView = function(){
$scope.$parent.subview1 = "templates/view3.html";
}
}
scope.loadNewView should load a different view (and relative controller) within the div with src="subview1" in mainView.html). Basically it's about refreshing the view itself by raplacing it with another view (and related controller).
I use $parent to update the view in subview1's parent view (i.e. mainView).
however nothing happens and if I try to use $scope.$apply() I get error (digest already in progress).
Any clue?
you can try something like this...
In your stateProvider or in your routeProvider if you using.
var mod = angular.module('example.states', ['ui.router']);
mod.config(['$stateProvider', '$urlRouterProvider',
function($stateProvider, $urlRouterProvider) {
$stateProvider
.state('exampleState', {
url: '/main',
templateUrl: 'mainView.html',
controller: mainController
});
}
]);
return mod;
So here you have associated your parent controller(let's say the mainController which will be the parent of all others) with its template mainView.html.
Then in your mainView.html,Load all the subview templates.
<div ng-repeat="template in templates">
<ng-include src="template.url"></ng-include>
</div>
templates is an array in your mainController which has the url or path of all your subtemplates.When you use ng-include inside the main template then all subTemplates will automaticlly become the child of the mainTemplate and its Controllers too.In a way it will inherit from the parent Controller.
So suppose if subView1.html is one of the template url you had given in ng-include.Then it will look like
<div ng-controller="subView1Controller">
//Here your code
</div>
And subview2 as
<div ng-controller="subView2Controller">
//Here your code
</div>
This way you will have multiple views on the same page with one url and different controllers with its associated templates and each will inherit from the parent controller which is mainController here.
There, might be better approach than this.
This is what i had used in my project,and its simple to keep your code simple manage.
Okay,so using routeProvider,you can use it like this
var app = angular.module("app",[]);
app.config(function($routeProvider){
$routeProvider
.when('/main',{
templateUrl:"mainView.html",
controller:mainController
})
});
app.controller("mainController",function($scope){
});
app.controller("subView1Controller",function($scope){
});
app.controller("subView1Controller",function($scope){
});
Then in your mainView.html,Load all the subview templates.
<ng-include src="yoursubtemplate1path"></ng-include>
<ng-include src="yoursubtemplate2path"></ng-include>
And then in yoursubtemplate1 use
<div ng-controller="subView1Controller">
//Here your code
</div>
Same for the other templates.
You can set the template src of the subtemplates from your mainController.
app.controller("mainController",function($scope){
$scope.templatesrc="/app/template1.html";
});
And then use it in your template,where you are using ng-include directive.
<ng-include src="templatesrc"></ng-include>
Its better to store template url's in an array and use ng-repeat directive like i had stated before,if you are loading more templates.
And if you want to show the div on some button click lets say in parent controller then use ng-if in the sub-view main and make it true on button click.
This answer is regarding your updated question.
The solution which you had used before,will load all temlplate and once in ng-include and its associated controller making the mainController as parent.
But if you want to load a different view with its newController then you can try something like this.
Just add one more route and call on your event click,but remember this newView's Controller will have no parent-child relation with the mainView's controller.
var app = angular.module("app",[]);
app.config(function($routeProvider){
$routeProvider
.when('/main',{
templateUrl:"mainView.html",
controller:mainController
})
.when('/anyName',{
templateUrl:"templates/view3.html",
controller:temp3Controller
})
});
And in your controller1.js
.controller('controller1', function($scope){
$scope.loadNewView = function(){
$location.path('/anyName');
}
}
Inject location service in controller1.
I finally found the solution.
The tricks is using
$scope.$parent.$parent.subview1 = "templates/view3.html";
instead of
$scope.$parent.subview1 = "templates/view3.html";
since, basically:
ng-include is the child of mainView
subview1 is the child of ng-include

angularjs call a service injecting in the parent in the children

I'm finding a way to call a service
injecting in the parent from within a children.
I ended up with
<div ng-controller="ParentController">
<div ng-controller="ChildController">{{my}}</div>
</div>
<script>
var app = angular.module('myApp', []);
app.factory('Data',function(){
return {show:function(msg){return msg;}};
});
app.controller('ParentController',function($scope,Data){
$scope.shareService = Data;
});
app.controller('ChildController',function($scope){
$scope.my = $scope.$parent.shareService.show('Hey');
});
</script>
I'm wondering if could be a good practice (may be it's not very handy) or not
or if there is a better way.
If the service is independent of the parent controller, you can inject the service directly in the child controller like you did in parent controller. Why create a dependency on the parent scope.
Services by definition are meant to be shared across controllers, directive and other services.

Resources