AngularJS - decouple directive from parent controllerAs syntax - angularjs

I have a child directive inside a parent directive. I want the child directive to be completely generic and not have to rely on the naming of the parent directive's controllerAs syntax. To explain myself better here is what i Have
Parent Directive
templateUrl: '/apps/common/myParentDirective.html',
controller: 'myParentDirectiveController',
controllerAs: 'vm'
Child Directive (this has to inherit parent scope and watch a property named 'dynamicFields' on the scope of the parent directive. Right now i have the code below
$scope.$watch('vm.dynamicFields', function (newVal) {
if (!newVal) {
return;
}
// do something with dynamicfield
});
I want this directive to be re-usable and don't want to be tied into using vm.dynamicFields. Can i simply use 'dynamicFields' as it is guaranteed that the name of the field on the scope will always be the same but it not guaraneteed that the parent directive would be using 'vm' or 'somethingelse'

Related

How can I share a scope with a directive in another module without using "scope: false"?

I have 2 modules, jsTag and mainApp. mainApp injects jsTag to use it's functionality
var jsTag = angular.module('jsTag')
angular.module('mainApp', ['jsTag']);
The jsTag module has a directive I'll call jsTagDirective
jsTag.directive('jsTagDirective', function(){
restrict: 'E',
scope: true,
controller: 'jsTagMainCtrl',
templateUrl: 'jsTag/source/Templates/js-tag.html'
The template of the above directive has an input tag inside of it, with an ng-model reference to jsText. I want to be able to capture the value of this model in the controller of my mainApp module. Changing scope to false does work - I can access $scope.jsText in the mainApp - but I understand this is bad practice. I can't figure out how to get inherited scope or isolated scope to pass the value upwards, though.
That's a perfect example why you should use isolated scope along with two-way binding. Docs here.
JS
jsTag.directive('jsTagDirective', function () {
return {
restrict: 'E',
scope: {
jsText: '='
},
controller: 'jsTagMainCtrl',
templateUrl: 'jsTag/source/Templates/js-tag.html'
};
});
HTML
<js-tag-directive js-text="jsText"></js-tag-directive>
This will make the directive have its jsText property in sync with a parent scope, even creating the said property.

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

Multiple Named Views + Destroy $scope

If I am using a state with multiple views, how do I destroy one of the view's scopes? I tried the following and it did not work:
<div ng-if='showFilters' ui-view="filters"></div>
<div ui-view="tabledata"></div>
<div ui-view="graph"></div>
Even when $scope.showFilters set to false, the scope for the 'filters' view still exists. I wonder if the ng-if is only destroying its child scope, but doesn't know about the ui-view's scope. I appreciate the help.
I'd recommend using a hierarchy of views so you can easily destroy the scope of any 'child' view:
.state('parent', {
controller: "parentController as parent",
templateUrl: '../parent.html'
})
.state('child1', {
controller: "child1Controller",
templateUrl: '../child1.html'
})
.state('child2', {
controller: "child2Controller",
templateUrl: '../child2.html'
})
Note that you don't have to use 'parent.child2' (nested states) unless you want to. The key is that the child scopes will inherit the parent scope as long as they are within the html frame of the parent, such as:
<div ui-view="parent">
<div ui-view="child1"></div>
<div ui-view="child2"></div>
</div>
Then from the children, you can simply reference something like {{parent.filters.filter1}} and if you need to destroy the scope, you can do so from the parent controller using this.filters = undefined.

Angular, Why does the child controller have same scope as parent?

I have created a test located on plunker at this address: Full example on plunker
Here is the child controller which works:
child.directive('child', function(){
return{
restrict:'E',
templateUrl: 'child.html',
link: function(){},
controller:['$scope', function($scope){
this.inherited = $scope.test;
this.local = "child";
}],
controllerAs:'child'
};
});
I am expecting the controller located in child.js to be a child controller of the controller in script.js. This would mean that if I want to access a variable added to the scope of parent controller from the child controller, I would need to access it using $scope.$parent. Can someone explain why these are the same scope?
By default, directives do not create a new scope. So in your example $scope in the directive will be the same value as the scope that the controller is contained in. The scope is not inherited - they are the same scope.
So for this markup:
<div ng-controller="SomeController">
<child></child>
</div>
scope in SomeController will be the exact same object as scope in your directive. If you did $scope.$parent in the directive, you would actually be accessing the parent scope of SomeController. This is equivalent to
scope: false //default for directives
If you add:
scope: true
to your directive definition, then the directive will create a new scope that prototypically inherits from the parent scope. In this situation,
<div ng-controller="SomeController">
<child></child>
</div>
Now $scope.$parent in the directive will be the $scope of SomeController. Also, since it prototypically inherits, the directive will have access to methods and properties defined on $scope.$parent, with the caveats and complications that come with prototypically inheritance in javascript.
If you use:
scope: {}
Now $scope.$parent in the directive will still be the $scope of SomeController, but the new scope will not prototypically inherit from the parent, so you will not have access to methods and properties defined on $scope.$parent.
The child scope inherits from the parent scope, so anything you define in the parent will appear in the child scope. Keep in mind that this is a new scope, so modifications won't affect the parent directly without using the $scope.$parent scope. Take a look at this question and the accepted answer: AngularJS access parent scope from child controller
In directives the parent scope is inherited by default:
https://github.com/angular/angular.js/wiki/Understanding-Scopes

angular ui modal can NOT refer to parent scope

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

Resources