angular ui modal can NOT refer to parent scope - angularjs

i am using angular ui modal to create modal in my project.
Everything works fine until I need to refer to variable in parent scope. see plunker code
It seems like modal can't access parent scope. Is there anyway to overcome this?

Angular UI's modals use $rootScope by default (See the documentation here).
You can pass a scope parameter with a custom scope when you open the modal – e.g. scope: $scope if you want to pass the parent scope. The modal controller will create a sub-scope from that scope, so you will only be able to use it for your initial values.

You'll need to refer to the parent scope in your $modal options. Angular documentation
Corrected Plunker Version
Below is also a code snippet of what I added to make it work.
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: ModalInstanceCtrl,
scope:$scope, //Refer to parent scope here
resolve: {
items: function () {
return $scope.items;
}
}
});

You can add an ID to the parent div and use his scope.
<div id="outerdiv" ng-controller="OuterCtrl">
<h2>Outer Controller</h2>
<input type="text" ng-model="checkBind">
<p>Value Of checkbind: {{checkBind}}</p>
And set up a "fake" binding within the controller
//init
$scope.checkBind = angular.element(document.getElementById('outerdiv')).scope().checkBind;
$scope.$watch('checkBind', function (newValue, oldValue) {
//update parent
angular.element(document.getElementById('outerdiv')).scope().checkBind = $scope.checkBind;
});
See http://plnkr.co/edit/u6DuoHJmOctFLFhvqCME?p=preview

Related

Angular Controller and controllerAs keyword usage in directive

learning angular so some time things not clear when read article on angular. here i stuck to understand what is the usage or importance of this keywords Controller and controllerAs in directive.
code taken from here http://blog.thoughtram.io/angularjs/2015/01/02/exploring-angular-1.3-bindToController.html
app.controller('SomeController', function () {
this.foo = 'bar';
});
app.directive('someDirective', function () {
return {
restrict: 'A',
controller: 'SomeController',
controllerAs: 'ctrl',
template: '{{ctrl.foo}}'
};
});
i like to know understand the importance of this two keywords in directive and they are controller: 'SomeController', and controllerAs: 'ctrl',
please tell me if we do not use these two keyword controller: 'SomeController', and controllerAs: 'ctrl', then what would happen or what would be worse ?
please help me to understand the usage or importance of this keywords controller: 'SomeController', and controllerAs: 'ctrl', in directive. thanks
You need the controller if you plan on referencing a controller object. This is how you hook it up.
The controllerAs allows you to create a variable that you can reference the controller with in lieu of using the $scope.
Refined answer:
<html ng-app="app">
<head></head>
<body>
<script src="node_modules/angular/angular.js"></script>
<script>
var app = angular.module('app', []);
app.directive('fooDirective', function() {
return {
restrict: 'A',
controller: function($scope) {
// No 'controllerAs' is defined, so we need another way
// to expose this controller's API.
// We can use $scope instead.
$scope.foo = 'Hello from foo';
},
template: '{{foo}}'
};
});
app.directive('barDirective', function() {
return {
restrict: 'A',
controller: function() {
// We define a 'vm' variable and set it to this instance.
// Note, the name 'vm' is not important here. It's not public outside this controller.
// The fact that the 'controllerAs' is also called 'vm' is just a coincidence/convention.
// You could simply use 'this.bar' if you prefer.
var vm = this;
vm.bar = 'Hello from bar';
},
// This allows us to reference objects on the controller's instance by
// a variable called 'vm'.
controllerAs: 'vm',
// Now we can reference objects on the controller using the 'controllerAs' 'vm' variable.
template: '{{vm.bar}}'
};
});
</script>
<div foo-directive></div>
<div bar-directive></div>
</body>
</html>
One of its main advantages, especially if you're new to AngularJS, is that it ensures proper data binding between child scopes.
Just play around with this code sample and try to notice something strange:
angular
.module('myApp', [])
.controller('MainCtrl', ['$scope',
function($scope) {
$scope.truthyValue = true;
$scope.foo = 'hello';
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<div ng-app="myApp" ng-controller="MainCtrl">
<p>Start by writing something in the first input. Then write something in the second one. Good job, you've broke AngularJS!</p>
1.
<input type="text" ng-model="foo">
<div ng-if="truthyValue">
2.
<input type="text" ng-model="foo">
</div>
<div>$scope.foo: {{ foo }}</div>
</div>
The reason behind it is that ngIf creates a child scope which inherits from the parent scope. You're basically changing the value inside ngIf's scope which doesn't affect the value from its parent scope.
Finally, I consider controllerAs syntax an important AngularJS best practice. If you get accustomed to it early in your learning process, you'd be avoiding a lot of head-scratching wondering why your code doesn't work, especially when everything seems in order.
You don't need to use both controller and controllerAs. You can use the shorthand:
controller: 'SomeController as ctrl'
The relationship is that a new instance of the controller is created and exposed to the template using the instance handle you provide as ctrl.
Where this comes in handy is if you are using nested controllers -- or using multiple instances of a controller in a view.
UPDATE TO ANSWER COMMENTS
You do not need to use controllers with AngularJS directives. Infact as of AngularJS 1.5 you should probably only use controllers when creating components rather than directives.
Directives and Components are conceptually similar. Up until AngularJS they all components would be defined as a directive.
In many ways a directive interacts with an element (like ng-href) or events (like ng-click).
The simplest way to differentiate Components and Directives is a Component will have a template.
Can't I just create a component using the directive link method?
You can, but I wouldn't recommend it unless you have a good reason. Using controllers allows you to use object oriented classes or prototypes to define the action behaviors with the template and user.
As well these controllers are extremely more easy to unit test than the directive link functions.
Check out this plunkr code
Here is my simple Directive code:
angular.module('app', [])
.directive('someDirective', function () {
return {
scope: {},
controller: function ($scope) {
this.name = 'Pascal';
$scope.color = 'blue';
},
controllerAs: 'ctrl',
template: '<div>name: {{ctrl.name}} and Color: {{color}}</div>'
};
});
And The HTML
<body ng-app="app">
<some-directive />
</body>
So, as you can see, if you need to access some variable which were defined against this keyword in the controller, you have to use controllerAs. But if it was defined against $scope object you can just access it with its name.
For example, you can get the variable color just by using {{color}} as it was defined against $scope but you have to use {{ctrl.name}} as "name" was defined against this.
I don't think there really is much difference, as this answer says,
Some people don't like the $scope syntax (don't ask me why). They say
that they could just use this
Also from their own website you can read the about the motivation behind this design choice,
Using controller as makes it obvious which controller you are
accessing in the template when multiple controllers apply to an
element
Hope it helps.

Angularjs remove custom directive and child directives from DOM

I have a single page angularjs app. I use $routeProvider to load up custom directives shown in the code below.
Now each custom directive loaded is made up of additional sub custom directives. All the custom directives have isolated scopes.
What I need is when the view changes is the scope to be destroyed as well as remove the directives from the DOM under the current view. I've got as far as the following code. Can this be achieved with Jquery lite and/or angularjs only? If so how do I remove the parent and child directives from the DOM for a particular view? Thanks in advance.
Custom Directive Form
angular.module("form", [])
.directive("form",['$http','$rootScope','$location', function($http,$rootScope,$location){
return{
link: function(scope,element,attrs){
//functions go heere
//destroy scope and remove from DOM on route change
$rootScope.$on( "$routeChangeSuccess", function(event, next, current) {
if($location.path()!=='/form'){
scope.$destroy();
console.log('This should not be displayed on route change');
}
});
//function and scopes go here
},//return
restrict:"A",
replace:true,
templateUrl:"partials/form/form.html",//template
transclude:true, //incorporate additional data within
scope:{}
}//return
}])
ng-view/routeProvider
app.config(['$routeProvider',function($routeProvider) {
//configure the routes
$routeProvider
.when('/',{
// route for the home page
templateUrl:'partials/login/login.html',
controller:'loginCtrl'
})
.when('/home',{
// route for the home page
templateUrl:'partials/home/home.html',
template:'<div home></div>'
})
.when('/company',{
// route for the sites& companies
template:'<div company></div>'
})
.when('/form',{
// route for form
template:'<div form></div>'
})
.otherwise({
//when all else fails
templateUrl:'partials/login/login.html',
controller:'loginCtrl'
});
}]);
Please see this reference:
How to manually take an Angular directive out of the DOM
As per the source reference :
Steps:
1. Delete the directive's scope
2. Delete the directive's DOM
childScope.$destroy(); //IF THE DIRECTIVE WAS CREATED DYNAMICALLY OR ELSE WE MAY USE angular.element(DIRECTIVES-DOM).scope().$destroy()
$('.my-directive-placeholder').empty(); //DELETE DIRECTIVE'S DOM

Angular MyCtrl as instead of scope not working for me

I've got a form with hundred of fields.
As part of a secondary controller I'm trying to avoid the $scope to bind the data to my view. The way I go is:
angular
.module('app')
.controller('SequencesController', SequencesController) // main controller for the view
.controller('AccordionCtrl', AccordionCtrl); // the one I'm targetting
AccordionCtrl.$inject = ['$scope','$http'];
function AccordionCtrl($scope,$http) {
this.foo = "bar";
}
I'm using this on my view but it's not working.
<div ng-controller="AccordionCtrl as acc">
Acc : {{ acc.foo }}
</div>
Using $scope does work though. Any ideas?
Extra information:
The view is binded to a main controller that's called like that in app.js
.when('/sequences', {
controller: 'SequencesController',
templateUrl: 'app/Sequences/sequences.view.html',
controllerAs: 'vm'
})
When you are trying to access to the object(controller) property: {{ acc.foo }}, which angular is doing behind is: $scope.acc.foo, because this is how angular works, you must define your variables inside the scope.
If you dont want to interfer in the showing variables, create two diferent objects inside the scope: $scope.viewVars and $scope.backVars and add them all properties you need separately.

How to call parent method from model controller

I have one controller named "contractController"
contractController contains a method save()
contractController opens one model window with controller named "PopUpcontroller"
from PopUpcontroller i want to call save method on contractController
tried to call save method like $parent but nothing works.
Please advice.
If you are using Angular UI Bootstrap (http://angular-ui.github.io/bootstrap/), then, make use of the "resolve" attribute when you call $modal.open().
Whatever you add to resolve, will be available if you hook it up as a dependency injection.
In the example on their page, the "item" is available as below because it is hooked up in "resolve".
Resolve:
var modalInstance = $modal.open({
templateUrl: 'myModalContent.html',
controller: 'ModalInstanceCtrl',
size: size,
resolve: {
items: function () {
return $scope.items;
}
}
});
Use:
angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance, items) {
If the two controllers are nested so that:
<div ng-controller="contractController">
<div ng-controller="PopUpcontroller">
</div>
</Div>
you can just call $scope.save() on the popUpController and it automatically goes up to find a parent with that method (till the $rootScope).
if they are not nested you should use the services in order to perform the communication among controllers
You need to make sure the popup is created from contractController's scope if you want to retain its prototype. How are you creating the popup?
Something like this in Angular UI Boostrap (I don't use it but the API should accept it):
$modal.open({
scope: $scope,
/* ... other opts */
});

angular accessing modal parent controller

I'm using ui-router with $modal and my set up is like this in my routing page:
.state('resourcesControl.resource.dataStuff', {
url: "/:resourceId/dataStuff",
onEnter: ['$stateParams', '$state', '$modal', '$timeout', 'resourceService', function($stateParams, $state, $modal, $timeout, resourceService){
var modalInst = $modal.open({
templateUrl: "templates/dataStuff.html",
windowClass: 'data-modal',
controller: 'dataStuffCtrl'
});
modalInst.result.then(function(){
}, function(){
$state.go('resourcesControl.resource');
});
}]
})
My understanding with UI router is that all the child states have access to their parents controller and scope variables. In theory my dataStuffCtrl should have access to resource and resourcesControl controllers and their scopes.
However, when I wrap curly brackets around a parent scope item in the dataStuff view, nothing renders. Is there a way around this? I remember seeing other people posting about parent controllers with $modal but I can't find them on SO atm.
The issue is that the $modal service adds the element to the end of the document. So it doesn't sit in you scope hierarchy and instead is only a child of the $rootScope. You have a couple of options.
Pass the data to the modals controller via the $rootScope or broadcast/emit events (messy)
Manually pass the modal the scope you want to use as part of the modal.open options object via the scope property. (You can call $scope.$new() to manually create a child scope).
Use the resolve property of the modal.open options object to pass the data to be injected into the modals controller just like angular route resolves

Resources